jellyfin.php 26 KB

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