'Plex', 'enabled' => strpos('personal', $this->config['license']) !== false, 'image' => 'plugins/images/tabs/plex.png', 'category' => 'Media Server', 'settingsArray' => __FUNCTION__ ]; if ($infoOnly) { return $homepageInformation; } $libraryList = [['name' => 'Refresh page to update List', 'value' => '', 'disabled' => true]]; if ($this->config['plexID'] !== '' && $this->config['plexToken'] !== '') { $loop = $this->plexLibraryList('key'); if ($loop) { $loop = $loop['libraries']; foreach ($loop as $key => $value) { $libraryList[] = ['name' => $key, 'value' => $value]; } } } $homepageSettings = [ 'docs' => $this->docs('features/homepage/plex-homepage-item'), 'debug' => true, 'settings' => [ 'Enable' => [ $this->settingsOption('enable', 'homepagePlexEnabled'), $this->settingsOption('auth', 'homepagePlexAuth'), ], 'Connection' => [ $this->settingsOption('url', 'plexURL'), $this->settingsOption('blank'), $this->settingsOption('disable-cert-check', 'plexDisableCertCheck'), $this->settingsOption('use-custom-certificate', 'plexUseCustomCertificate'), $this->settingsOption('token', 'plexToken'), $this->settingsOption('button', '', ['label' => 'Get Plex Token', 'icon' => 'fa fa-ticket', 'text' => 'Retrieve', 'attr' => 'onclick="PlexOAuth(oAuthSuccess,oAuthError, null, \'#homepage-Plex-form [name=plexToken]\')"']), $this->settingsOption('password-alt', 'plexID', ['label' => 'Plex Machine']), $this->settingsOption('button', '', ['label' => 'Get Plex Machine', 'icon' => 'fa fa-id-badge', 'text' => 'Retrieve', 'attr' => 'onclick="showPlexMachineForm(\'#homepage-Plex-form [name=plexID]\')"']), ], 'Active Streams' => [ $this->settingsOption('enable', 'homepagePlexStreams'), $this->settingsOption('auth', 'homepagePlexStreamsAuth'), $this->settingsOption('switch', 'homepageShowStreamNames', ['label' => 'User Information', 'help' => 'Show user and IP information']), $this->settingsOption('auth', 'homepageShowStreamNamesAuth'), $this->settingsOption('switch', 'homepageShowStreamNamesWithoutIp', ['label' => 'User Information Without IP', 'help' => 'Only shows username and no IP information']), $this->settingsOption('auth', 'homepageShowStreamNamesWithoutIpAuth'), $this->settingsOption('refresh', 'homepageStreamRefresh'), $this->settingsOption('plex-library-exclude', 'homepagePlexStreamsExclude', ['options' => $libraryList]), ], 'Recent Items' => [ $this->settingsOption('enable', 'homepagePlexRecent'), $this->settingsOption('auth', 'homepagePlexRecentAuth'), $this->settingsOption('plex-library-exclude', 'homepagePlexRecentExclude', ['options' => $libraryList]), $this->settingsOption('limit', 'homepageRecentLimit'), $this->settingsOption('refresh', 'homepageRecentRefresh'), ], 'Media Search' => [ $this->settingsOption('enable', 'mediaSearch'), $this->settingsOption('auth', 'mediaSearchAuth'), $this->settingsOption('plex-library-exclude', 'homepagePlexSearchExclude', ['options' => $libraryList]), $this->settingsOption('media-search-server', 'mediaSearchType'), ], 'Playlists' => [ $this->settingsOption('enable', 'homepagePlexPlaylist'), $this->settingsOption('auth', 'homepagePlexPlaylistAuth'), ], 'Misc Options' => [ $this->settingsOption('input', 'plexTabName', ['label' => 'Plex Tab Name', 'placeholder' => 'Only use if you have Plex in a reverse proxy']), $this->settingsOption('input', 'plexTabURL', ['label' => 'Plex Tab WAN URL', 'placeholder' => 'http(s)://domain.com/plex']), $this->settingsOption('image-cache-quality', 'cacheImageSize'), $this->settingsOption('blank'), $this->settingsOption('switch', 'homepageUseCustomStreamNames', ['label' => 'Use Tautulli custom names for users']), ], 'Test Connection' => [ $this->settingsOption('blank', null, ['label' => 'Please Save before Testing']), $this->settingsOption('test', 'plex'), ] ] ]; return array_merge($homepageInformation, $homepageSettings); } public function testConnectionPlex() { if (!empty($this->config['plexURL']) && !empty($this->config['plexToken'])) { $url = $this->qualifyURL($this->config['plexURL']) . "/servers?X-Plex-Token=" . $this->config['plexToken']; try { $options = $this->requestOptions($url, null, $this->config['plexDisableCertCheck'], $this->config['plexUseCustomCertificate']); $response = Requests::get($url, [], $options); libxml_use_internal_errors(true); if ($response->success) { $this->setAPIResponse('success', 'API Connection succeeded', 200); return true; } else { $this->setAPIResponse('error', 'URL and/or Token not setup correctly', 422); return false; } } catch (Requests_Exception $e) { $this->setResponse(500, $e->getMessage()); return false; } } else { $this->setAPIResponse('error', 'URL and/or Token not setup', 422); return 'URL and/or Token not setup'; } } public function plexHomepagePermissions($key = null) { $permissions = [ 'streams' => [ 'enabled' => [ 'homepagePlexEnabled', 'homepagePlexStreams' ], 'auth' => [ 'homepagePlexAuth', 'homepagePlexStreamsAuth' ], 'not_empty' => [ 'plexURL', 'plexToken', 'plexID' ] ], 'recent' => [ 'enabled' => [ 'homepagePlexEnabled', 'homepagePlexRecent' ], 'auth' => [ 'homepagePlexAuth', 'homepagePlexRecentAuth' ], 'not_empty' => [ 'plexURL', 'plexToken', 'plexID' ] ], 'playlists' => [ 'enabled' => [ 'homepagePlexEnabled', 'homepagePlexPlaylist' ], 'auth' => [ 'homepagePlexAuth', 'homepagePlexPlaylistAuth' ], 'not_empty' => [ 'plexURL', 'plexToken', 'plexID' ] ], 'metadata' => [ 'enabled' => [ 'homepagePlexEnabled' ], 'auth' => [ 'homepagePlexAuth' ], 'not_empty' => [ 'plexURL', 'plexToken', 'plexID' ] ], 'search' => [ 'enabled' => [ 'homepagePlexEnabled', 'mediaSearch' ], 'auth' => [ 'homepagePlexAuth', 'mediaSearchAuth' ], 'not_empty' => [ 'plexURL', 'plexToken', 'plexID' ] ] ]; return $this->homepageCheckKeyPermissions($key, $permissions); } public function homepageOrderplexnowplaying() { if ($this->homepageItemPermissions($this->plexHomepagePermissions('streams'))) { return '

Loading Now Playing...

'; } } public function homepageOrderplexrecent() { if ($this->homepageItemPermissions($this->plexHomepagePermissions('recent'))) { return '

Loading Recent...

'; } } public function homepageOrderplexplaylist() { if ($this->homepageItemPermissions($this->plexHomepagePermissions('playlists'))) { return '

Loading Playlists...

'; } } public function getPlexHomepageStreams() { if (!$this->homepageItemPermissions($this->plexHomepagePermissions('streams'), true)) { return false; } if ($this->demo) { return $this->demoData('plex/plex-streams.json'); } $this->setTautulliFriendlyNames(); $ignore = array(); $exclude = explode(',', $this->config['homepagePlexStreamsExclude']); $resolve = true; $url = $this->qualifyURL($this->config['plexURL']); $url = $url . "/status/sessions?X-Plex-Token=" . $this->config['plexToken']; $options = $this->requestOptions($url, $this->config['homepageStreamRefresh'], $this->config['plexDisableCertCheck'], $this->config['plexUseCustomCertificate']); try { $response = Requests::get($url, [], $options); libxml_use_internal_errors(true); if ($response->success) { $items = array(); $plex = simplexml_load_string($response->body); foreach ($plex as $child) { if (!in_array($child['type'], $ignore) && !in_array($child['librarySectionID'], $exclude) && isset($child['librarySectionID'])) { $items[] = $this->resolvePlexItem($child); } } $api['content'] = ($resolve) ? $items : $plex; $api['plexID'] = $this->config['plexID']; $api['showNames'] = true; $api['group'] = '1'; $this->setAPIResponse('success', null, 200, $api); return $api; } else { $this->setAPIResponse('error', null, 401, []); return []; } } catch (Exception $e) { $this->setAPIResponse('error', null, 422, [$e->getMessage()]); return false; } } public function getPlexHomepageRecent() { if (!$this->homepageItemPermissions($this->plexHomepagePermissions('recent'), true)) { return false; } $ignore = array(); $exclude = explode(',', $this->config['homepagePlexRecentExclude']); $resolve = true; $url = $this->qualifyURL($this->config['plexURL']); $urls['movie'] = $url . "/hubs/home/recentlyAdded?X-Plex-Token=" . $this->config['plexToken'] . "&X-Plex-Container-Start=0&X-Plex-Container-Size=" . $this->config['homepageRecentLimit'] . "&type=1"; $urls['tv'] = $url . "/hubs/home/recentlyAdded?X-Plex-Token=" . $this->config['plexToken'] . "&X-Plex-Container-Start=0&X-Plex-Container-Size=" . $this->config['homepageRecentLimit'] . "&type=2"; $urls['music'] = $url . "/hubs/home/recentlyAdded?X-Plex-Token=" . $this->config['plexToken'] . "&X-Plex-Container-Start=0&X-Plex-Container-Size=" . $this->config['homepageRecentLimit'] . "&type=8"; try { foreach ($urls as $k => $v) { $options = $this->requestOptions($url, $this->config['homepageRecentRefresh'], $this->config['plexDisableCertCheck'], $this->config['plexUseCustomCertificate']); $response = Requests::get($v, [], $options); libxml_use_internal_errors(true); if ($response->success) { $items = array(); $plex = simplexml_load_string($response->body); foreach ($plex as $child) { if (!in_array($child['type'], $ignore) && !in_array($child['librarySectionID'], $exclude) && isset($child['librarySectionID'])) { $items[] = $this->resolvePlexItem($child); } } if (isset($api)) { $api['content'] = array_merge($api['content'], ($resolve) ? $items : $plex); } else { $api['content'] = ($resolve) ? $items : $plex; } } } if (isset($api['content'])) { usort($api['content'], function ($a, $b) { return $b['addedAt'] <=> $a['addedAt']; }); } $api['plexID'] = $this->config['plexID']; $api['showNames'] = true; $api['group'] = '1'; $this->setAPIResponse('success', null, 200, $api); return $api; } catch (Exception $e) { $this->setAPIResponse('error', null, 422, [$e->getMessage()]); return false; } } public function getPlexHomepagePlaylists() { if (!$this->homepageItemPermissions($this->plexHomepagePermissions('playlists'), true)) { return false; } $url = $this->qualifyURL($this->config['plexURL']); $url = $url . "/playlists?X-Plex-Token=" . $this->config['plexToken']; $options = $this->requestOptions($url, null, $this->config['plexDisableCertCheck'], $this->config['plexUseCustomCertificate']); try { $response = Requests::get($url, [], $options); libxml_use_internal_errors(true); if ($response->success) { $items = array(); $plex = simplexml_load_string($response->body); foreach ($plex as $child) { if ($child['playlistType'] == "video" && strpos(strtolower($child['title']), 'private') === false) { $playlistTitleClean = preg_replace("/(\W)+/", "", (string)$child['title']); $playlistURL = $this->qualifyURL($this->config['plexURL']); $playlistURL = $playlistURL . $child['key'] . "?X-Plex-Token=" . $this->config['plexToken']; $options = ($this->localURL($url)) ? array('verify' => false) : array(); $playlistResponse = Requests::get($playlistURL, array(), $options); if ($playlistResponse->success) { $playlistResponse = simplexml_load_string($playlistResponse->body); $items[$playlistTitleClean]['title'] = (string)$child['title']; foreach ($playlistResponse->Video as $playlistItem) { $items[$playlistTitleClean][] = $this->resolvePlexItem($playlistItem); } } } } $api['content'] = $items; $api['plexID'] = $this->config['plexID']; $api['showNames'] = true; $api['group'] = '1'; $this->setAPIResponse('success', null, 200, $api); return $api; } else { $this->setAPIResponse('error', 'Plex API error', 500); return false; } } catch (Exception $e) { $this->setAPIResponse('error', null, 422, [$e->getMessage()]); return false; } } public function getPlexHomepageMetadata($array) { if (!$this->homepageItemPermissions($this->plexHomepagePermissions('metadata'), true)) { return false; } if ($this->demo) { return $this->demoData('plex/plex-metadata.json'); } $key = $array['key'] ?? null; if (!$key) { $this->setAPIResponse('error', 'Plex Metadata key is not defined', 422); return false; } $ignore = array(); $resolve = true; $url = $this->qualifyURL($this->config['plexURL']); $url = $url . "/library/metadata/" . $key . "?X-Plex-Token=" . $this->config['plexToken']; $options = $this->requestOptions($url, null, $this->config['plexDisableCertCheck'], $this->config['plexUseCustomCertificate']); try { $response = Requests::get($url, [], $options); libxml_use_internal_errors(true); if ($response->success) { $items = array(); $plex = simplexml_load_string($response->body); foreach ($plex as $child) { if (!in_array($child['type'], $ignore) && isset($child['librarySectionID'])) { $items[] = $this->resolvePlexItem($child); } } $api['content'] = ($resolve) ? $items : $plex; $api['plexID'] = $this->config['plexID']; $api['showNames'] = true; $api['group'] = '1'; $this->setAPIResponse('success', null, 200, $api); return $api; } } catch (Exception $e) { $this->setAPIResponse('error', null, 422, [$e->getMessage()]); return false; } } public function getPlexHomepageSearch($query) { if (!$this->homepageItemPermissions($this->plexHomepagePermissions('search'), true)) { return false; } $query = $query ?? null; if (!$query) { $this->setAPIResponse('error', 'Plex Metadata key is not defined', 422); return false; } $ignore = array('artist', 'episode'); $exclude = explode(',', $this->config['homepagePlexSearchExclude']); $resolve = true; $url = $this->qualifyURL($this->config['plexURL']); $url = $url . "/search?query=" . rawurlencode($query) . "&X-Plex-Token=" . $this->config['plexToken']; $options = $this->requestOptions($url, null, $this->config['plexDisableCertCheck'], $this->config['plexUseCustomCertificate']); try { $response = Requests::get($url, [], $options); libxml_use_internal_errors(true); if ($response->success) { $items = array(); $plex = simplexml_load_string($response->body); foreach ($plex as $child) { if (!in_array($child['type'], $ignore) && !in_array($child['librarySectionID'], $exclude) && isset($child['librarySectionID'])) { $items[] = $this->resolvePlexItem($child); } } $api['content'] = ($resolve) ? $items : $plex; $api['plexID'] = $this->config['plexID']; $api['showNames'] = true; $api['group'] = '1'; $this->setAPIResponse('success', null, 200, $api); return $api; } } catch (Exception $e) { $this->setAPIResponse('error', null, 422, [$e->getMessage()]); return false; } } public function resolvePlexItem($item) { // Static Height & Width $height = $this->getCacheImageSize('h'); $width = $this->getCacheImageSize('w'); $nowPlayingHeight = $this->getCacheImageSize('nph'); $nowPlayingWidth = $this->getCacheImageSize('npw'); // Cache Directories $cacheDirectory = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR; $cacheDirectoryWeb = 'data/cache/'; // Types switch ($item['type']) { case 'show': $plexItem['type'] = 'tv'; $plexItem['title'] = (string)$item['title']; $plexItem['secondaryTitle'] = (string)$item['year']; $plexItem['summary'] = (string)$item['summary']; $plexItem['ratingKey'] = (string)$item['ratingKey']; $plexItem['thumb'] = (string)$item['thumb']; $plexItem['key'] = (string)$item['ratingKey'] . "-list"; $plexItem['nowPlayingThumb'] = (string)$item['art']; $plexItem['nowPlayingKey'] = (string)$item['ratingKey'] . "-np"; $plexItem['nowPlayingTitle'] = (string)$item['title']; $plexItem['nowPlayingBottom'] = (string)$item['year']; $plexItem['metadataKey'] = (string)$item['ratingKey']; break; case 'season': $plexItem['type'] = 'tv'; $plexItem['title'] = (string)$item['parentTitle']; $plexItem['secondaryTitle'] = (string)$item['title']; $plexItem['summary'] = (string)$item['parentSummary']; $plexItem['ratingKey'] = (string)$item['parentRatingKey']; $plexItem['thumb'] = (string)$item['thumb']; $plexItem['key'] = (string)$item['ratingKey'] . "-list"; $plexItem['nowPlayingThumb'] = (string)$item['art']; $plexItem['nowPlayingKey'] = (string)$item['ratingKey'] . "-np"; $plexItem['metadataKey'] = (string)$item['parentRatingKey']; break; case 'episode': $useImage = (isset($item['live']) ? 'plugins/images/homepage/livetv.png' : null); $plexItem['type'] = 'tv'; $plexItem['title'] = (string)$item['grandparentTitle']; $plexItem['secondaryTitle'] = (string)$item['parentTitle'] . ' - Episode ' . (string)$item['index']; $plexItem['summary'] = (string)$item['title']; $plexItem['ratingKey'] = (string)($item['parentRatingKey'] ?? $item['ratingKey']); $plexItem['thumb'] = ($item['parentThumb'] ? (string)$item['parentThumb'] : (string)$item['grandparentThumb']); $plexItem['key'] = (string)$item['ratingKey'] . "-list"; $plexItem['nowPlayingThumb'] = (string)$item['grandparentArt']; $plexItem['nowPlayingKey'] = (string)$item['grandparentRatingKey'] . "-np"; $plexItem['nowPlayingTitle'] = (string)$item['grandparentTitle'] . ' - ' . (string)$item['title']; $plexItem['nowPlayingBottom'] = 'S' . (string)$item['parentIndex'] . ' ยท E' . (string)$item['index']; $plexItem['metadataKey'] = (string)($item['grandparentRatingKey'] ?? $item['parentRatingKey'] ?? $item['ratingKey']); break; case 'clip': $useImage = (isset($item['live']) ? "plugins/images/homepage/livetv.png" : null); $plexItem['type'] = 'clip'; $plexItem['title'] = (isset($item['live']) ? 'Live TV' : (string)$item['title']); $plexItem['secondaryTitle'] = ''; $plexItem['summary'] = (string)$item['summary']; $plexItem['ratingKey'] = (string)$item['parentRatingKey']; $plexItem['thumb'] = (string)$item['thumb']; $plexItem['key'] = (string)$item['ratingKey'] . "-list"; $plexItem['nowPlayingThumb'] = (string)$item['art']; $plexItem['nowPlayingKey'] = isset($item['ratingKey']) ? (string)$item['ratingKey'] . "-np" : (isset($item['live']) ? "livetv.png" : ":)"); $plexItem['nowPlayingTitle'] = $plexItem['title']; $plexItem['nowPlayingBottom'] = isset($item['extraType']) ? "Trailer" : (isset($item['live']) ? "Live TV" : ":)"); break; case 'album': case 'track': $plexItem['type'] = 'music'; $plexItem['title'] = (string)$item['parentTitle']; $plexItem['secondaryTitle'] = (string)$item['title']; $plexItem['summary'] = (string)$item['title']; $plexItem['ratingKey'] = (string)$item['parentRatingKey']; $plexItem['thumb'] = (string)$item['thumb']; $plexItem['key'] = (string)$item['ratingKey'] . "-list"; $plexItem['nowPlayingThumb'] = ($item['parentThumb']) ? (string)$item['parentThumb'] : (string)$item['art']; $plexItem['nowPlayingKey'] = (string)$item['parentRatingKey'] . "-np"; $plexItem['nowPlayingTitle'] = (string)$item['grandparentTitle'] . ' - ' . (string)$item['title']; $plexItem['nowPlayingBottom'] = (string)$item['parentTitle']; $plexItem['metadataKey'] = isset($item['grandparentRatingKey']) ? (string)$item['grandparentRatingKey'] : (string)$item['parentRatingKey']; break; default: $useImage = (isset($item['live']) ? 'plugins/images/homepage/livetv.png' : null); $plexItem['type'] = 'movie'; $plexItem['title'] = (string)$item['title']; $plexItem['secondaryTitle'] = (string)$item['year']; $plexItem['summary'] = (string)$item['summary']; $plexItem['ratingKey'] = (string)$item['ratingKey']; $plexItem['thumb'] = (string)$item['thumb']; $plexItem['key'] = (string)$item['ratingKey'] . "-list"; $plexItem['nowPlayingThumb'] = (string)$item['art']; $plexItem['nowPlayingKey'] = (string)$item['ratingKey'] . "-np"; $plexItem['nowPlayingTitle'] = (string)$item['title']; $plexItem['nowPlayingBottom'] = (string)$item['year']; $plexItem['metadataKey'] = (string)$item['ratingKey']; } $plexItem['originalType'] = $item['type']; $plexItem['uid'] = (string)$item['ratingKey']; $plexItem['elapsed'] = isset($item['viewOffset']) && $item['viewOffset'] !== '0' ? (int)$item['viewOffset'] : null; $plexItem['duration'] = isset($item['duration']) ? (int)$item['duration'] : (int)$item->Media['duration']; $plexItem['addedAt'] = isset($item['addedAt']) ? (int)$item['addedAt'] : null; $plexItem['watched'] = ($plexItem['elapsed'] && $plexItem['duration'] ? floor(($plexItem['elapsed'] / $plexItem['duration']) * 100) : 0); $plexItem['transcoded'] = isset($item->TranscodeSession['progress']) ? floor((int)$item->TranscodeSession['progress'] - $plexItem['watched']) : ''; $plexItem['stream'] = isset($item->Media->Part->Stream['decision']) ? (string)$item->Media->Part->Stream['decision'] : ''; $plexItem['id'] = str_replace('"', '', (string)$item->Player['machineIdentifier']); $plexItem['session'] = (string)$item->Session['id']; $plexItem['bandwidth'] = (string)$item->Session['bandwidth']; $plexItem['bandwidthType'] = (string)$item->Session['location']; $plexItem['sessionType'] = isset($item->TranscodeSession['progress']) ? 'Transcoding' : 'Direct Playing'; $plexItem['state'] = (((string)$item->Player['state'] == "paused") ? "pause" : "play"); $plexItem['user'] = $this->formatPlexUserName($item); $plexItem['userThumb'] = (($this->config['homepageShowStreamNames'] && $this->qualifyRequest($this->config['homepageShowStreamNamesAuth'])) || ($this->config['homepageShowStreamNamesWithoutIp'] && $this->qualifyRequest($this->config['homepageShowStreamNamesWithoutIpAuth']))) ? (string)$item->User['thumb'] : ""; $plexItem['userAddress'] = ($this->config['homepageShowStreamNames'] && $this->qualifyRequest($this->config['homepageShowStreamNamesAuth'])) ? (string)$item->Player['address'] : "x.x.x.x"; $plexItem['address'] = $this->config['plexTabURL'] ? $this->config['plexTabURL'] . "/web/index.html#!/server/" . $this->config['plexID'] . "/details?key=/library/metadata/" . $item['ratingKey'] : "https://app.plex.tv/web/app#!/server/" . $this->config['plexID'] . "/details?key=/library/metadata/" . $item['ratingKey']; $plexItem['nowPlayingOriginalImage'] = 'api/v2/homepage/image?source=plex&img=' . $plexItem['nowPlayingThumb'] . '&height=' . $nowPlayingHeight . '&width=' . $nowPlayingWidth . '&key=' . $plexItem['nowPlayingKey'] . '$' . $this->randString(); $plexItem['originalImage'] = 'api/v2/homepage/image?source=plex&img=' . $plexItem['thumb'] . '&height=' . $height . '&width=' . $width . '&key=' . $plexItem['key'] . '$' . $this->randString(); $plexItem['openTab'] = $this->config['plexTabURL'] && $this->config['plexTabName'] ? true : false; $plexItem['tabName'] = $this->config['plexTabName'] ? $this->config['plexTabName'] : ''; // Stream info $plexItem['userStream'] = array( 'platform' => (string)$item->Player['platform'], 'product' => (string)$item->Player['product'], 'device' => (string)$item->Player['device'], 'stream' => isset($item->Media) ? (string)$item->Media->Part['decision'] . ($item->TranscodeSession['throttled'] == '1' ? ' (Throttled)' : '') : '', 'videoResolution' => (string)$item->Media['videoResolution'], 'throttled' => ($item->TranscodeSession['throttled'] == 1) ? true : false, 'sourceVideoCodec' => (string)$item->TranscodeSession['sourceVideoCodec'], 'videoCodec' => (string)$item->TranscodeSession['videoCodec'], 'audioCodec' => (string)$item->TranscodeSession['audioCodec'], 'sourceAudioCodec' => (string)$item->TranscodeSession['sourceAudioCodec'], 'videoDecision' => $this->streamType((string)$item->TranscodeSession['videoDecision']), 'audioDecision' => $this->streamType((string)$item->TranscodeSession['audioDecision']), 'container' => (string)$item->TranscodeSession['container'], 'audioChannels' => (string)$item->TranscodeSession['audioChannels'] ); // Genre catch all if ($item->Genre) { $genres = array(); foreach ($item->Genre as $key => $value) { $genres[] = (string)$value['tag']; } } // Actor catch all if ($item->Role) { $actors = array(); foreach ($item->Role as $key => $value) { if ($value['thumb']) { $actors[] = array( 'name' => (string)$value['tag'], 'role' => (string)$value['role'], 'thumb' => (string)$value['thumb'] ); } } } // Metadata information $plexItem['metadata'] = array( 'guid' => (string)$item['guid'], 'summary' => (string)$item['summary'], 'rating' => (string)$item['rating'], 'duration' => (string)$item['duration'], 'originallyAvailableAt' => (string)$item['originallyAvailableAt'], 'year' => (string)$item['year'], 'studio' => (string)$item['studio'], 'tagline' => (string)$item['tagline'], 'genres' => ($item->Genre) ? $genres : '', 'actors' => ($item->Role) ? $actors : '' ); if (file_exists($cacheDirectory . $plexItem['nowPlayingKey'] . '.jpg')) { $plexItem['nowPlayingImageURL'] = $cacheDirectoryWeb . $plexItem['nowPlayingKey'] . '.jpg'; } if (file_exists($cacheDirectory . $plexItem['key'] . '.jpg')) { $plexItem['imageURL'] = $cacheDirectoryWeb . $plexItem['key'] . '.jpg'; } if (file_exists($cacheDirectory . $plexItem['nowPlayingKey'] . '.jpg') && (time() - 604800) > filemtime($cacheDirectory . $plexItem['nowPlayingKey'] . '.jpg') || !file_exists($cacheDirectory . $plexItem['nowPlayingKey'] . '.jpg')) { $plexItem['nowPlayingImageURL'] = 'api/v2/homepage/image?source=plex&img=' . $plexItem['nowPlayingThumb'] . '&height=' . $nowPlayingHeight . '&width=' . $nowPlayingWidth . '&key=' . $plexItem['nowPlayingKey'] . ''; } if (file_exists($cacheDirectory . $plexItem['key'] . '.jpg') && (time() - 604800) > filemtime($cacheDirectory . $plexItem['key'] . '.jpg') || !file_exists($cacheDirectory . $plexItem['key'] . '.jpg')) { $plexItem['imageURL'] = 'api/v2/homepage/image?source=plex&img=' . $plexItem['thumb'] . '&height=' . $height . '&width=' . $width . '&key=' . $plexItem['key'] . ''; } if (!$plexItem['nowPlayingThumb']) { $plexItem['nowPlayingOriginalImage'] = $plexItem['nowPlayingImageURL'] = "plugins/images/homepage/no-np.png"; $plexItem['nowPlayingKey'] = "no-np"; } if (!$plexItem['thumb'] || $plexItem['addedAt'] >= (time() - 300)) { $plexItem['originalImage'] = $plexItem['imageURL'] = "plugins/images/homepage/no-list.png"; $plexItem['key'] = "no-list"; } if (isset($useImage)) { $plexItem['useImage'] = $useImage; } return $plexItem; } public function getTautulliFriendlyNames($bypass = null) { $names = []; if (!$this->qualifyRequest(1) && !$bypass) { return false; } $url = $this->qualifyURL($this->config['tautulliURL']); $url .= '/api/v2?apikey=' . $this->config['tautulliApikey']; $url .= '&cmd=get_users'; $options = $this->requestOptions($url, null, $this->config['tautulliDisableCertCheck'], $this->config['tautulliUseCustomCertificate']); try { $response = Requests::get($url, [], $options); if ($response->success) { $response = json_decode($response->body, true); foreach ($response['response']['data'] as $user) { if ($user['user_id'] != 0) { $names[$user['username']] = $user['friendly_name']; } } } } catch (Exception $e) { $this->setAPIResponse('error', null, 422, [$e->getMessage()]); } $this->setAPIResponse('success', null, 200, $names); return $names; } public function setTautulliFriendlyNames() { if ($this->config['tautulliURL'] && $this->config['tautulliApikey'] && $this->config['homepageUseCustomStreamNames']) { $names = $this->getTautulliFriendlyNames(true); $names = json_encode($names); if ($names !== $this->config['homepageCustomStreamNames']) { $this->updateConfig(array('homepageCustomStreamNames' => $names)); $this->config['homepageCustomStreamNames'] = $names; $this->setLoggerChannel('Tautulli'); $this->logger->debug('Updating Tautulli custom names config item', $names); } } } private function formatPlexUserName($item) { $name = (($this->config['homepageShowStreamNames'] && $this->qualifyRequest($this->config['homepageShowStreamNamesAuth'])) || ($this->config['homepageShowStreamNamesWithoutIp'] && $this->qualifyRequest($this->config['homepageShowStreamNamesWithoutIpAuth']))) ? (string)$item->User['title'] : ""; try { if ($this->config['homepageUseCustomStreamNames']) { $customNames = json_decode($this->config['homepageCustomStreamNames'], true); if (array_key_exists($name, $customNames)) { $name = $customNames[$name]; } } } catch (Exception $e) { // don't do anythig if it goes wrong, like if the JSON is badly formatted } return $name; } public function plexLibraryList($value = 'id') { if (!empty($this->config['plexToken']) && !empty($this->config['plexID'])) { $url = 'https://plex.tv/api/servers/' . $this->config['plexID']; try { $headers = array( "Accept" => "application/json", "X-Plex-Token" => $this->config['plexToken'] ); $response = Requests::get($url, $headers, array()); libxml_use_internal_errors(true); if ($response->success) { $libraryList = array(); $plex = simplexml_load_string($response->body); foreach ($plex->Server->Section as $child) { $libraryList['libraries'][(string)$child['title']] = (string)$child[$value]; } $libraryList = array_change_key_case($libraryList, CASE_LOWER); return $libraryList; } } catch (Requests_Exception $e) { $this->setLoggerChannel('Plex')->error($e); return false; }; } return false; } }