jellyfin.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. <?php
  2. trait JellyfinHomepageItem
  3. {
  4. public function jellyfinSettingsArray($infoOnly = false)
  5. {
  6. $homepageInformation = [
  7. 'name' => 'Jellyfin',
  8. 'enabled' => strpos('personal', $this->config['license']) !== false,
  9. 'image' => 'plugins/images/tabs/jellyfin.png',
  10. 'category' => 'Media Server',
  11. 'settingsArray' => __FUNCTION__
  12. ];
  13. if ($infoOnly) {
  14. return $homepageInformation;
  15. }
  16. $homepageSettings = [
  17. 'debug' => true,
  18. 'settings' => [
  19. 'Enable' => [
  20. $this->settingsOption('enable', 'homepageJellyfinEnabled'),
  21. $this->settingsOption('auth', 'homepageJellyfinAuth'),
  22. ],
  23. 'Connection' => [
  24. $this->settingsOption('url', 'jellyfinURL'),
  25. $this->settingsOption('token', 'jellyfinToken'),
  26. $this->settingsOption('disable-cert-check', 'jellyfinDisableCertCheck'),
  27. $this->settingsOption('use-custom-certificate', 'jellyfinUseCustomCertificate'),
  28. ],
  29. 'Active Streams' => [
  30. $this->settingsOption('enable', 'homepageJellyfinStreams'),
  31. $this->settingsOption('auth', 'homepageJellyStreamsAuth'),
  32. $this->settingsOption('switch', 'homepageShowStreamNames', ['label' => 'User Information']),
  33. $this->settingsOption('auth', 'homepageShowStreamNamesAuth'),
  34. $this->settingsOption('refresh', 'homepageStreamRefresh'),
  35. ],
  36. 'Recent Items' => [
  37. $this->settingsOption('enable', 'homepageJellyfinRecent'),
  38. $this->settingsOption('auth', 'homepageJellyfinRecentAuth'),
  39. $this->settingsOption('limit', 'homepageRecentLimit'),
  40. $this->settingsOption('refresh', 'homepageRecentRefresh'),
  41. ],
  42. 'Misc Options' => [
  43. $this->settingsOption('input', 'homepageJellyfinLink', ['label' => 'Jellyfin Homepage Link URL', 'help' => 'Available variables: {id} {serverId}']),
  44. $this->settingsOption('input', 'jellyfinTabName', ['label' => 'Jellyfin Tab Name', 'placeholder' => 'Only use if you have Jellyfin in a reverse proxy']),
  45. $this->settingsOption('image-cache-quality', 'cacheImageSize'),
  46. ],
  47. 'Test Connection' => [
  48. $this->settingsOption('blank', null, ['label' => 'Please Save before Testing']),
  49. $this->settingsOption('test', 'jellyfin'),
  50. ]
  51. ]
  52. ];
  53. return array_merge($homepageInformation, $homepageSettings);
  54. }
  55. public function testConnectionJellyfin()
  56. {
  57. if (empty($this->config['jellyfinURL'])) {
  58. $this->setAPIResponse('error', 'Jellyfin URL is not defined', 422);
  59. return false;
  60. }
  61. if (empty($this->config['jellyfinToken'])) {
  62. $this->setAPIResponse('error', 'Jellyfin Token is not defined', 422);
  63. return false;
  64. }
  65. $url = $this->qualifyURL($this->config['jellyfinURL']);
  66. $url = $url . "/Users?api_key=" . $this->config['jellyfinToken'];
  67. $options = $this->requestOptions($url, null, $this->config['jellyfinDisableCertCheck'], $this->config['jellyfinUseCustomCertificate']);
  68. try {
  69. $response = Requests::get($url, [], $options);
  70. if ($response->success) {
  71. $json = json_decode($response->body);
  72. if (is_array($json) || is_object($json)) {
  73. $this->setAPIResponse('success', 'API Connection succeeded', 200);
  74. return true;
  75. } else {
  76. $this->setAPIResponse('error', 'URL or token incorrect', 409);
  77. return false;
  78. }
  79. } else {
  80. $this->setAPIResponse('error', 'Jellyfin Connection Error', 500);
  81. return true;
  82. }
  83. } catch (Requests_Exception $e) {
  84. $this->setAPIResponse('error', $e->getMessage(), 500);
  85. return false;
  86. }
  87. }
  88. public function jellyfinHomepagePermissions($key = null)
  89. {
  90. $permissions = [
  91. 'streams' => [
  92. 'enabled' => [
  93. 'homepageJellyfinEnabled',
  94. 'homepageJellyfinStreams'
  95. ],
  96. 'auth' => [
  97. 'homepageJellyfinAuth',
  98. 'homepageJellyStreamsAuth'
  99. ],
  100. 'not_empty' => [
  101. 'jellyfinURL',
  102. 'jellyfinToken'
  103. ]
  104. ],
  105. 'recent' => [
  106. 'enabled' => [
  107. 'homepageJellyfinEnabled',
  108. 'homepageJellyfinRecent'
  109. ],
  110. 'auth' => [
  111. 'homepageJellyfinAuth',
  112. 'homepageJellyfinRecentAuth'
  113. ],
  114. 'not_empty' => [
  115. 'jellyfinURL',
  116. 'jellyfinToken'
  117. ]
  118. ],
  119. 'metadata' => [
  120. 'enabled' => [
  121. 'homepageJellyfinEnabled'
  122. ],
  123. 'auth' => [
  124. 'homepageJellyfinAuth'
  125. ],
  126. 'not_empty' => [
  127. 'jellyfinURL',
  128. 'jellyfinToken'
  129. ]
  130. ]
  131. ];
  132. if (array_key_exists($key, $permissions)) {
  133. return $permissions[$key];
  134. } elseif ($key == 'all') {
  135. return $permissions;
  136. } else {
  137. return [];
  138. }
  139. }
  140. public function homepageOrderjellyfinnowplaying()
  141. {
  142. if ($this->homepageItemPermissions($this->jellyfinHomepagePermissions('streams'))) {
  143. return '
  144. <div id="' . __FUNCTION__ . '">
  145. <div class="white-box homepage-loading-box"><h2 class="text-center" lang="en">Loading Now Playing...</h2></div>
  146. <script>
  147. // Jellyfin Stream
  148. homepageStream("jellyfin", "' . $this->config['homepageStreamRefresh'] . '");
  149. // End Jellyfin Stream
  150. </script>
  151. </div>
  152. ';
  153. }
  154. }
  155. public function homepageOrderjellyfinrecent()
  156. {
  157. if ($this->homepageItemPermissions($this->jellyfinHomepagePermissions('recent'))) {
  158. return '
  159. <div id="' . __FUNCTION__ . '">
  160. <div class="white-box homepage-loading-box"><h2 class="text-center" lang="en">Loading Recent...</h2></div>
  161. <script>
  162. // Jellyfin Recent
  163. homepageRecent("jellyfin", "' . $this->config['homepageRecentRefresh'] . '");
  164. // End Jellyfin Recent
  165. </script>
  166. </div>
  167. ';
  168. }
  169. }
  170. public function getJellyfinHomepageStreams()
  171. {
  172. if (!$this->homepageItemPermissions($this->jellyfinHomepagePermissions('streams'), true)) {
  173. return false;
  174. }
  175. $url = $this->qualifyURL($this->config['jellyfinURL']);
  176. $url = $url . '/Sessions?api_key=' . $this->config['jellyfinToken'] . '&Fields=Overview,People,Genres,CriticRating,Studios,Taglines';
  177. $options = $this->requestOptions($url, $this->config['homepageStreamRefresh'], $this->config['jellyfinDisableCertCheck'], $this->config['jellyfinUseCustomCertificate']);
  178. try {
  179. $response = Requests::get($url, [], $options);
  180. if ($response->success) {
  181. $items = array();
  182. $jellyfin = json_decode($response->body, true);
  183. foreach ($jellyfin as $child) {
  184. if (isset($child['NowPlayingItem']) || isset($child['Name'])) {
  185. $items[] = $this->resolveJellyfinItem($child);
  186. }
  187. }
  188. $api['content'] = array_filter($items);
  189. $this->setAPIResponse('success', null, 200, $api);
  190. return $api;
  191. } else {
  192. $this->setAPIResponse('error', 'Jellyfin Error Occurred', 500);
  193. return false;
  194. }
  195. } catch (Requests_Exception $e) {
  196. $this->writeLog('error', 'Jellyfin Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
  197. $this->setAPIResponse('error', $e->getMessage(), 500);
  198. return false;
  199. }
  200. }
  201. public function getJellyfinHomepageRecent()
  202. {
  203. if (!$this->homepageItemPermissions($this->jellyfinHomepagePermissions('recent'), true)) {
  204. return false;
  205. }
  206. $url = $this->qualifyURL($this->config['jellyfinURL']);
  207. $options = $this->requestOptions($url, $this->config['homepageRecentRefresh'], $this->config['jellyfinDisableCertCheck'], $this->config['jellyfinUseCustomCertificate']);
  208. $username = false;
  209. $showPlayed = false;
  210. $userId = 0;
  211. try {
  212. if (isset($this->user['username'])) {
  213. $username = strtolower($this->user['username']);
  214. }
  215. // Get A User
  216. $userIds = $url . "/Users?api_key=" . $this->config['jellyfinToken'];
  217. $response = Requests::get($userIds, [], $options);
  218. if ($response->success) {
  219. $jellyfin = json_decode($response->body, true);
  220. foreach ($jellyfin as $value) { // Scan for admin user
  221. if (isset($value['Policy']) && isset($value['Policy']['IsAdministrator']) && $value['Policy']['IsAdministrator']) {
  222. $userId = $value['Id'];
  223. }
  224. if ($username && strtolower($value['Name']) == $username) {
  225. $userId = $value['Id'];
  226. $showPlayed = false;
  227. break;
  228. }
  229. }
  230. $url = $url . '/Users/' . $userId . '/Items/Latest?EnableImages=true&Limit=' . $this->config['homepageRecentLimit'] . '&api_key=' . $this->config['jellyfinToken'] . ($showPlayed ? '' : '&IsPlayed=false') . '&Fields=Overview,People,Genres,CriticRating,Studios,Taglines';
  231. } else {
  232. $this->setAPIResponse('error', 'Jellyfin Error Occurred', 500);
  233. return false;
  234. }
  235. $response = Requests::get($url, [], $options);
  236. if ($response->success) {
  237. $items = array();
  238. $jellyfin = json_decode($response->body, true);
  239. foreach ($jellyfin as $child) {
  240. if (isset($child['NowPlayingItem']) || isset($child['Name'])) {
  241. $items[] = $this->resolveJellyfinItem($child);
  242. }
  243. }
  244. $api['content'] = array_filter($items);
  245. $this->setAPIResponse('success', null, 200, $api);
  246. return $api;
  247. } else {
  248. $this->setAPIResponse('error', 'Jellyfin Error Occurred', 500);
  249. return false;
  250. }
  251. } catch (Requests_Exception $e) {
  252. $this->writeLog('error', 'Jellyfin Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
  253. $this->setAPIResponse('error', $e->getMessage(), 500);
  254. return false;
  255. }
  256. }
  257. public function getJellyfinHomepageMetadata($array)
  258. {
  259. if (!$this->homepageItemPermissions($this->jellyfinHomepagePermissions('metadata'), true)) {
  260. return false;
  261. }
  262. $key = $array['key'] ?? null;
  263. if (!$key) {
  264. $this->setAPIResponse('error', 'Jellyfin Metadata key is not defined', 422);
  265. return false;
  266. }
  267. $url = $this->qualifyURL($this->config['jellyfinURL']);
  268. $options = $this->requestOptions($url, 60, $this->config['jellyfinDisableCertCheck'], $this->config['jellyfinUseCustomCertificate']);
  269. $username = false;
  270. $showPlayed = false;
  271. $userId = 0;
  272. try {
  273. if (isset($this->user['username'])) {
  274. $username = strtolower($this->user['username']);
  275. }
  276. // Get A User
  277. $userIds = $url . "/Users?api_key=" . $this->config['jellyfinToken'];
  278. $response = Requests::get($userIds, [], $options);
  279. if ($response->success) {
  280. $jellyfin = json_decode($response->body, true);
  281. foreach ($jellyfin as $value) { // Scan for admin user
  282. if (isset($value['Policy']) && isset($value['Policy']['IsAdministrator']) && $value['Policy']['IsAdministrator']) {
  283. $userId = $value['Id'];
  284. }
  285. if ($username && strtolower($value['Name']) == $username) {
  286. $userId = $value['Id'];
  287. $showPlayed = false;
  288. break;
  289. }
  290. }
  291. $url = $url . '/Users/' . $userId . '/Items/' . $key . '?EnableImages=true&Limit=' . $this->config['homepageRecentLimit'] . '&api_key=' . $this->config['jellyfinToken'] . ($showPlayed ? '' : '&IsPlayed=false') . '&Fields=Overview,People,Genres,CriticRating,Studios,Taglines';
  292. } else {
  293. $this->setAPIResponse('error', 'Jellyfin Error Occurred', 500);
  294. return false;
  295. }
  296. $response = Requests::get($url, [], $options);
  297. if ($response->success) {
  298. $items = array();
  299. $jellyfin = json_decode($response->body, true);
  300. if (isset($jellyfin['NowPlayingItem']) || isset($jellyfin['Name'])) {
  301. $items[] = $this->resolveJellyfinItem($jellyfin);
  302. }
  303. $api['content'] = array_filter($items);
  304. $this->setAPIResponse('success', null, 200, $api);
  305. return $api;
  306. } else {
  307. $this->setAPIResponse('error', 'Jellyfin Error Occurred', 500);
  308. return false;
  309. }
  310. } catch (Requests_Exception $e) {
  311. $this->writeLog('error', 'Jellyfin Connect Function - Error: ' . $e->getMessage(), 'SYSTEM');
  312. $this->setAPIResponse('error', $e->getMessage(), 500);
  313. return false;
  314. }
  315. }
  316. public function resolveJellyfinItem($itemDetails)
  317. {
  318. $item = isset($itemDetails['NowPlayingItem']['Id']) ? $itemDetails['NowPlayingItem'] : $itemDetails;
  319. // Static Height & Width
  320. $height = $this->getCacheImageSize('h');
  321. $width = $this->getCacheImageSize('w');
  322. $nowPlayingHeight = $this->getCacheImageSize('nph');
  323. $nowPlayingWidth = $this->getCacheImageSize('npw');
  324. $actorHeight = 450;
  325. $actorWidth = 300;
  326. // Cache Directories
  327. $cacheDirectory = dirname(__DIR__, 2) . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR;
  328. $cacheDirectoryWeb = 'plugins/images/cache/';
  329. // Types
  330. switch (@$item['Type']) {
  331. case 'Series':
  332. $jellyfinItem['type'] = 'tv';
  333. $jellyfinItem['title'] = $item['Name'];
  334. $jellyfinItem['secondaryTitle'] = '';
  335. $jellyfinItem['summary'] = '';
  336. $jellyfinItem['ratingKey'] = $item['Id'];
  337. $jellyfinItem['thumb'] = $item['Id'];
  338. $jellyfinItem['key'] = $item['Id'] . "-list";
  339. $jellyfinItem['nowPlayingThumb'] = $item['Id'];
  340. $jellyfinItem['nowPlayingKey'] = $item['Id'] . "-np";
  341. $jellyfinItem['metadataKey'] = $item['Id'];
  342. $jellyfinItem['nowPlayingImageType'] = isset($item['ImageTags']['Thumb']) ? 'Thumb' : (isset($item['BackdropImageTags'][0]) ? 'Backdrop' : '');
  343. break;
  344. case 'Episode':
  345. $jellyfinItem['type'] = 'tv';
  346. $jellyfinItem['title'] = $item['SeriesName'];
  347. $jellyfinItem['secondaryTitle'] = '';
  348. $jellyfinItem['summary'] = '';
  349. $jellyfinItem['ratingKey'] = $item['Id'];
  350. $jellyfinItem['thumb'] = (isset($item['SeriesId']) ? $item['SeriesId'] : $item['Id']);
  351. $jellyfinItem['key'] = (isset($item['SeriesId']) ? $item['SeriesId'] : $item['Id']) . "-list";
  352. $jellyfinItem['nowPlayingThumb'] = isset($item['ParentThumbItemId']) ? $item['ParentThumbItemId'] : (isset($item['ParentBackdropItemId']) ? $item['ParentBackdropItemId'] : false);
  353. $jellyfinItem['nowPlayingKey'] = isset($item['ParentThumbItemId']) ? $item['ParentThumbItemId'] . '-np' : (isset($item['ParentBackdropItemId']) ? $item['ParentBackdropItemId'] . '-np' : false);
  354. $jellyfinItem['metadataKey'] = $item['Id'];
  355. $jellyfinItem['nowPlayingImageType'] = isset($item['ImageTags']['Thumb']) ? 'Thumb' : (isset($item['ParentBackdropImageTags'][0]) ? 'Backdrop' : '');
  356. $jellyfinItem['nowPlayingTitle'] = @$item['SeriesName'] . ' - ' . @$item['Name'];
  357. $jellyfinItem['nowPlayingBottom'] = 'S' . @$item['ParentIndexNumber'] . ' · E' . @$item['IndexNumber'];
  358. break;
  359. case 'MusicAlbum':
  360. case 'Audio':
  361. $jellyfinItem['type'] = 'music';
  362. $jellyfinItem['title'] = $item['Name'];
  363. $jellyfinItem['secondaryTitle'] = '';
  364. $jellyfinItem['summary'] = '';
  365. $jellyfinItem['ratingKey'] = $item['Id'];
  366. $jellyfinItem['thumb'] = $item['Id'];
  367. $jellyfinItem['key'] = $item['Id'] . "-list";
  368. $jellyfinItem['nowPlayingThumb'] = (isset($item['AlbumId']) ? $item['AlbumId'] : @$item['ParentBackdropItemId']);
  369. $jellyfinItem['nowPlayingKey'] = $item['Id'] . "-np";
  370. $jellyfinItem['metadataKey'] = isset($item['AlbumId']) ? $item['AlbumId'] : $item['Id'];
  371. $jellyfinItem['nowPlayingImageType'] = (isset($item['ParentBackdropItemId']) ? "Primary" : "Backdrop");
  372. $jellyfinItem['nowPlayingTitle'] = @$item['AlbumArtist'] . ' - ' . @$item['Name'];
  373. $jellyfinItem['nowPlayingBottom'] = @$item['Album'];
  374. break;
  375. case 'Movie':
  376. $jellyfinItem['type'] = 'movie';
  377. $jellyfinItem['title'] = $item['Name'];
  378. $jellyfinItem['secondaryTitle'] = '';
  379. $jellyfinItem['summary'] = '';
  380. $jellyfinItem['ratingKey'] = $item['Id'];
  381. $jellyfinItem['thumb'] = $item['Id'];
  382. $jellyfinItem['key'] = $item['Id'] . "-list";
  383. $jellyfinItem['nowPlayingThumb'] = $item['Id'];
  384. $jellyfinItem['nowPlayingKey'] = $item['Id'] . "-np";
  385. $jellyfinItem['metadataKey'] = $item['Id'];
  386. $jellyfinItem['nowPlayingImageType'] = isset($item['ImageTags']['Thumb']) ? "Thumb" : (isset($item['BackdropImageTags']) ? "Backdrop" : false);
  387. $jellyfinItem['nowPlayingTitle'] = @$item['Name'];
  388. $jellyfinItem['nowPlayingBottom'] = @$item['ProductionYear'];
  389. break;
  390. case 'Video':
  391. $jellyfinItem['type'] = 'video';
  392. $jellyfinItem['title'] = $item['Name'];
  393. $jellyfinItem['secondaryTitle'] = '';
  394. $jellyfinItem['summary'] = '';
  395. $jellyfinItem['ratingKey'] = $item['Id'];
  396. $jellyfinItem['thumb'] = $item['Id'];
  397. $jellyfinItem['key'] = $item['Id'] . "-list";
  398. $jellyfinItem['nowPlayingThumb'] = $item['Id'];
  399. $jellyfinItem['nowPlayingKey'] = $item['Id'] . "-np";
  400. $jellyfinItem['metadataKey'] = $item['Id'];
  401. $jellyfinItem['nowPlayingImageType'] = isset($item['ImageTags']['Thumb']) ? "Thumb" : (isset($item['BackdropImageTags']) ? "Backdrop" : false);
  402. $jellyfinItem['nowPlayingTitle'] = @$item['Name'];
  403. $jellyfinItem['nowPlayingBottom'] = @$item['ProductionYear'];
  404. break;
  405. default:
  406. return false;
  407. }
  408. $jellyfinItem['uid'] = $item['Id'];
  409. $jellyfinItem['imageType'] = (isset($item['ImageTags']['Primary']) ? "Primary" : false);
  410. $jellyfinItem['elapsed'] = isset($itemDetails['PlayState']['PositionTicks']) && $itemDetails['PlayState']['PositionTicks'] !== '0' ? (int)$itemDetails['PlayState']['PositionTicks'] : null;
  411. $jellyfinItem['duration'] = isset($itemDetails['NowPlayingItem']['RunTimeTicks']) ? (int)$itemDetails['NowPlayingItem']['RunTimeTicks'] : (int)(isset($item['RunTimeTicks']) ? $item['RunTimeTicks'] : '');
  412. $jellyfinItem['watched'] = ($jellyfinItem['elapsed'] && $jellyfinItem['duration'] ? floor(($jellyfinItem['elapsed'] / $jellyfinItem['duration']) * 100) : 0);
  413. $jellyfinItem['transcoded'] = isset($itemDetails['TranscodingInfo']['CompletionPercentage']) ? floor((int)$itemDetails['TranscodingInfo']['CompletionPercentage']) : 100;
  414. $jellyfinItem['stream'] = @$itemDetails['PlayState']['PlayMethod'];
  415. $jellyfinItem['id'] = $item['ServerId'];
  416. $jellyfinItem['session'] = @$itemDetails['DeviceId'];
  417. $jellyfinItem['bandwidth'] = isset($itemDetails['TranscodingInfo']['Bitrate']) ? $itemDetails['TranscodingInfo']['Bitrate'] / 1000 : '';
  418. $jellyfinItem['bandwidthType'] = 'wan';
  419. $jellyfinItem['sessionType'] = (@$itemDetails['PlayState']['PlayMethod'] == 'Transcode') ? 'Transcoding' : 'Direct Playing';
  420. $jellyfinItem['state'] = ((@(string)$itemDetails['PlayState']['IsPaused'] == '1') ? "pause" : "play");
  421. $jellyfinItem['user'] = ($this->config['homepageShowStreamNames'] && $this->qualifyRequest($this->config['homepageShowStreamNamesAuth'])) ? @(string)$itemDetails['UserName'] : "";
  422. $jellyfinItem['userThumb'] = '';
  423. $jellyfinItem['userAddress'] = (isset($itemDetails['RemoteEndPoint']) ? $itemDetails['RemoteEndPoint'] : "x.x.x.x");
  424. $jellfinVariablesForLink = [
  425. '{id}' => $jellyfinItem['uid'],
  426. '{serverId}' => $jellyfinItem['id']
  427. ];
  428. $jellyfinItem['address'] = $this->userDefinedIdReplacementLink($this->config['homepageJellyfinLink'], $jellfinVariablesForLink);
  429. $jellyfinItem['nowPlayingOriginalImage'] = 'api/v2/homepage/image?source=jellyfin&type=' . $jellyfinItem['nowPlayingImageType'] . '&img=' . $jellyfinItem['nowPlayingThumb'] . '&height=' . $nowPlayingHeight . '&width=' . $nowPlayingWidth . '&key=' . $jellyfinItem['nowPlayingKey'] . '$' . $this->randString();
  430. $jellyfinItem['originalImage'] = 'api/v2/homepage/image?source=jellyfin&type=' . $jellyfinItem['imageType'] . '&img=' . $jellyfinItem['thumb'] . '&height=' . $height . '&width=' . $width . '&key=' . $jellyfinItem['key'] . '$' . $this->randString();
  431. $jellyfinItem['openTab'] = (bool)$this->config['jellyfinTabName'];
  432. $jellyfinItem['tabName'] = $this->config['jellyfinTabName'] ?: '';
  433. // Stream info
  434. $jellyfinItem['userStream'] = array(
  435. 'platform' => @(string)$itemDetails['Client'],
  436. 'product' => @(string)$itemDetails['Client'],
  437. 'device' => @(string)$itemDetails['DeviceName'],
  438. 'stream' => @$itemDetails['PlayState']['PlayMethod'],
  439. 'videoResolution' => isset($itemDetails['NowPlayingItem']['MediaStreams'][0]['Width']) ? $itemDetails['NowPlayingItem']['MediaStreams'][0]['Width'] : '',
  440. 'throttled' => false,
  441. 'sourceVideoCodec' => isset($itemDetails['NowPlayingItem']['MediaStreams'][0]) ? $itemDetails['NowPlayingItem']['MediaStreams'][0]['Codec'] : '',
  442. 'videoCodec' => @$itemDetails['TranscodingInfo']['VideoCodec'],
  443. 'audioCodec' => @$itemDetails['TranscodingInfo']['AudioCodec'],
  444. 'sourceAudioCodec' => isset($itemDetails['NowPlayingItem']['MediaStreams'][1]) ? $itemDetails['NowPlayingItem']['MediaStreams'][1]['Codec'] : (isset($itemDetails['NowPlayingItem']['MediaStreams'][0]) ? $itemDetails['NowPlayingItem']['MediaStreams'][0]['Codec'] : ''),
  445. 'videoDecision' => $this->streamType(@$itemDetails['PlayState']['PlayMethod']),
  446. 'audioDecision' => $this->streamType(@$itemDetails['PlayState']['PlayMethod']),
  447. 'container' => isset($itemDetails['NowPlayingItem']['Container']) ? $itemDetails['NowPlayingItem']['Container'] : '',
  448. 'audioChannels' => @$itemDetails['TranscodingInfo']['AudioChannels']
  449. );
  450. // Genre catch all
  451. if (isset($item['Genres'])) {
  452. $genres = array();
  453. foreach ($item['Genres'] as $genre) {
  454. $genres[] = $genre;
  455. }
  456. }
  457. // Actor catch all
  458. if (isset($item['People'])) {
  459. $actors = array();
  460. foreach ($item['People'] as $key => $value) {
  461. if (@$value['PrimaryImageTag'] && @$value['Role']) {
  462. if (file_exists($cacheDirectory . (string)$value['Id'] . '-cast.jpg')) {
  463. $actorImage = $cacheDirectoryWeb . (string)$value['Id'] . '-cast.jpg';
  464. }
  465. if (file_exists($cacheDirectory . (string)$value['Id'] . '-cast.jpg') && (time() - 604800) > filemtime($cacheDirectory . (string)$value['Id'] . '-cast.jpg') || !file_exists($cacheDirectory . (string)$value['Id'] . '-cast.jpg')) {
  466. $actorImage = 'api/v2/homepage/image?source=jellyfin&type=Primary&img=' . (string)$value['Id'] . '&height=' . $actorHeight . '&width=' . $actorWidth . '&key=' . (string)$value['Id'] . '-cast';
  467. }
  468. $actors[] = array(
  469. 'name' => (string)$value['Name'],
  470. 'role' => (string)$value['Role'],
  471. 'thumb' => $actorImage
  472. );
  473. }
  474. }
  475. }
  476. // Metadata information
  477. $jellyfinItem['metadata'] = array(
  478. 'guid' => $item['Id'],
  479. 'summary' => @(string)$item['Overview'],
  480. 'rating' => @(string)$item['CommunityRating'],
  481. 'duration' => @(string)$item['RunTimeTicks'],
  482. 'originallyAvailableAt' => @(string)$item['PremiereDate'],
  483. 'year' => (string)isset($item['ProductionYear']) ? $item['ProductionYear'] : '',
  484. //'studio' => (string)$item['studio'],
  485. 'tagline' => @(string)$item['Taglines'][0],
  486. 'genres' => (isset($item['Genres'])) ? $genres : '',
  487. 'actors' => (isset($item['People'])) ? $actors : ''
  488. );
  489. if (file_exists($cacheDirectory . $jellyfinItem['nowPlayingKey'] . '.jpg')) {
  490. $jellyfinItem['nowPlayingImageURL'] = $cacheDirectoryWeb . $jellyfinItem['nowPlayingKey'] . '.jpg';
  491. }
  492. if (file_exists($cacheDirectory . $jellyfinItem['key'] . '.jpg')) {
  493. $jellyfinItem['imageURL'] = $cacheDirectoryWeb . $jellyfinItem['key'] . '.jpg';
  494. }
  495. if (file_exists($cacheDirectory . $jellyfinItem['nowPlayingKey'] . '.jpg') && (time() - 604800) > filemtime($cacheDirectory . $jellyfinItem['nowPlayingKey'] . '.jpg') || !file_exists($cacheDirectory . $jellyfinItem['nowPlayingKey'] . '.jpg')) {
  496. $jellyfinItem['nowPlayingImageURL'] = 'api/v2/homepage/image?source=jellyfin&type=' . $jellyfinItem['nowPlayingImageType'] . '&img=' . $jellyfinItem['nowPlayingThumb'] . '&height=' . $nowPlayingHeight . '&width=' . $nowPlayingWidth . '&key=' . $jellyfinItem['nowPlayingKey'] . '';
  497. }
  498. if (file_exists($cacheDirectory . $jellyfinItem['key'] . '.jpg') && (time() - 604800) > filemtime($cacheDirectory . $jellyfinItem['key'] . '.jpg') || !file_exists($cacheDirectory . $jellyfinItem['key'] . '.jpg')) {
  499. $jellyfinItem['imageURL'] = 'api/v2/homepage/image?source=jellyfin&type=' . $jellyfinItem['imageType'] . '&img=' . $jellyfinItem['thumb'] . '&height=' . $height . '&width=' . $width . '&key=' . $jellyfinItem['key'] . '';
  500. }
  501. if (!$jellyfinItem['nowPlayingThumb']) {
  502. $jellyfinItem['nowPlayingOriginalImage'] = $jellyfinItem['nowPlayingImageURL'] = "plugins/images/cache/no-np.png";
  503. $jellyfinItem['nowPlayingKey'] = "no-np";
  504. }
  505. if (!$jellyfinItem['thumb']) {
  506. $jellyfinItem['originalImage'] = $jellyfinItem['imageURL'] = "plugins/images/cache/no-list.png";
  507. $jellyfinItem['key'] = "no-list";
  508. }
  509. if (isset($useImage)) {
  510. $jellyfinItem['useImage'] = $useImage;
  511. }
  512. return $jellyfinItem;
  513. }
  514. }