jellyfin.php 26 KB

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