tautulli.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. <?php
  2. trait TautulliHomepageItem
  3. {
  4. public function tautulliSettingsArray($infoOnly = false)
  5. {
  6. $homepageInformation = [
  7. 'name' => 'Tautulli',
  8. 'enabled' => strpos('personal', $this->config['license']) !== false,
  9. 'image' => 'plugins/images/tabs/tautulli.png',
  10. 'category' => 'Monitor',
  11. 'settingsArray' => __FUNCTION__
  12. ];
  13. if ($infoOnly) {
  14. return $homepageInformation;
  15. }
  16. $libraryList = [['name' => 'Refresh page to update List', 'value' => '', 'disabled' => true]];
  17. if (!empty($this->config['tautulliApikey']) && !empty($this->config['tautulliURL'])) {
  18. $libraryList = [];
  19. $loop = $this->tautulliLibraryList('key')['libraries'];
  20. foreach ($loop as $key => $value) {
  21. $libraryList[] = ['name' => $key, 'value' => $value];
  22. }
  23. }
  24. $homepageSettings = [
  25. 'debug' => true,
  26. 'settings' => [
  27. 'Enable' => [
  28. $this->settingsOption('enable', 'homepageTautulliEnabled'),
  29. $this->settingsOption('auth', 'homepageTautulliAuth'),
  30. ],
  31. 'Options' => [
  32. $this->settingsOption('title', 'tautulliHeader'),
  33. $this->settingsOption('toggle-title', 'tautulliHeaderToggle'),
  34. $this->settingsOption('refresh', 'homepageTautulliRefresh'),
  35. ],
  36. 'Connection' => [
  37. $this->settingsOption('multiple-url', 'tautulliURL'),
  38. $this->settingsOption('multiple-api-key', 'tautulliApikey'),
  39. $this->settingsOption('disable-cert-check', 'tautulliDisableCertCheck'),
  40. $this->settingsOption('use-custom-certificate', 'tautulliUseCustomCertificate'),
  41. ],
  42. 'API SOCKS' => [
  43. $this->settingsOption('socks', 'tautulli'),
  44. $this->settingsOption('blank'),
  45. $this->settingsOption('enable', 'tautulliSocksEnabled'),
  46. $this->settingsOption('auth', 'tautulliSocksAuth'),
  47. ],
  48. 'Library Stats' => [
  49. $this->settingsOption('switch', 'tautulliLibraries', ['label' => 'Libraries', 'help' => 'Shows/hides the card with library information.']),
  50. $this->settingsOption('auth', 'homepageTautulliLibraryAuth'),
  51. $this->settingsOption('plex-library-exclude', 'homepageTautulliLibraryStatsExclude', ['options' => $libraryList]),
  52. ],
  53. 'Viewing Stats' => [
  54. $this->settingsOption('switch', 'tautulliPopularMovies', ['label' => 'Popular Movies', 'help' => 'Shows/hides the card with Popular Movie information.']),
  55. $this->settingsOption('switch', 'tautulliPopularTV', ['label' => 'Popular TV', 'help' => 'Shows/hides the card with Popular TV information.']),
  56. $this->settingsOption('switch', 'tautulliTopMovies', ['label' => 'Top Movies', 'help' => 'Shows/hides the card with Top Movies information.']),
  57. $this->settingsOption('switch', 'tautulliTopTV', ['label' => 'Top TV', 'help' => 'Shows/hides the card with Top TV information.']),
  58. $this->settingsOption('auth', 'homepageTautulliViewsAuth'),
  59. $this->settingsOption('plex-library-exclude', 'homepageTautulliViewingStatsExclude', ['options' => $libraryList]),
  60. ],
  61. 'Misc Stats' => [
  62. $this->settingsOption('switch', 'tautulliTopUsers', ['label' => 'Top Users', 'help' => 'Shows/hides the card with Top Users information.']),
  63. $this->settingsOption('switch', 'tautulliTopPlatforms', ['label' => 'Top Platforms', 'help' => 'Shows/hides the card with Top Platforms information.']),
  64. $this->settingsOption('auth', 'homepageTautulliMiscAuth'),
  65. $this->settingsOption('switch', 'tautulliFriendlyName', ['label' => 'Use Friendly Name', 'help' => 'Use the friendly name set in tautulli for users.']),
  66. ],
  67. 'Test Connection' => [
  68. $this->settingsOption('blank', null, ['label' => 'Please Save before Testing']),
  69. $this->settingsOption('test', 'tautulli'),
  70. ]
  71. ]
  72. ];
  73. return array_merge($homepageInformation, $homepageSettings);
  74. }
  75. public function testConnectionTautulli()
  76. {
  77. $this->setLoggerChannel('Tautulli Homepage');
  78. if (empty($this->config['tautulliURL'])) {
  79. $this->setAPIResponse('error', 'Tautulli URL is not defined', 422);
  80. return false;
  81. }
  82. if (empty($this->config['tautulliApikey'])) {
  83. $this->setAPIResponse('error', 'Tautulli Token is not defined', 422);
  84. return false;
  85. }
  86. $url = $this->qualifyURL($this->config['tautulliURL']);
  87. $apiURL = $url . '/api/v2?apikey=' . $this->config['tautulliApikey'];
  88. try {
  89. $homestatsUrl = $apiURL . '&cmd=get_home_stats&grouping=1';
  90. $options = $this->requestOptions($this->config['tautulliURL'], $this->config['homepageTautulliRefresh'], $this->config['tautulliDisableCertCheck'], $this->config['tautulliUseCustomCertificate']);
  91. $homestats = Requests::get($homestatsUrl, [], $options);
  92. if ($homestats->success) {
  93. $this->setAPIResponse('success', 'API Connection succeeded', 200);
  94. return true;
  95. } else {
  96. $this->setAPIResponse('error', 'Tautulli Error Occurred - Check URL or Credentials', 409);
  97. return false;
  98. }
  99. } catch (Requests_Exception $e) {
  100. $this->logger->critical($e, [$url]);
  101. $this->setAPIResponse('error', $e->getMessage(), 500);
  102. return false;
  103. }
  104. }
  105. public function tautulliHomepagePermissions($key = null)
  106. {
  107. $permissions = [
  108. 'main' => [
  109. 'enabled' => [
  110. 'homepageTautulliEnabled'
  111. ],
  112. 'auth' => [
  113. 'homepageTautulliAuth'
  114. ],
  115. 'not_empty' => [
  116. 'tautulliURL',
  117. 'tautulliApikey'
  118. ]
  119. ]
  120. ];
  121. return $this->homepageCheckKeyPermissions($key, $permissions);
  122. }
  123. public function homepageOrdertautulli()
  124. {
  125. if ($this->homepageItemPermissions($this->tautulliHomepagePermissions('main'))) {
  126. return '
  127. <div id="' . __FUNCTION__ . '">
  128. <div class="white-box homepage-loading-box"><h2 class="text-center" lang="en">Loading Tautulli...</h2></div>
  129. <script>
  130. // Tautulli
  131. homepageTautulli("' . $this->config['homepageTautulliRefresh'] . '");
  132. // End Tautulli
  133. </script>
  134. </div>
  135. ';
  136. }
  137. }
  138. public function getTautulliHomepageData()
  139. {
  140. $this->setLoggerChannel('Tautulli Homepage');
  141. if (!$this->homepageItemPermissions($this->tautulliHomepagePermissions('main'), true)) {
  142. return false;
  143. }
  144. $api = [];
  145. $url = $this->qualifyURL($this->config['tautulliURL']);
  146. $apiURL = $url . '/api/v2?apikey=' . $this->config['tautulliApikey'];
  147. $height = $this->getCacheImageSize('h');
  148. $width = $this->getCacheImageSize('w');
  149. $nowPlayingHeight = $this->getCacheImageSize('nph');
  150. $nowPlayingWidth = $this->getCacheImageSize('npw');
  151. try {
  152. $homestatsUrl = $apiURL . '&cmd=get_home_stats&grouping=1';
  153. $options = $this->requestOptions($this->config['tautulliURL'], $this->config['homepageTautulliRefresh'], $this->config['tautulliDisableCertCheck'], $this->config['tautulliUseCustomCertificate']);
  154. $homestats = Requests::get($homestatsUrl, [], $options);
  155. if ($homestats->success) {
  156. $homepageTautulliViewingStatsExclude = explode(",",$this->config['homepageTautulliViewingStatsExclude']);
  157. $homestats = json_decode($homestats->body, true);
  158. foreach ($homestats['response']['data'] as $s => $stats) {
  159. foreach ($stats['rows'] as $i => $v) {
  160. if (array_key_exists('section_id', $v)) {
  161. if (in_array($v['section_id'],$homepageTautulliViewingStatsExclude)) {
  162. unset($homestats['response']['data'][$s]['rows'][$i]);
  163. }
  164. }
  165. }
  166. }
  167. $homestats['response']['data'] = array_values($homestats['response']['data']);
  168. $api['homestats'] = $homestats['response'];
  169. // Cache art & thumb for first result in each tautulli API result
  170. $categories = ['top_movies', 'top_tv', 'popular_movies', 'popular_tv'];
  171. foreach ($categories as $cat) {
  172. $key = array_search($cat, array_column($api['homestats']['data'], 'stat_id'));
  173. $img = $api['homestats']['data'][$key]['rows'][0];
  174. $this->cacheImage($url . '/pms_image_proxy?img=' . $img['art'] . '&rating_key=' . $img['rating_key'] . '&width=' . $nowPlayingWidth . '&height=' . $nowPlayingHeight, $img['rating_key'] . '-np');
  175. $this->cacheImage($url . '/pms_image_proxy?img=' . $img['thumb'] . '&rating_key=' . $img['rating_key'] . '&width=' . $width . '&height=' . $height, $img['rating_key'] . '-list');
  176. $img['art'] = 'plugins/images/cache/' . $img['rating_key'] . '-np.jpg';
  177. $img['thumb'] = 'plugins/images/cache/' . $img['rating_key'] . '-list.jpg';
  178. $api['homestats']['data'][$key]['rows'][0] = $img;
  179. }
  180. // Cache the platform icon
  181. $key = array_search('top_platforms', array_column($api['homestats']['data'], 'stat_id'));
  182. $platform = $api['homestats']['data'][$key]['rows'][0]['platform_name'];
  183. $this->cacheImage($url . '/images/platforms/' . $platform . '.svg', 'tautulli-' . $platform, 'svg');
  184. }
  185. $libstatsUrl = $apiURL . '&cmd=get_libraries_table';
  186. $options = $this->requestOptions($this->config['tautulliURL'], $this->config['homepageTautulliRefresh'], $this->config['tautulliDisableCertCheck'], $this->config['tautulliUseCustomCertificate']);
  187. $libstats = Requests::get($libstatsUrl, [], $options);
  188. if ($libstats->success) {
  189. $homepageTautulliLibraryStatsExclude = explode(",",$this->config['homepageTautulliLibraryStatsExclude']);
  190. $libstats = json_decode($libstats->body, true);
  191. foreach ($libstats['response']['data']['data'] as $i => $v) {
  192. if (array_key_exists('section_id', $v)) {
  193. if (in_array($v['section_id'],$homepageTautulliLibraryStatsExclude)) {
  194. unset($libstats['response']['data']['data'][$i]);
  195. }
  196. }
  197. }
  198. $libstats['response']['data']['data'] = array_values($libstats['response']['data']['data']);
  199. $api['libstats'] = $libstats['response']['data'];
  200. $categories = ['movie.svg', 'show.svg', 'artist.svg'];
  201. foreach ($categories as $cat) {
  202. $parts = explode('.', $cat);
  203. $this->cacheImage($url . '/images/libraries/' . $cat, 'tautulli-' . $parts[0], $parts[1]);
  204. }
  205. }
  206. $api['options'] = [
  207. 'url' => $url,
  208. 'libraries' => $this->config['tautulliLibraries'],
  209. 'topMovies' => $this->config['tautulliTopMovies'],
  210. 'topTV' => $this->config['tautulliTopTV'],
  211. 'topUsers' => $this->config['tautulliTopUsers'],
  212. 'topPlatforms' => $this->config['tautulliTopPlatforms'],
  213. 'popularMovies' => $this->config['tautulliPopularMovies'],
  214. 'popularTV' => $this->config['tautulliPopularTV'],
  215. 'title' => $this->config['tautulliHeaderToggle'],
  216. 'friendlyName' => $this->config['tautulliFriendlyName'],
  217. ];
  218. $ids = []; // Array of stat_ids to remove from the returned array
  219. if (!$this->qualifyRequest($this->config['homepageTautulliLibraryAuth'])) {
  220. $api['options']['libraries'] = false;
  221. unset($api['libstats']);
  222. }
  223. if (!$this->qualifyRequest($this->config['homepageTautulliViewsAuth'])) {
  224. $api['options']['topMovies'] = false;
  225. $api['options']['topTV'] = false;
  226. $api['options']['popularMovies'] = false;
  227. $api['options']['popularTV'] = false;
  228. $ids = array_merge(['top_movies', 'popular_movies', 'popular_tv', 'top_tv'], $ids);
  229. $api['homestats']['data'] = array_values($api['homestats']['data']);
  230. }
  231. if (!$this->qualifyRequest($this->config['homepageTautulliMiscAuth'])) {
  232. $api['options']['topUsers'] = false;
  233. $api['options']['topPlatforms'] = false;
  234. $ids = array_merge(['top_platforms', 'top_users'], $ids);
  235. $api['homestats']['data'] = array_values($api['homestats']['data']);
  236. }
  237. $ids = array_merge(['top_music', 'popular_music', 'last_watched', 'most_concurrent'], $ids);
  238. foreach ($ids as $id) {
  239. if ($key = array_search($id, array_column($api['homestats']['data'], 'stat_id'))) {
  240. unset($api['homestats']['data'][$key]);
  241. $api['homestats']['data'] = array_values($api['homestats']['data']);
  242. }
  243. }
  244. } catch (Requests_Exception $e) {
  245. $this->logger->critical($e, [$url]);
  246. $this->setAPIResponse('error', $e->getMessage(), 500);
  247. return false;
  248. };
  249. $api = isset($api) ? $api : false;
  250. $this->setAPIResponse('success', null, 200, $api);
  251. return $api;
  252. }
  253. public function tautulliLibraryList()
  254. {
  255. $url = $this->qualifyURL($this->config['tautulliURL']);
  256. $apiURL = $url . '/api/v2?apikey=' . $this->config['tautulliApikey'];
  257. if (!empty($this->config['tautulliApikey']) && !empty($this->config['tautulliURL'])) {
  258. $liblistUrl = $apiURL . '&cmd=get_libraries';
  259. $options = $this->requestOptions($this->config['tautulliURL'], $this->config['homepageTautulliRefresh'], $this->config['tautulliDisableCertCheck'], $this->config['tautulliUseCustomCertificate']);
  260. try {
  261. $liblist = Requests::get($liblistUrl, [], $options);
  262. $libraryList = array();
  263. if ($liblist->success) {
  264. $liblist = json_decode($liblist->body, true);
  265. foreach ($liblist['response']['data'] as $lib) {
  266. $libraryList['libraries'][(string)$lib['section_name']] = (string)$lib["section_id"];
  267. }
  268. $libraryList = array_change_key_case($libraryList, CASE_LOWER);
  269. return $libraryList;
  270. }
  271. } catch (Requests_Exception $e) {
  272. $this->setAPIResponse('error', 'Tautulli Homepage Error - Unable to get list of libraries: '.$e->getMessage(), 500);
  273. $this->writeLog('error', 'Tautulli Homepage Error - Unable to get list of libraries: ' . $e->getMessage(), 'SYSTEM');
  274. return false;
  275. };
  276. }
  277. return false;
  278. }
  279. }