| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801 |
- <?php
- trait EmbyLiveTVTrackerHomepageItem
- {
- public function embyLiveTVTrackerSettingsArray($infoOnly = false)
- {
- $homepageInformation = [
- 'name' => 'EmbyLiveTVTracker',
- 'enabled' => strpos('personal', $this->config['license']) !== false,
- 'image' => 'plugins/images/homepage/embyLiveTVTracker.png',
- 'category' => 'Media Server',
- 'settingsArray' => __FUNCTION__
- ];
- if ($infoOnly) {
- return $homepageInformation;
- }
- $homepageSettings = [
- 'debug' => true,
- 'settings' => [
- 'Enable' => [
- $this->settingsOption('enable', 'homepageEmbyLiveTVTrackerEnabled'),
- $this->settingsOption('auth', 'homepageEmbyLiveTVTrackerAuth'),
- ],
- 'Connection' => [
- $this->settingsOption('url', 'embyURL'),
- $this->settingsOption('token', 'embyToken'),
- $this->settingsOption('disable-cert-check', 'embyDisableCertCheck'),
- $this->settingsOption('use-custom-certificate', 'embyUseCustomCertificate'),
- ],
- 'Display Options' => [
- $this->settingsOption('number', 'homepageEmbyLiveTVTrackerRefresh', ['label' => 'Auto-refresh Interval (minutes)', 'min' => 1, 'max' => 60]),
- $this->settingsOption('switch', 'homepageEmbyLiveTVTrackerCompactView', ['label' => 'Use Compact View']),
- $this->settingsOption('switch', 'homepageEmbyLiveTVTrackerShowDuration', ['label' => 'Show Recording Duration']),
- $this->settingsOption('switch', 'homepageEmbyLiveTVTrackerShowSeriesInfo', ['label' => 'Show Series Information']),
- $this->settingsOption('switch', 'homepageEmbyLiveTVTrackerShowUserInfo', ['label' => 'Show User Information']),
- $this->settingsOption('number', 'homepageEmbyLiveTVTrackerMaxItems', ['label' => 'Maximum Scheduled Items', 'min' => 5, 'max' => 50]),
- $this->settingsOption('switch', 'homepageEmbyLiveTVTrackerShowCompleted', ['label' => 'Show Completed Recordings']),
- $this->settingsOption('number', 'homepageEmbyLiveTVTrackerDaysShown', ['label' => 'Days of Completed Recordings', 'min' => 1, 'max' => 30]),
- $this->settingsOption('number', 'homepageEmbyLiveTVTrackerMaxCompletedItems', ['label' => 'Maximum Completed Items', 'min' => 5, 'max' => 50]),
- $this->settingsOption('switch', 'homepageEmbyLiveTVTrackerDebug', ['label' => 'Enable Debug Logging']),
- ],
- 'Test Connection' => [
- $this->settingsOption('blank', null, ['label' => 'Please Save before Testing']),
- $this->settingsOption('test', 'embyLiveTVTracker'),
- ]
- ]
- ];
- return array_merge($homepageInformation, $homepageSettings);
- }
- public function testConnectionEmbyLiveTVTracker()
- {
- if (!$this->homepageItemPermissions($this->embyLiveTVTrackerHomepagePermissions('test'), true)) {
- return false;
- }
- $url = $this->qualifyURL($this->config['embyURL']);
- $url = $url . "/emby/System/Info?api_key=" . $this->config['embyToken'];
- $options = $this->requestOptions($url, null, $this->config['embyDisableCertCheck'], $this->config['embyUseCustomCertificate']);
- try {
- $response = Requests::get($url, [], $options);
- if ($response->success) {
- $info = json_decode($response->body, true);
- if (isset($info['ServerName'])) {
- // Test LiveTV functionality
- $liveTvUrl = $this->qualifyURL($this->config['embyURL']) . '/emby/LiveTv/Info?api_key=' . $this->config['embyToken'];
- try {
- $liveTvResponse = Requests::get($liveTvUrl, [], $options);
- $liveTvInfo = json_decode($liveTvResponse->body, true);
- $hasLiveTV = isset($liveTvInfo['Services']) && count($liveTvInfo['Services']) > 0;
- $message = 'Successfully connected to ' . $info['ServerName'];
- if ($hasLiveTV) {
- $message .= ' with LiveTV support enabled';
- } else {
- $message .= ' (Warning: LiveTV may not be configured)';
- }
- $this->setAPIResponse('success', $message, 200);
- } catch (Exception $e) {
- $this->setAPIResponse('success', 'Connected to ' . $info['ServerName'] . ' but LiveTV status unknown', 200);
- }
- } else {
- $this->setAPIResponse('error', 'Invalid response from Emby server', 500);
- }
- return true;
- } else {
- $this->setAPIResponse('error', 'Emby Connection Error', 500);
- return false;
- }
- } catch (Requests_Exception $e) {
- $this->setResponse(500, $e->getMessage());
- return false;
- }
- }
- public function embyLiveTVTrackerHomepagePermissions($key = null)
- {
- $permissions = [
- 'test' => [
- 'enabled' => [
- 'homepageEmbyLiveTVTrackerEnabled',
- ],
- 'auth' => [
- 'homepageEmbyLiveTVTrackerAuth',
- ],
- 'not_empty' => [
- 'embyURL',
- 'embyToken'
- ]
- ],
- 'main' => [
- 'enabled' => [
- 'homepageEmbyLiveTVTrackerEnabled'
- ],
- 'auth' => [
- 'homepageEmbyLiveTVTrackerAuth'
- ],
- 'not_empty' => [
- 'embyURL',
- 'embyToken'
- ]
- ]
- ];
- return $this->homepageCheckKeyPermissions($key, $permissions);
- }
- public function homepageOrderEmbyLiveTVTracker()
- {
- if ($this->homepageItemPermissions($this->embyLiveTVTrackerHomepagePermissions('main'))) {
- $refreshInterval = ($this->config['homepageEmbyLiveTVTrackerRefresh'] ?? 5) * 60000; // Convert minutes to milliseconds
- $compactView = ($this->config['homepageEmbyLiveTVTrackerCompactView'] ?? false) ? 'true' : 'false';
- $showDuration = ($this->config['homepageEmbyLiveTVTrackerShowDuration'] ?? true) ? 'true' : 'false';
- $showSeriesInfo = ($this->config['homepageEmbyLiveTVTrackerShowSeriesInfo'] ?? true) ? 'true' : 'false';
- $showUserInfo = ($this->config['homepageEmbyLiveTVTrackerShowUserInfo'] ?? false) ? 'true' : 'false';
- $maxItems = $this->config['homepageEmbyLiveTVTrackerMaxItems'] ?? 10;
- $showCompleted = ($this->config['homepageEmbyLiveTVTrackerShowCompleted'] ?? true) ? 'true' : 'false';
- $daysShown = $this->config['homepageEmbyLiveTVTrackerDaysShown'] ?? 7;
- $maxCompletedItems = $this->config['homepageEmbyLiveTVTrackerMaxCompletedItems'] ?? 5;
- $panelClass = ($compactView === 'true') ? 'panel-compact' : '';
- $statsClass = ($compactView === 'true') ? 'col-sm-6' : 'col-sm-3';
- return '
- <div id="' . __FUNCTION__ . '">
- <div class="white-box ' . $panelClass . '">
- <div class="white-box-header">
- <i class="fa fa-tv"></i> Emby LiveTV Tracker
- <span class="pull-right">
- <small id="embylivetv-last-update" class="text-muted"></small>
- <button class="btn btn-xs btn-primary" onclick="refreshEmbyLiveTVData()" title="Refresh Data">
- <i class="fa fa-refresh" id="embylivetv-refresh-icon"></i>
- </button>
- </span>
- </div>
- <div class="white-box-content">
- <div class="row" id="embylivetv-stats">
- <div class="' . $statsClass . '">
- <div class="text-center">
- <h3 id="embylivetv-active-timers" class="text-success">-</h3>
- <small>Active Timers</small>
- </div>
- </div>
- <div class="' . $statsClass . '">
- <div class="text-center">
- <h3 id="embylivetv-series-timers" class="text-info">-</h3>
- <small>Series Timers</small>
- </div>
- </div>
- ' . (($compactView === 'false') ? '
- <div class="' . $statsClass . '">
- <div class="text-center">
- <h3 id="embylivetv-today-recordings" class="text-warning">-</h3>
- <small>Today\'s Recordings</small>
- </div>
- </div>
- <div class="' . $statsClass . '">
- <div class="text-center">
- <h3 id="embylivetv-total-recordings" class="text-primary">-</h3>
- <small>Total Recordings</small>
- </div>
- </div>
- ' : '') . '
- </div>
- <!-- Scheduled Recordings Table -->
- <div class="row" style="margin-top: 20px;">
- <div class="col-lg-12">
- <h4>
- Scheduled Recordings
- <small class="text-muted">Upcoming and active timers</small>
- </h4>
- <div class="table-responsive">
- <table class="table table-hover table-striped table-condensed">
- <thead>
- <tr>
- <th width="120">Date</th>
- <th>Series</th>
- ' . (($showSeriesInfo === 'true') ? '<th>Episode Title</th>' : '') . '
- <th>Channel</th>
- ' . (($showUserInfo === 'true') ? '<th>User</th>' : '') . '
- ' . (($showDuration === 'true') ? '<th width="80">Duration</th>' : '') . '
- <th width="70">Status</th>
- </tr>
- </thead>
- <tbody id="embylivetv-scheduled-table">
- <tr>
- <td colspan="' . (4 + ($showSeriesInfo === 'true' ? 1 : 0) + ($showUserInfo === 'true' ? 1 : 0) + ($showDuration === 'true' ? 1 : 0)) . '" class="text-center">
- <i class="fa fa-spinner fa-spin"></i> Loading...
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- </div>
- </div>
-
- <!-- Completed Recordings Table (only if enabled) -->
- ' . (($showCompleted === 'true') ? '
- <div class="row" style="margin-top: 20px;">
- <div class="col-lg-12">
- <h4>
- Completed Recordings
- <small class="text-muted">Recent recordings</small>
- </h4>
- <div class="table-responsive">
- <table class="table table-hover table-striped table-condensed">
- <thead>
- <tr>
- <th width="120">Date</th>
- <th>Series</th>
- ' . (($showSeriesInfo === 'true') ? '<th>Series</th>' : '') . '
- ' . (($showDuration === 'true') ? '<th width="80">Duration</th>' : '') . '
- <th width="70">Status</th>
- </tr>
- </thead>
- <tbody id="embylivetv-completed-table">
- <tr>
- <td colspan="' . (3 + ($showSeriesInfo === 'true' ? 1 : 0) + ($showDuration === 'true' ? 1 : 0)) . '" class="text-center">
- <i class="fa fa-spinner fa-spin"></i> Loading...
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- </div>
- </div>
- ' : '') . '
- </div>
- </div>
- </div>
- <style>
- .panel-compact .white-box-content { padding: 10px; }
- .panel-compact h3 { margin: 5px 0; font-size: 1.8em; }
- .panel-compact small { font-size: 0.85em; }
- #' . __FUNCTION__ . ' .table-condensed td { padding: 4px 8px; font-size: 0.9em; }
- #' . __FUNCTION__ . ' .status-success { color: #5cb85c; }
- #' . __FUNCTION__ . ' .status-recording { color: #d9534f; }
- #' . __FUNCTION__ . ' .status-scheduled { color: #f0ad4e; }
- </style>
- <script>
- var embyLiveTVRefreshTimer;
- var embyLiveTVLastRefresh = 0;
- function refreshEmbyLiveTVData() {
- var refreshIcon = $("#embylivetv-refresh-icon");
- refreshIcon.addClass("fa-spin");
- // Show loading state
- $("#embylivetv-stats h3").text("-");
- $("#embylivetv-scheduled-table").html("<tr><td colspan=\"' . (4 + ($showSeriesInfo === 'true' ? 1 : 0) + ($showUserInfo === 'true' ? 1 : 0) + ($showDuration === 'true' ? 1 : 0)) . '\" class=\"text-center\"><i class=\"fa fa-spinner fa-spin\"></i> Loading...</td></tr>");
- ' . (($showCompleted === 'true') ? '$("#embylivetv-completed-table").html("<tr><td colspan=\"' . (4 + ($showSeriesInfo === 'true' ? 1 : 0) + ($showUserInfo === 'true' ? 1 : 0) + ($showDuration === 'true' ? 1 : 0)) . '\" class=\"text-center\"><i class=\"fa fa-spinner fa-spin\"></i> Loading...</td></tr>");' : '') . ';
- // Load stats and activity
- homepageEmbyLiveTVTrackerStats()
- .always(function() {
- refreshIcon.removeClass("fa-spin");
- embyLiveTVLastRefresh = Date.now();
- updateEmbyLiveTVLastRefreshTime();
- });
- }
- function updateEmbyLiveTVLastRefreshTime() {
- if (embyLiveTVLastRefresh > 0) {
- var ago = Math.floor((Date.now() - embyLiveTVLastRefresh) / 1000);
- var timeText = ago < 60 ? ago + "s ago" : Math.floor(ago / 60) + "m ago";
- $("#embylivetv-last-update").text("Updated " + timeText);
- }
- }
- function homepageEmbyLiveTVTrackerStats() {
- return organizrAPI2("GET", "api/v2/homepage/embyLiveTVTracker/stats")
- .done(function(data) {
- console.log("Stats response received:", data);
- if (data && data.response && data.response.result === "success" && data.response.data) {
- console.log("Stats data is valid, loading activity...");
- $("#embylivetv-active-timers").text(data.response.data.activeTimers || "0");
- $("#embylivetv-series-timers").text(data.response.data.seriesTimers || "0");
- ' . (($compactView === 'false') ? '
- $("#embylivetv-today-recordings").text(data.response.data.todaysRecordings || "0");
- $("#embylivetv-total-recordings").text(data.response.data.totalRecordings || "0");
- ' : '') . '
-
- // Load activity
- homepageEmbyLiveTVTrackerActivity();
- } else {
- console.error("Stats response structure issue:", {
- hasData: !!data,
- hasResponse: !!(data && data.response),
- result: data && data.response && data.response.result,
- hasResponseData: !!(data && data.response && data.response.data)
- });
- console.error("Failed to load Emby LiveTV stats:", data.response ? data.response.message : "Unknown error");
- $("#embylivetv-stats h3").text("?").attr("title", "Error loading data");
- }
- })
- .fail(function(xhr, status, error) {
- console.error("Error loading Emby LiveTV stats:", error);
- $("#embylivetv-stats h3").text("!").attr("title", "Connection failed");
- });
- }
- function homepageEmbyLiveTVTrackerActivity() {
- console.log("Activity function called - making API request...");
- return organizrAPI2("GET", "api/v2/homepage/embyLiveTVTracker/activity?days=' . ($daysShown ?: 7) . '\u0026limit=' . ($maxItems ?: 10) . '")
- .done(function(data) {
- console.log("Activity response received:", data);
- console.log("Response structure check:", {
- hasData: !!data,
- hasResponse: !!(data && data.response),
- result: data && data.response && data.response.result,
- hasResponseData: !!(data && data.response && data.response.data),
- hasActivities: !!(data && data.response && data.response.data && data.response.data.activities),
- activitiesLength: data && data.response && data.response.data && data.response.data.activities ? data.response.data.activities.length : 0
- });
- if (data && data.response && data.response.result === "success" && data.response.data) {
- var scheduledRecordings = data.response.data.scheduledRecordings || [];
- var completedRecordings = data.response.data.completedRecordings || [];
-
- console.log("Scheduled recordings:", scheduledRecordings.length);
- console.log("Completed recordings:", completedRecordings.length);
-
- // Apply limits to each category separately to ensure we show both types
- var maxScheduled = Math.floor(' . $maxItems . ' * 0.7); // 70% for scheduled
- var maxCompleted = ' . $maxItems . ' - maxScheduled; // 30% for completed
-
- // If we have fewer scheduled than the 70% allocation, give more space to completed
- if (scheduledRecordings.length < maxScheduled) {
- maxCompleted = Math.min(completedRecordings.length, ' . $maxItems . ' - scheduledRecordings.length);
- }
- // If we have fewer completed than the 30% allocation, give more space to scheduled
- if (completedRecordings.length < maxCompleted) {
- maxScheduled = Math.min(scheduledRecordings.length, ' . $maxItems . ' - completedRecordings.length);
- }
-
- var scheduledActivities = scheduledRecordings.slice(0, maxScheduled);
- var completedActivities = completedRecordings.slice(0, maxCompleted);
-
- console.log("Split - Scheduled activities:", scheduledActivities.length);
- console.log("Split - Completed activities:", completedActivities.length);
- // Helper function to format scheduled activity rows
- function formatScheduledRow(activity) {
- var date = new Date(activity.date);
- var formattedDate = date.toLocaleDateString() + " " + date.toLocaleTimeString([], {hour: "2-digit", minute:"2-digit"});
- var status = activity.status || "Scheduled";
- var statusClass = status.toLowerCase() === "completed" ? "status-success" :
- status.toLowerCase() === "recording" ? "status-recording" : "status-scheduled";
- return "<tr>" +
- "<td><small>" + formattedDate + "</small></td>" +
- "<td>" + (activity.seriesName || activity.name || "-") + "</td>" +
- ' . (($showSeriesInfo === 'true') ? '"<td><small>" + (activity.episodeTitle || activity.name || "-") + "</small></td>" +' : '') . '
- "<td><small>" + (activity.channelName || "-") + "</small></td>" +
- ' . (($showUserInfo === 'true') ? '"<td><small>" + (activity.userName || "-") + "</small></td>" +' : '') . '
- ' . (($showDuration === 'true') ? '"<td><small>" + (activity.duration || "-") + "</small></td>" +' : '') . '
- "<td><span class=\"" + statusClass + "\"><i class=\"fa fa-circle\"></i></span></td>" +
- "</tr>";
- }
-
- // Helper function to format completed activity rows (no channel or user columns)
- function formatCompletedRow(activity) {
- var date = new Date(activity.date);
- var formattedDate = date.toLocaleDateString() + " " + date.toLocaleTimeString([], {hour: "2-digit", minute:"2-digit"});
- var status = activity.status || "Completed";
- var statusClass = "status-success";
- return "<tr>" +
- "<td><small>" + formattedDate + "</small></td>" +
- "<td>" + (activity.seriesName || activity.name || "-") + "</td>" +
- ' . (($showSeriesInfo === 'true') ? '"<td><small>" + (activity.seriesName || "-") + "</small></td>" +' : '') . '
- ' . (($showDuration === 'true') ? '"<td><small>" + (activity.duration || "-") + "</small></td>" +' : '') . '
- "<td><span class=\"" + statusClass + "\"><i class=\"fa fa-circle\"></i></span></td>" +
- "</tr>";
- }
-
- // Populate scheduled recordings table
- var scheduledTable = $("#embylivetv-scheduled-table");
- if (scheduledActivities.length === 0) {
- scheduledTable.html("<tr><td colspan=\"' . (4 + ($showSeriesInfo === 'true' ? 1 : 0) + ($showDuration === 'true' ? 1 : 0) + ($showUserInfo === 'true' ? 1 : 0)) . '\" class=\"text-center text-muted\">No scheduled recordings</td></tr>");
- } else {
- var scheduledRows = scheduledActivities.map(formatScheduledRow).join("");
- scheduledTable.html(scheduledRows);
- }
-
- // Populate completed recordings table (only if enabled and table exists)
- ' . (($showCompleted === 'true') ? '
- var completedTable = $("#embylivetv-completed-table");
- if (completedActivities.length === 0) {
- completedTable.html("<tr><td colspan=\"' . (3 + ($showSeriesInfo === 'true' ? 1 : 0) + ($showDuration === 'true' ? 1 : 0)) . '\" class=\"text-center text-muted\">No completed recordings</td></tr>");
- } else {
- var completedRows = completedActivities.map(formatCompletedRow).join("");
- completedTable.html(completedRows);
- }
- ' : '') . '
- } else {
- $("#embylivetv-scheduled-table").html("<tr><td colspan=\"' . (4 + ($showSeriesInfo === 'true' ? 1 : 0) + ($showDuration === 'true' ? 1 : 0) + ($showUserInfo === 'true' ? 1 : 0)) . '\" class=\"text-center text-muted\">No activity data available</td></tr>");
- ' . (($showCompleted === 'true') ? '$("#embylivetv-completed-table").html("<tr><td colspan=\"' . (3 + ($showSeriesInfo === 'true' ? 1 : 0) + ($showDuration === 'true' ? 1 : 0)) . '\" class=\"text-center text-muted\">No activity data available</td></tr>");' : '') . '
- }
- })
- .fail(function(xhr, status, error) {
- console.error("Error loading Emby LiveTV activity:", error);
- $("#embylivetv-scheduled-table").html("<tr><td colspan=\"' . (4 + ($showSeriesInfo === 'true' ? 1 : 0) + ($showUserInfo === 'true' ? 1 : 0) + ($showDuration === 'true' ? 1 : 0)) . '\" class=\"text-center text-danger\">Error loading activity data</td></tr>");
- ' . (($showCompleted === 'true') ? '$("#embylivetv-completed-table").html("<tr><td colspan=\"' . (3 + ($showSeriesInfo === 'true' ? 1 : 0) + ($showDuration === 'true' ? 1 : 0)) . '\" class=\"text-center text-danger\">Error loading activity data</td></tr>");' : '') . '
- });
- }
- // Auto-refresh setup
- var refreshInterval = ' . $refreshInterval . ';
- if (refreshInterval > 0) {
- embyLiveTVRefreshTimer = setInterval(function() {
- refreshEmbyLiveTVData();
- }, refreshInterval);
- }
- // Update time display every 30 seconds
- setInterval(updateEmbyLiveTVLastRefreshTime, 30000);
- // Initial load
- $(document).ready(function() {
- refreshEmbyLiveTVData();
- });
- // Cleanup timer when page unloads
- $(window).on("beforeunload", function() {
- if (embyLiveTVRefreshTimer) {
- clearInterval(embyLiveTVRefreshTimer);
- }
- });
- </script>
- ';
- }
- }
- public function getHomepageEmbyLiveTVStats()
- {
- if (!$this->homepageItemPermissions($this->embyLiveTVTrackerHomepagePermissions('main'), true)) {
- return false;
- }
-
- if (!$this->config['embyURL'] || !$this->config['embyToken']) {
- $this->setAPIResponse('error', 'Emby URL or Token not configured', 500);
- return false;
- }
-
- try {
- $options = $this->requestOptions($this->config['embyURL'], null, $this->config['embyDisableCertCheck'], $this->config['embyUseCustomCertificate']);
- $baseUrl = $this->qualifyURL($this->config['embyURL']);
-
- $stats = [
- 'activeTimers' => 0,
- 'seriesTimers' => 0,
- 'todaysRecordings' => 0,
- 'totalRecordings' => 0,
- 'recentRecordings' => []
- ];
-
- // Get active timers
- $timersUrl = $baseUrl . '/emby/LiveTv/Timers?api_key=' . $this->config['embyToken'];
- try {
- $timersResponse = Requests::get($timersUrl, [], $options);
- if ($timersResponse->success) {
- $timers = json_decode($timersResponse->body, true);
- $stats['activeTimers'] = count($timers['Items'] ?? []);
- }
- } catch (Exception $e) {
- $this->setLoggerChannel('EmbyLiveTVTracker')->warning('Failed to get timers: ' . $e->getMessage());
- }
-
- // Get series timers
- $seriesTimersUrl = $baseUrl . '/emby/LiveTv/SeriesTimers?api_key=' . $this->config['embyToken'];
- try {
- $seriesTimersResponse = Requests::get($seriesTimersUrl, [], $options);
- if ($seriesTimersResponse->success) {
- $seriesTimers = json_decode($seriesTimersResponse->body, true);
- $stats['seriesTimers'] = count($seriesTimers['Items'] ?? []);
- }
- } catch (Exception $e) {
- $this->setLoggerChannel('EmbyLiveTVTracker')->warning('Failed to get series timers: ' . $e->getMessage());
- }
-
- // Get recordings from the last 90 days
- $recordingsUrl = $baseUrl . '/emby/LiveTv/Recordings?api_key=' . $this->config['embyToken'] . '&StartIndex=0&Limit=50&Fields=Overview,DateCreated&SortBy=DateCreated&SortOrder=Descending';
- try {
- $recordingsResponse = Requests::get($recordingsUrl, [], $options);
- if ($recordingsResponse->success) {
- $recordings = json_decode($recordingsResponse->body, true);
- $allRecordings = $recordings['Items'] ?? [];
-
- // Count today's recordings
- $today = date('Y-m-d');
- $todaysCount = 0;
- $recentRecordings = [];
-
- foreach ($allRecordings as $recording) {
- if (isset($recording['DateCreated'])) {
- $recordDate = date('Y-m-d', strtotime($recording['DateCreated']));
- if ($recordDate === $today) {
- $todaysCount++;
- }
-
- // Add to recent recordings list
- $recentRecordings[] = [
- 'date' => $recordDate,
- 'program' => $recording['Name'] ?? 'Unknown',
- 'series' => $recording['SeriesName'] ?? '',
- 'channel' => $recording['ChannelName'] ?? 'Unknown Channel',
- 'status' => 'Completed'
- ];
- }
- }
-
- $stats['todaysRecordings'] = $todaysCount;
- $stats['totalRecordings'] = $recordings['TotalRecordCount'] ?? count($allRecordings);
- $stats['recentRecordings'] = array_slice($recentRecordings, 0, 10); // Limit to 10 recent recordings
- }
- } catch (Exception $e) {
- $this->setLoggerChannel('EmbyLiveTVTracker')->warning('Failed to get recordings: ' . $e->getMessage());
- }
-
- $this->setAPIResponse('success', 'LiveTV stats retrieved successfully', 200, $stats);
- return true;
-
- } catch (Exception $e) {
- $this->setAPIResponse('error', 'Failed to retrieve LiveTV stats: ' . $e->getMessage(), 500);
- return false;
- }
- }
- public function getHomepageEmbyLiveTVActivity()
- {
- $debugEnabled = $this->config['homepageEmbyLiveTVTrackerDebug'] ?? false;
-
- if (!$this->homepageItemPermissions($this->embyLiveTVTrackerHomepagePermissions('main'), true)) {
- if ($debugEnabled) {
- $this->setLoggerChannel('EmbyLiveTVTracker')->warning('Permission denied for user');
- }
- $this->setAPIResponse('error', 'Permission denied', 403);
- return false;
- }
-
- if (!$this->config['embyURL'] || !$this->config['embyToken']) {
- $this->setAPIResponse('error', 'Emby URL or Token not configured', 500);
- return false;
- }
-
- try {
- if ($debugEnabled) {
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('Activity method called - starting execution');
- }
- $options = $this->requestOptions($this->config['embyURL'], null, $this->config['embyDisableCertCheck'], $this->config['embyUseCustomCertificate']);
- $baseUrl = $this->qualifyURL($this->config['embyURL']);
- if ($debugEnabled) {
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('Base URL configured: ' . $baseUrl);
- }
-
- $scheduledRecordings = [];
- $completedRecordings = [];
- $maxItems = intval($this->config['homepageEmbyLiveTVTrackerMaxItems'] ?? 10);
- $showCompleted = $this->config['homepageEmbyLiveTVTrackerShowCompleted'] ?? true;
- $maxCompletedItems = intval($this->config['homepageEmbyLiveTVTrackerMaxCompletedItems'] ?? 5);
-
- // Get user info if user info is enabled
- $userMap = [];
- $showUserInfo = $this->config['homepageEmbyLiveTVTrackerShowUserInfo'] ?? false;
- if ($showUserInfo) {
- $usersUrl = $baseUrl . '/emby/Users?api_key=' . $this->config['embyToken'];
- try {
- $usersResponse = Requests::get($usersUrl, [], $options);
- if ($usersResponse->success) {
- $users = json_decode($usersResponse->body, true);
- foreach ($users as $user) {
- $userMap[$user['Id']] = $user['Name'];
- }
- if ($debugEnabled) {
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('Retrieved ' . count($userMap) . ' users for mapping');
- }
- }
- } catch (Exception $e) {
- $this->setLoggerChannel('EmbyLiveTVTracker')->warning('Failed to get users: ' . $e->getMessage());
- }
- }
-
- // Get scheduled recordings (active timers)
- $timersUrl = $baseUrl . '/emby/LiveTv/Timers?api_key=' . $this->config['embyToken'] . '&Fields=ChannelName,ChannelId,SeriesName,ProgramInfo,StartDate,EndDate,UserId';
- if ($debugEnabled) {
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('Fetching timers from URL: ' . $timersUrl);
- }
- try {
- $timersResponse = Requests::get($timersUrl, [], $options);
- if ($debugEnabled) {
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('Timers API response status: ' . ($timersResponse->success ? 'success' : 'failed'));
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('Timers API response code: ' . $timersResponse->status_code);
- }
- if ($timersResponse->success) {
- $timers = json_decode($timersResponse->body, true);
- $allTimers = $timers['Items'] ?? [];
- if ($debugEnabled) {
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('Retrieved ' . count($allTimers) . ' timers from Emby API');
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('Timers API raw response length: ' . strlen($timersResponse->body));
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('First timer sample: ' . json_encode(array_slice($allTimers, 0, 1)));
- }
-
- // Sort timers by start date
- usort($allTimers, function($a, $b) {
- $aDate = $a['StartDate'] ?? '';
- $bDate = $b['StartDate'] ?? '';
- return strcmp($aDate, $bDate);
- });
- $timersToProcess = array_slice($allTimers, 0, intval($maxItems));
- if ($debugEnabled) {
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('Processing ' . count($timersToProcess) . ' timers (maxItems: ' . $maxItems . ')');
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('All timers count before slice: ' . count($allTimers));
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('MaxItems value: ' . $maxItems . ' (type: ' . gettype($maxItems) . ')');
- }
-
- foreach ($timersToProcess as $index => $timer) {
- if ($debugEnabled) {
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('Processing timer ' . ($index + 1) . ': ' . json_encode([
- 'Name' => $timer['Name'] ?? 'no name',
- 'StartDate' => $timer['StartDate'] ?? 'no start date',
- 'EndDate' => $timer['EndDate'] ?? 'no end date',
- 'ChannelName' => $timer['ChannelName'] ?? 'no channel name',
- 'Status' => $timer['Status'] ?? 'no status',
- 'UserId' => $timer['UserId'] ?? 'no user'
- ]));
- }
-
- // Calculate duration
- $duration = '-';
- if (isset($timer['StartDate']) && isset($timer['EndDate'])) {
- $start = strtotime($timer['StartDate']);
- $end = strtotime($timer['EndDate']);
- if ($start && $end) {
- $minutes = round(($end - $start) / 60);
- $hours = floor($minutes / 60);
- $remainingMinutes = $minutes % 60;
- if ($hours > 0) {
- $duration = sprintf('%dh %dm', $hours, $remainingMinutes);
- } else {
- $duration = sprintf('%dm', $minutes);
- }
- }
- }
-
- // Get channel name - timers should have this information
- $channelName = $timer['ChannelName'] ?? null;
- if (empty($channelName) && !empty($timer['ChannelId'])) {
- $channelName = 'Channel ' . $timer['ChannelId'];
- } elseif (empty($channelName)) {
- $channelName = 'Unknown Channel';
- }
-
- // Get user name
- $userName = null;
- if ($showUserInfo && !empty($timer['UserId']) && isset($userMap[$timer['UserId']])) {
- $userName = $userMap[$timer['UserId']];
- }
-
- // Determine status based on timing
- $status = 'Scheduled';
- $startTime = strtotime($timer['StartDate'] ?? '');
- $endTime = strtotime($timer['EndDate'] ?? '');
- $now = time();
-
- if ($startTime && $endTime) {
- if ($now >= $startTime && $now <= $endTime) {
- $status = 'Recording';
- } elseif ($now > $endTime) {
- $status = 'Completed';
- }
- }
-
- // Get series name and episode title - try multiple approaches
- $seriesName = '';
- $episodeTitle = '';
-
- // Check for episode title first
- if (!empty($timer['ProgramInfo']['EpisodeTitle'])) {
- $episodeTitle = $timer['ProgramInfo']['EpisodeTitle'];
- }
-
- // Get series name
- if (!empty($timer['SeriesName'])) {
- $seriesName = $timer['SeriesName'];
- } elseif (!empty($timer['ProgramInfo']['SeriesName'])) {
- $seriesName = $timer['ProgramInfo']['SeriesName'];
- } elseif (!empty($timer['ProgramInfo']['Name'])) {
- $seriesName = $timer['ProgramInfo']['Name'];
- } elseif (!empty($timer['Name'])) {
- $seriesName = $timer['Name'];
- }
-
- // Use episode title if available, otherwise use program/series name
- $displayName = $episodeTitle ? $episodeTitle : ($timer['Name'] ?? ($timer['ProgramInfo']['Name'] ?? 'Unknown Program'));
-
- $activity = [
- 'date' => $timer['StartDate'] ?? '',
- 'name' => $displayName,
- 'seriesName' => $seriesName,
- 'episodeTitle' => $episodeTitle,
- 'channelName' => $channelName,
- 'userName' => $userName,
- 'duration' => $duration,
- 'status' => $status,
- 'type' => 'timer'
- ];
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('Created activity for timer ' . ($index + 1) . ': ' . json_encode($activity));
-
- // Debug timer date parsing
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('Timer date debug - StartDate: "' . ($timer['StartDate'] ?? 'null') . '", parsed startTime: ' . ($startTime ? date('Y-m-d H:i:s', $startTime) : 'failed to parse') . ', EndDate: "' . ($timer['EndDate'] ?? 'null') . '", parsed endTime: ' . ($endTime ? date('Y-m-d H:i:s', $endTime) : 'failed to parse') . ', current time: ' . date('Y-m-d H:i:s', $now) . ', calculated status: ' . $status);
-
- $scheduledRecordings[] = $activity;
- }
- }
- } catch (Exception $e) {
- $this->setLoggerChannel('EmbyLiveTVTracker')->warning('Failed to get timers for activity: ' . $e->getMessage());
- }
-
- // Get completed recordings if enabled
- if ($showCompleted) {
- $recordingsUrl = $baseUrl . '/emby/LiveTv/Recordings?api_key=' . $this->config['embyToken'] . '&StartIndex=0&Limit=' . $maxCompletedItems . '&Fields=DateCreated,SeriesName,RunTimeTicks&SortBy=DateCreated&SortOrder=Descending';
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('Fetching completed recordings from URL: ' . $recordingsUrl);
- try {
- $recordingsResponse = Requests::get($recordingsUrl, [], $options);
- if ($recordingsResponse->success) {
- $recordings = json_decode($recordingsResponse->body, true);
- $allRecordings = $recordings['Items'] ?? [];
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('Retrieved ' . count($allRecordings) . ' completed recordings');
-
- foreach ($allRecordings as $recording) {
- if (isset($recording['DateCreated'])) {
- // Format duration
- $duration = '-';
- if (isset($recording['RunTimeTicks']) && $recording['RunTimeTicks'] > 0) {
- $minutes = floor($recording['RunTimeTicks'] / 600000000);
- $hours = floor($minutes / 60);
- $remainingMinutes = $minutes % 60;
- if ($hours > 0) {
- $duration = sprintf('%dh %dm', $hours, $remainingMinutes);
- } else {
- $duration = sprintf('%dm', $minutes);
- }
- }
-
- $completedRecordings[] = [
- 'date' => $recording['DateCreated'],
- 'name' => $recording['Name'] ?? 'Unknown Program',
- 'seriesName' => $recording['SeriesName'] ?? '',
- 'channelName' => 'Unknown Channel', // Completed recordings don't have reliable channel info
- 'userName' => null, // No user info available for completed recordings
- 'duration' => $duration,
- 'status' => 'Completed',
- 'type' => 'recording'
- ];
- }
- }
- }
- } catch (Exception $e) {
- $this->setLoggerChannel('EmbyLiveTVTracker')->warning('Failed to get completed recordings: ' . $e->getMessage());
- }
- }
-
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('Final scheduled recordings count: ' . count($scheduledRecordings));
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('Final completed recordings count: ' . count($completedRecordings));
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('Sample scheduled: ' . json_encode(array_slice($scheduledRecordings, 0, 1)));
- $this->setLoggerChannel('EmbyLiveTVTracker')->info('Sample completed: ' . json_encode(array_slice($completedRecordings, 0, 1)));
-
- $this->setAPIResponse('success', 'LiveTV activity retrieved successfully', 200, [
- 'scheduledRecordings' => $scheduledRecordings,
- 'completedRecordings' => $completedRecordings
- ]);
- return true;
-
- } catch (Exception $e) {
- $this->setAPIResponse('error', 'Failed to retrieve LiveTV activity: ' . $e->getMessage(), 500);
- return false;
- }
- }
- }
- ?>
|