ombi.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. <?php
  2. trait OmbiHomepageItem
  3. {
  4. public function ombiSettingsArray($infoOnly = false)
  5. {
  6. $homepageInformation = [
  7. 'name' => 'Ombi',
  8. 'enabled' => strpos('personal', $this->config['license']) !== false,
  9. 'image' => 'plugins/images/tabs/ombi.png',
  10. 'category' => 'Requests',
  11. 'settingsArray' => __FUNCTION__
  12. ];
  13. if ($infoOnly) {
  14. return $homepageInformation;
  15. }
  16. $homepageSettings = [
  17. 'debug' => true,
  18. 'settings' => [
  19. 'Enable' => [
  20. $this->settingsOption('enable', 'homepageOmbiEnabled'),
  21. $this->settingsOption('auth', 'homepageOmbiAuth'),
  22. ],
  23. 'Connection' => [
  24. $this->settingsOption('url', 'ombiURL'),
  25. $this->settingsOption('token', 'ombiToken'),
  26. $this->settingsOption('username', 'ombiFallbackUser', ['label' => 'Ombi Fallback User', 'help' => 'Organizr will request an Ombi User Token based off of this user credentials']),
  27. $this->settingsOption('password', 'ombiFallbackPassword', ['label' => 'Ombi Fallback Password',]),
  28. $this->settingsOption('disable-cert-check', 'ombiDisableCertCheck'),
  29. $this->settingsOption('use-custom-certificate', 'ombiUseCustomCertificate'),
  30. ],
  31. 'Misc Options' => [
  32. $this->settingsOption('auth', 'homepageOmbiRequestAuth', ['label' => 'Minimum Group to Request']),
  33. $this->settingsOption('select', 'ombiTvDefault', ['label' => 'TV Show Default Request', 'options' => $this->requestTvOptions()]),
  34. $this->settingsOption('switch', 'ombiLimitUser', ['label' => 'Limit to User']),
  35. $this->settingsOption('limit', 'ombiLimit'),
  36. $this->settingsOption('refresh', 'ombiRefresh'),
  37. $this->settingsOption('switch', 'ombiAlias', ['label' => 'Use Ombi Alias Names', 'help' => 'Use Ombi Alias Names instead of Usernames - If Alias is blank, Alias will fallback to Username']),
  38. ],
  39. 'Default Filter' => [
  40. $this->settingsOption('switch', 'ombiDefaultFilterAvailable', ['label' => 'Show Available', 'help' => 'Show All Available Ombi Requests']),
  41. $this->settingsOption('switch', 'ombiDefaultFilterUnavailable', ['label' => 'Show Unavailable', 'help' => 'Show All Unavailable Ombi Requests']),
  42. $this->settingsOption('switch', 'ombiDefaultFilterApproved', ['label' => 'Show Approved', 'help' => 'Show All Approved Ombi Requests']),
  43. $this->settingsOption('switch', 'ombiDefaultFilterUnapproved', ['label' => 'Show Unapproved', 'help' => 'Show All Unapproved Ombi Requests']),
  44. $this->settingsOption('switch', 'ombiDefaultFilterDenied', ['label' => 'Show Denied', 'help' => 'Show All Denied Ombi Requests']),
  45. ],
  46. 'Test Connection' => [
  47. $this->settingsOption('blank', null, ['label' => 'Please Save before Testing']),
  48. $this->settingsOption('test', 'ombi'),
  49. ]
  50. ]
  51. ];
  52. return array_merge($homepageInformation, $homepageSettings);
  53. }
  54. public function testConnectionOmbi()
  55. {
  56. if (empty($this->config['ombiURL'])) {
  57. $this->setAPIResponse('error', 'Ombi URL is not defined', 422);
  58. return false;
  59. }
  60. if (empty($this->config['ombiToken'])) {
  61. $this->setAPIResponse('error', 'Ombi Token is not defined', 422);
  62. return false;
  63. }
  64. $headers = array(
  65. "Accept" => "application/json",
  66. "Apikey" => $this->config['ombiToken'],
  67. );
  68. $url = $this->qualifyURL($this->config['ombiURL']);
  69. try {
  70. $options = $this->requestOptions($url, null, $this->config['ombiDisableCertCheck'], $this->config['ombiUseCustomCertificate']);
  71. $test = Requests::get($url . "/api/v1/Settings/about", $headers, $options);
  72. if ($test->success) {
  73. $this->setAPIResponse('success', 'API Connection succeeded', 200);
  74. return true;
  75. } else {
  76. $this->setResponse(401, $test->body);
  77. return false;
  78. }
  79. } catch (Requests_Exception $e) {
  80. $this->setLoggerChannel('Ombi')->error($e);
  81. $this->setResponse(500, $e->getMessage());
  82. return false;
  83. }
  84. }
  85. public function ombiHomepagePermissions($key = null)
  86. {
  87. $permissions = [
  88. 'main' => [
  89. 'enabled' => [
  90. 'homepageOmbiEnabled'
  91. ],
  92. 'auth' => [
  93. 'homepageOmbiAuth'
  94. ],
  95. 'not_empty' => [
  96. 'ombiURL',
  97. 'ombiToken'
  98. ]
  99. ]
  100. ];
  101. return $this->homepageCheckKeyPermissions($key, $permissions);
  102. }
  103. public function homepageOrderombi()
  104. {
  105. if ($this->homepageItemPermissions($this->ombiHomepagePermissions('main'))) {
  106. return '
  107. <div id="' . __FUNCTION__ . '">
  108. <div class="white-box homepage-loading-box"><h2 class="text-center" lang="en">Loading Requests...</h2></div>
  109. <script>
  110. // Ombi Requests
  111. homepageRequests("ombi", "' . $this->config['ombiRefresh'] . '");
  112. // End Ombi Requests
  113. </script>
  114. </div>
  115. ';
  116. }
  117. }
  118. public function getOmbiRequests($type = "both", $limit = 50, $offset = 0)
  119. {
  120. if (!$this->homepageItemPermissions($this->ombiHomepagePermissions('main'), true)) {
  121. return false;
  122. }
  123. $api['count'] = array(
  124. 'movie' => 0,
  125. 'tv' => 0,
  126. 'limit' => (integer)$limit,
  127. 'offset' => (integer)$offset
  128. );
  129. $headers = array(
  130. "Accept" => "application/json",
  131. "Apikey" => $this->config['ombiToken'],
  132. );
  133. $requests = array();
  134. $url = $this->qualifyURL($this->config['ombiURL']);
  135. try {
  136. $options = $this->requestOptions($url, $this->config['ombiRefresh'], $this->config['ombiDisableCertCheck'], $this->config['ombiUseCustomCertificate']);
  137. switch ($type) {
  138. case 'movie':
  139. $movie = Requests::get($url . "/api/v1/Request/movie", $headers, $options);
  140. break;
  141. case 'tv':
  142. $tv = Requests::get($url . "/api/v1/Request/tv", $headers, $options);
  143. break;
  144. default:
  145. $movie = Requests::get($url . "/api/v1/Request/movie", $headers, $options);
  146. $tv = Requests::get($url . "/api/v1/Request/tv", $headers, $options);
  147. break;
  148. }
  149. if ($movie->success || $tv->success) {
  150. if (isset($movie)) {
  151. $movie = json_decode($movie->body, true);
  152. //$movie = array_reverse($movie);
  153. foreach ($movie as $key => $value) {
  154. $proceed = (($this->config['ombiLimitUser']) && strtolower($this->user['username']) == strtolower($value['requestedUser']['userName'])) || (strtolower($value['requestedUser']['userName']) == strtolower($this->config['ombiFallbackUser'])) || (!$this->config['ombiLimitUser']) || $this->qualifyRequest(1);
  155. if ($proceed) {
  156. $api['count']['movie']++;
  157. $requests[] = array(
  158. 'id' => $value['theMovieDbId'],
  159. 'title' => $value['title'],
  160. 'overview' => $value['overview'],
  161. 'poster' => (isset($value['posterPath']) && $value['posterPath'] !== '') ? 'https://image.tmdb.org/t/p/w300/' . $value['posterPath'] : 'plugins/images/homepage/no-list.png',
  162. 'background' => (isset($value['background']) && $value['background'] !== '') ? 'https://image.tmdb.org/t/p/w1280/' . $value['background'] : '',
  163. 'approved' => $value['approved'],
  164. 'available' => $value['available'],
  165. 'denied' => $value['denied'],
  166. 'deniedReason' => $value['deniedReason'],
  167. 'user' => $value['requestedUser']['userName'],
  168. 'userAlias' => $value['requestedUser']['userAlias'],
  169. 'request_id' => $value['id'],
  170. 'request_date' => $value['requestedDate'],
  171. 'release_date' => $value['releaseDate'],
  172. 'type' => 'movie',
  173. 'icon' => 'mdi mdi-filmstrip',
  174. 'color' => 'palette-Deep-Purple-900 bg white',
  175. );
  176. }
  177. }
  178. }
  179. if (isset($tv) && (is_array($tv) || is_object($tv))) {
  180. $tv = json_decode($tv->body, true);
  181. foreach ($tv as $key => $value) {
  182. if (count($value['childRequests']) > 0) {
  183. $proceed = (($this->config['ombiLimitUser']) && strtolower($this->user['username']) == strtolower($value['childRequests'][0]['requestedUser']['userName'])) || (!$this->config['ombiLimitUser']) || $this->qualifyRequest(1);
  184. if ($proceed) {
  185. $api['count']['tv']++;
  186. $requests[] = array(
  187. 'id' => $value['tvDbId'],
  188. 'title' => $value['title'],
  189. 'overview' => $value['overview'],
  190. 'poster' => (isset($value['posterPath']) && $value['posterPath'] !== '') ? (str_starts_with($value['posterPath'], '/') ? 'https://image.tmdb.org/t/p/w300/' . $value['posterPath'] : $value['posterPath']) : 'plugins/images/homepage/no-list.png',
  191. 'background' => (isset($value['background']) && $value['background'] !== '') ? 'https://image.tmdb.org/t/p/w1280/' . $value['background'] : '',
  192. 'approved' => $value['childRequests'][0]['approved'],
  193. 'available' => $value['childRequests'][0]['available'],
  194. 'denied' => $value['childRequests'][0]['denied'],
  195. 'deniedReason' => $value['childRequests'][0]['deniedReason'],
  196. 'user' => $value['childRequests'][0]['requestedUser']['userName'],
  197. 'userAlias' => $value['childRequests'][0]['requestedUser']['userAlias'],
  198. 'request_id' => $value['id'],
  199. 'request_date' => $value['childRequests'][0]['requestedDate'],
  200. 'release_date' => $value['releaseDate'],
  201. 'type' => 'tv',
  202. 'icon' => 'mdi mdi-television',
  203. 'color' => 'grayish-blue-bg',
  204. );
  205. }
  206. }
  207. }
  208. }
  209. //sort here
  210. usort($requests, function ($item1, $item2) {
  211. if ($item1['request_date'] == $item2['request_date']) {
  212. return 0;
  213. }
  214. return $item1['request_date'] > $item2['request_date'] ? -1 : 1;
  215. });
  216. }
  217. } catch (Requests_Exception $e) {
  218. $this->setLoggerChannel('Ombi')->error($e);
  219. $this->setResponse(500, $e->getMessage());
  220. return false;
  221. };
  222. $api['content'] = isset($requests) ? array_slice($requests, $offset, $limit) : false;
  223. $this->setAPIResponse('success', null, 200, $api);
  224. return $api;
  225. }
  226. public function addOmbiRequest($id, $type)
  227. {
  228. $id = ($id) ?? null;
  229. $type = ($type) ?? null;
  230. if (!$id) {
  231. $this->setAPIResponse('error', 'Id was not supplied', 422);
  232. return false;
  233. }
  234. if (!$type) {
  235. $this->setAPIResponse('error', 'Type was not supplied', 422);
  236. return false;
  237. }
  238. if (!$this->homepageItemPermissions($this->ombiHomepagePermissions('main'), true)) {
  239. return false;
  240. }
  241. $url = $this->qualifyURL($this->config['ombiURL']);
  242. switch ($type) {
  243. case 'season':
  244. case 'tv':
  245. $type = 'tv';
  246. $add = array(
  247. 'tvDbId' => $id,
  248. 'requestAll' => $this->ombiTVDefault('all'),
  249. 'latestSeason' => $this->ombiTVDefault('last'),
  250. 'firstSeason' => $this->ombiTVDefault('first')
  251. );
  252. break;
  253. default:
  254. $type = 'movie';
  255. $add = array("theMovieDbId" => (int)$id);
  256. break;
  257. }
  258. try {
  259. $options = array('timeout' => 30);
  260. if (isset($_COOKIE['Auth'])) {
  261. $headers = array(
  262. "Accept" => "application/json",
  263. "Content-Type" => "application/json",
  264. "Authorization" => "Bearer " . $_COOKIE['Auth']
  265. );
  266. } else {
  267. $this->setAPIResponse('error', 'User does not have Auth Cookie', 500);
  268. return false;
  269. }
  270. //https://api.themoviedb.org/3/movie/157336?api_key=83cf4ee97bb728eeaf9d4a54e64356a1
  271. // Lets check if it exists inside Ombi first... but since I can't search with ID - i have to query title from id
  272. $tmdbResponse = Requests::get('https://api.themoviedb.org/3/' . $type . '/' . $id . '?api_key=83cf4ee97bb728eeaf9d4a54e64356a1', [], $options);
  273. if ($tmdbResponse->success) {
  274. $details = json_decode($tmdbResponse->body, true);
  275. if (count($details) > 0) {
  276. switch ($type) {
  277. case 'tv':
  278. $title = $details['name'];
  279. $idType = 'theTvDbId';
  280. $tmdbResponseID = Requests::get('https://api.themoviedb.org/3/tv/' . $id . '/external_ids?api_key=83cf4ee97bb728eeaf9d4a54e64356a1', [], $options);
  281. if ($tmdbResponseID->success) {
  282. $detailsID = json_decode($tmdbResponseID->body, true);
  283. if (count($detailsID) > 0) {
  284. if (isset($detailsID['tvdb_id'])) {
  285. $id = $detailsID['tvdb_id'];
  286. $add['tvDbId'] = $id;
  287. } else {
  288. $this->setAPIResponse('error', 'Could not get TVDB Id', 422);
  289. return false;
  290. }
  291. } else {
  292. $this->setAPIResponse('error', 'Could not get TVDB Id', 422);
  293. return false;
  294. }
  295. }
  296. break;
  297. case 'movie':
  298. $title = $details['title'];
  299. $idType = 'theMovieDbId';
  300. break;
  301. default:
  302. $this->setAPIResponse('error', 'Ombi Type was not found', 422);
  303. return false;
  304. }
  305. } else {
  306. $this->setAPIResponse('error', 'No data returned from TMDB', 422);
  307. return false;
  308. }
  309. } else {
  310. $this->setAPIResponse('error', 'Could not contact TMDB', 422);
  311. return false;
  312. }
  313. $options = $this->requestOptions($url, null, $this->config['ombiDisableCertCheck'], $this->config['ombiUseCustomCertificate']);
  314. $searchResponse = Requests::get($url . '/api/v1/Search/' . $type . '/' . urlencode($title), $headers, $options);
  315. if ($searchResponse->success) {
  316. $details = json_decode($searchResponse->body, true);
  317. if (count($details) > 0) {
  318. foreach ($details as $k => $v) {
  319. if ($v[$idType] == $id) {
  320. if ($v['available']) {
  321. $this->setAPIResponse('error', 'Request is already available', 409);
  322. return false;
  323. } elseif ($v['requested']) {
  324. $this->setAPIResponse('error', 'Request is already requested', 409);
  325. return false;
  326. }
  327. }
  328. }
  329. }
  330. } else {
  331. $this->setAPIResponse('error', 'Ombi Error Occurred', 500);
  332. return false;
  333. }
  334. $response = Requests::post($url . "/api/v1/Request/" . $type, $headers, json_encode($add), $options);
  335. if ($response->success) {
  336. $this->setAPIResponse('success', 'Ombi Request submitted', 200);
  337. return true;
  338. } else {
  339. $this->setAPIResponse('error', 'Ombi Error Occurred', 500);
  340. return false;
  341. }
  342. } catch (Requests_Exception $e) {
  343. $this->setLoggerChannel('Ombi')->error($e);
  344. $this->setResponse(500, $e->getMessage());
  345. return false;
  346. }
  347. }
  348. public function actionOmbiRequest($id, $type, $action)
  349. {
  350. $id = ($id) ?? null;
  351. $type = ($type) ?? null;
  352. $action = ($action) ?? null;
  353. if (!$id) {
  354. $this->setAPIResponse('error', 'Id was not supplied', 422);
  355. return false;
  356. }
  357. if (!$type) {
  358. $this->setAPIResponse('error', 'Type was not supplied', 422);
  359. return false;
  360. }
  361. if (!$action) {
  362. $this->setAPIResponse('error', 'Action was not supplied', 422);
  363. return false;
  364. }
  365. if (!$this->homepageItemPermissions($this->ombiHomepagePermissions('main'), true)) {
  366. return false;
  367. }
  368. $url = $this->qualifyURL($this->config['ombiURL']);
  369. $headers = array(
  370. "Accept" => "application/json",
  371. "Content-Type" => "application/json",
  372. "Apikey" => $this->config['ombiToken']
  373. );
  374. $data = array(
  375. 'id' => $id,
  376. );
  377. switch ($type) {
  378. case 'season':
  379. case 'tv':
  380. $type = 'tv';
  381. break;
  382. default:
  383. $type = 'movie';
  384. break;
  385. }
  386. try {
  387. $options = $this->requestOptions($url, 60, $this->config['ombiDisableCertCheck'], $this->config['ombiUseCustomCertificate']);
  388. switch ($action) {
  389. case 'approve':
  390. $response = Requests::post($url . "/api/v1/Request/" . $type . "/approve", $headers, json_encode($data), $options);
  391. $message = 'Ombi Request has been approved';
  392. break;
  393. case 'available':
  394. $response = Requests::post($url . "/api/v1/Request/" . $type . "/available", $headers, json_encode($data), $options);
  395. $message = 'Ombi Request has been marked available';
  396. break;
  397. case 'unavailable':
  398. $response = Requests::post($url . "/api/v1/Request/" . $type . "/unavailable", $headers, json_encode($data), $options);
  399. $message = 'Ombi Request has been marked unavailable';
  400. break;
  401. case 'deny':
  402. $response = Requests::put($url . "/api/v1/Request/" . $type . "/deny", $headers, json_encode($data), $options);
  403. $message = 'Ombi Request has been denied';
  404. break;
  405. case 'delete':
  406. $response = Requests::delete($url . "/api/v1/Request/" . $type . "/" . $id, $headers, $options);
  407. $message = 'Ombi Request has been deleted';
  408. break;
  409. default:
  410. return false;
  411. }
  412. if ($response->success) {
  413. $this->setAPIResponse('success', $message, 200);
  414. return true;
  415. } else {
  416. $this->setAPIResponse('error', 'Ombi Error Occurred', 500);
  417. return false;
  418. }
  419. } catch (Requests_Exception $e) {
  420. $this->setLoggerChannel('Ombi')->error($e);
  421. $this->setResponse(500, $e->getMessage());
  422. return false;
  423. }
  424. }
  425. public function ombiTVDefault($type)
  426. {
  427. return $type == $this->config['ombiTvDefault'];
  428. }
  429. }