From 3658d7d6c723eff1dbe08a2d8aeed861313081e8 Mon Sep 17 00:00:00 2001 From: DariusIII Date: Fri, 19 Jun 2015 23:47:38 +0200 Subject: [PATCH] Port TraktTv v2 API support from nZEDb --- newznab/build/newznab.xml | 4 +- newznab/controllers/Film.php | 2 +- newznab/controllers/TraktTv.php | 129 ++++++++++++------ newznab/controllers/TvAnger.php | 24 ++-- newznab/utility/Utility.php | 88 ++++++------ resources/db/patches/0160~settings.sql | 9 ++ www/pages/details.php | 2 +- .../nntmux/views/admin/site-edit.tpl | 6 +- 8 files changed, 161 insertions(+), 103 deletions(-) create mode 100644 resources/db/patches/0160~settings.sql diff --git a/newznab/build/newznab.xml b/newznab/build/newznab.xml index 882d95875..8ec564d00 100644 --- a/newznab/build/newznab.xml +++ b/newznab/build/newznab.xml @@ -2,8 +2,8 @@ - 159 - 159 + 160 + 160 0.4.1 diff --git a/newznab/controllers/Film.php b/newznab/controllers/Film.php index ae781a119..2a8c77b70 100644 --- a/newznab/controllers/Film.php +++ b/newznab/controllers/Film.php @@ -1013,7 +1013,7 @@ class Film } // Check on trakt. - $getIMDBid = $trakTv->traktMoviesummary($movieName); + $getIMDBid = $trakTv->movieSummary($movieName); if ($getIMDBid !== false) { $imdbID = $this->doMovieUpdate($getIMDBid, 'Trakt', $arr['id']); if ($imdbID !== false) { diff --git a/newznab/controllers/TraktTv.php b/newznab/controllers/TraktTv.php index 431b844de..5e2b61970 100644 --- a/newznab/controllers/TraktTv.php +++ b/newznab/controllers/TraktTv.php @@ -1,15 +1,27 @@ null, @@ -26,7 +38,12 @@ Class TraktTv $options += $defaults; $settings = ($options['Settings'] instanceof Settings ? $options['Settings'] : new Settings()); - $this->APIKEY = $settings->getSetting('trakttvkey'); + $this->clientID = $settings->getSetting('trakttvclientkey'); + $this->requestHeaders = [ + 'Content-Type: application/json', + 'trakt-api-version: 2', + 'trakt-api-key: ' . $this->clientID + ]; } /** @@ -36,28 +53,27 @@ Class TraktTv * @param string $season * @param string $ep * - * @return bool|mixed + * @see http://docs.trakt.apiary.io/#reference/episodes/summary/get-a-single-episode-for-a-show + * + * @return bool|array * * @access public */ - public function traktTVSEsummary($title = '', $season = '', $ep = '') + public function episodeSummary($title = '', $season = '', $ep = '') { - if (!empty($this->APIKEY)) { - $TVjson = Utility::getUrl([ - 'url' => - 'http://api.trakt.tv/show/episode/summary.json/' . - $this->APIKEY . '/' . - str_replace([' ', '_', '.'], '-', $title) . '/' . - str_replace(['S', 's'], '', $season) . '/' . - str_replace(['E', 'e'], '', $ep) - ] - ); - - if ($TVjson !== false) { - return json_decode($TVjson, true); - } + $array = $this->getJsonArray( + 'https://api-v2launch.trakt.tv/shows/' . + str_replace([' ', '_', '.'], '-', $title) . + '/seasons/' . + str_replace(['S', 's'], '', $season) . + '/episodes/' . + str_replace(['E', 'e'], '', $ep), + 'full' + ); + if (!$array) { + return false; } - return false; + return $array; } /** @@ -65,35 +81,64 @@ Class TraktTv * Accept a title (the-big-lebowski-1998), a IMDB id, or a TMDB id. * * @param string $movie Title or IMDB id. - * @param bool $array Return the full array or just the IMDB id. + * @param string $type imdbID: Return only the IMDB ID (returns string) + * full: Return all extended properties (minus images). (returns array) * - * @return bool|mixed + * @see http://docs.trakt.apiary.io/#reference/movies/summary/get-a-movie + * + * @return bool|array|string * * @access public */ - public function traktMoviesummary($movie = '', $array=false) + public function movieSummary($movie = '', $type = 'imdbID') { - if (!empty($this->APIKEY)) { - $MovieJson = Utility::getUrl([ - 'url' => - 'http://api.trakt.tv/movie/summary.json/' . - $this->APIKEY . - '/' . - str_replace([' ', '_', '.'], '-', str_replace(['(', ')'], '', $movie)) + switch($type) { + case 'full': + $extended = $type; + break; + case 'imdbID': + default: + $extended = 'min'; + } + $array = $this->getJsonArray( + 'https://api-v2launch.trakt.tv/movies/' . str_replace([' ', '_', '.'], '-', str_replace(['(', ')'], '', $movie)), + $extended + ); + if (!$array) { + return false; + } else if ($type === 'imdbID' && isset($array['ids']['imdb'])) { + return $array['ids']['imdb']; + } + return $array; + } + + /** + * Download JSON from Trakt, convert to array. + * + * @param string $URI URI to download. + * @param string $extended Extended info from trakt tv. + * Valid values: + * 'min' Returns enough info to match locally. (Default) + * 'images' Minimal info and all images. + * 'full' Complete info for an item. + * 'full,images' Complete info and all images. + * + * @return bool|mixed + */ + private function getJsonArray($URI, $extended = 'min') + { + if (!empty($this->clientID)) { + $json = Utility::getUrl([ + 'url' => $URI . "?extended=$extended", + 'requestheaders' => $this->requestHeaders ] ); - - if ($MovieJson !== false) { - $MovieJson = json_decode($MovieJson, true); - if (isset($MovieJson['status']) && $MovieJson['status'] === 'failure') { + if ($json !== false) { + $json = json_decode($json, true); + if (!is_array($json) || (isset($json['status']) && $json['status'] === 'failure')) { return false; } - - if ($array) { - return $MovieJson; - } elseif (isset($MovieJson["imdb_id"])) { - return $MovieJson["imdb_id"]; - } + return $json; } } return false; diff --git a/newznab/controllers/TvAnger.php b/newznab/controllers/TvAnger.php index 1857a42c4..73760330d 100644 --- a/newznab/controllers/TvAnger.php +++ b/newznab/controllers/TvAnger.php @@ -627,20 +627,12 @@ class TvAnger if ($epinfo !== false) { $tvairdate = (!empty($epinfo['airdate'])) ? $this->pdo->escapeString($epinfo['airdate']) : "NULL"; $tvtitle = (!empty($epinfo['title'])) ? $this->pdo->escapeString($epinfo['title']) : "NULL"; - $this->pdo->queryExec(sprintf("UPDATE releases SET tvtitle = %s, tvairdate = %s, rageid = %d WHERE id = %d", $this->pdo->escapeString(trim($tvtitle)), $tvairdate, $traktArray['show']['tvrage_id'], $relid)); + $this->pdo->queryExec(sprintf("UPDATE releases SET tvtitle = %s, tvairdate = %s, rageid = %d WHERE id = %d", $this->pdo->escapeString(trim($tvtitle)), $tvairdate, $traktArray['ids']['tvrage'], $relid)); } else { - $this->pdo->queryExec(sprintf("UPDATE releases SET rageid = %d WHERE id = %d", $traktArray['show']['tvrage_id'], $relid)); + $this->pdo->queryExec(sprintf("UPDATE releases SET rageid = %d WHERE id = %d", $traktArray['ids']['tvrage'], $relid)); } - $genre = ''; - if (isset($traktArray['show']['genres']) && is_array($traktArray['show']['genres']) && !empty($traktArray['show']['genres'])) { - $genre = $traktArray['show']['genres']['0']; - } - - $country = ''; - if (isset($traktArray['show']['country']) && !empty($traktArray['show']['country'])) { - $country = $this->countryCode($traktArray['show']['country']); - } + $genre = $country = ''; $rInfo = $this->getRageInfoFromPage($rageid); $desc = ''; @@ -683,7 +675,7 @@ class TvAnger %s %s %s ORDER BY r.postdate DESC LIMIT %d", - ($groupID === '' ? '' : 'AND r.group_id = ' . $groupID), + ($groupID === '' ? '' : 'AND r.groupid = ' . $groupID), ($guidChar === '' ? '' : 'AND r.guid ' . $this->pdo->likeString($guidChar, false, true)), ($lookupTvRage == 2 ? 'AND r.isrenamed = 1' : ''), $this->rageqty @@ -721,13 +713,13 @@ class TvAnger $this->updateRageInfo($tvrShow['showid'], $show, $tvrShow, $arr['id']); } else if ($tvrShow === false) { // If tvrage fails, try trakt. - $traktArray = $trakt->traktTVSEsummary($show['name'], $show['season'], $show['episode']); + $traktArray = $trakt->episodeSummary($show['name'], $show['season'], $show['episode']); if ($traktArray !== false) { - if (isset($traktArray['show']['tvrage_id']) && $traktArray['show']['tvrage_id'] !== 0) { + if (isset($traktArray['ids']['tvrage']) && $traktArray['ids']['tvrage'] !== 0) { if ($this->echooutput) { - echo $this->pdo->log->primary('Found TVRage ID on trakt:' . $traktArray['show']['tvrage_id']); + echo $this->pdo->log->primary('Found TVRage ID on trakt:' . $traktArray['ids']['tvrage']); } - $this->updateRageInfoTrakt($traktArray['show']['tvrage_id'], $show, $traktArray, $arr['id']); + $this->updateRageInfoTrakt($traktArray['ids']['tvrage'], $show, $traktArray, $arr['id']); } // No match, add to tvrage with rageID = -2 and $show['cleanname'] title only. else { diff --git a/newznab/utility/Utility.php b/newznab/utility/Utility.php index d53a94866..2c0f605a3 100644 --- a/newznab/utility/Utility.php +++ b/newznab/utility/Utility.php @@ -334,18 +334,26 @@ class Utility * @static * @access public */ - static public function streamSslContextOptions($forceIgnore = false) + public static function streamSslContextOptions($forceIgnore = false) { - $options = [ - 'verify_peer' => ($forceIgnore ? false : (bool)NN_SSL_VERIFY_PEER), - 'verify_peer_name' => ($forceIgnore ? false : (bool)NN_SSL_VERIFY_HOST), - 'allow_self_signed' => ($forceIgnore ? true : (bool)NN_SSL_ALLOW_SELF_SIGNED), - ]; - if (NN_SSL_CAFILE) { - $options['cafile'] = NN_SSL_CAFILE; - } - if (NN_SSL_CAPATH) { - $options['capath'] = NN_SSL_CAPATH; + if (empty(NN_SSL_CAFILE) && empty(NN_SSL_CAPATH)) { + $options = [ + 'verify_peer' => false, + 'verify_peer_name' => false, + 'allow_self_signed' => true, + ]; + } else { + $options = [ + 'verify_peer' => ($forceIgnore ? false : (bool)NN_SSL_VERIFY_PEER), + 'verify_peer_name' => ($forceIgnore ? false : (bool)NN_SSL_VERIFY_HOST), + 'allow_self_signed' => ($forceIgnore ? true : (bool)NN_SSL_ALLOW_SELF_SIGNED), + ]; + if (!empty(NN_SSL_CAFILE)) { + $options['cafile'] = NN_SSL_CAFILE; + } + if (!empty(NN_SSL_CAPATH)) { + $options['capath'] = NN_SSL_CAPATH; + } } // If we set the transport to tls and the server falls back to ssl, // the context options would be for tls and would not apply to ssl, @@ -364,16 +372,20 @@ class Utility * @static * @access public */ - static public function curlSslContextOptions($verify = true) + public static function curlSslContextOptions($verify = true) { $options = []; - if ($verify && NN_SSL_VERIFY_HOST) { + if ($verify && NN_SSL_VERIFY_HOST && (!empty(NN_SSL_CAFILE) || !empty(NN_SSL_CAPATH))) { $options += [ - CURLOPT_CAINFO => NN_SSL_CAFILE, - CURLOPT_CAPATH => NN_SSL_CAPATH, CURLOPT_SSL_VERIFYPEER => (bool)NN_SSL_VERIFY_PEER, CURLOPT_SSL_VERIFYHOST => (NN_SSL_VERIFY_HOST ? 2 : 0), ]; + if (!empty(NN_SSL_CAFILE)) { + $options += [CURLOPT_CAINFO => NN_SSL_CAFILE]; + } + if (!empty(NN_SSL_CAPATH)) { + $options += [CURLOPT_CAPATH => NN_SSL_CAPATH]; + } } else { $options += [ CURLOPT_SSL_VERIFYPEER => false, @@ -396,17 +408,18 @@ class Utility public static function getUrl(array $options = []) { $defaults = [ - 'url' => '', // The URL to download. - 'method' => 'get', // Http method, get/post/etc.. - 'postdata' => '', // Data to send on post method. - 'enctype' => '', // Encoding type - 'language' => '', // Language in header string. - 'debug' => false, // Show curl debug information. - 'useragent' => '', // User agent string. - 'cookie' => '', // Cookie string. - 'verifycert' => true, /* Verify certificate authenticity? - Since curl does not have a verify self signed certs option, - you should use this instead if your cert is self signed. */ + 'url' => '', // String ; The URL to download. + 'method' => 'get', // String ; Http method, get/post/etc.. + 'postdata' => '', // String ; Data to send on post method. + 'language' => '', // String ; Language in request header string. + 'debug' => false, // Bool ; Show curl debug information. + 'useragent' => '', // String ; User agent string. + 'cookie' => '', // String ; Cookie string. + 'requestheaders' => [], // Array ; List of request headers. + // Example: ["Content-Type: application/json", "DNT: 1"] + 'verifycert' => true, // Bool ; Verify certificate authenticity? + // Since curl does not have a verify self signed certs option, + // you should use this instead if your cert is self signed. ]; $options += $defaults; @@ -418,25 +431,27 @@ class Utility switch ($options['language']) { case 'fr': case 'fr-fr': - $language = "fr-fr"; + $options['language'] = "fr-fr"; break; case 'de': case 'de-de': - $language = "de-de"; + $options['language'] = "de-de"; break; case 'en-us': - $language = "en-us"; + $options['language'] = "en-us"; break; case 'en-gb': - $language = "en-gb"; + $options['language'] = "en-gb"; break; case '': case 'en': default: - $language = 'en'; + $options['language'] = 'en'; + } + $header[] = "Accept-Language: " . $options['language']; + if (is_array($options['requestheaders'])) { + $header += $options['requestheaders']; } - $header = array(); - $header[] = "Accept-Language: " . $language; $ch = curl_init(); @@ -448,10 +463,10 @@ class Utility CURLOPT_TIMEOUT => 15 ]; $context += self::curlSslContextOptions($options['verifycert']); - if ($options['useragent'] !== '') { + if (!empty($options['useragent'])) { $context += [CURLOPT_USERAGENT => $options['useragent']]; } - if ($options['cookie'] !== '') { + if (!empty($options['cookie'])) { $context += [CURLOPT_COOKIE => $options['cookie']]; } if ($options['method'] === 'post') { @@ -460,9 +475,6 @@ class Utility CURLOPT_POSTFIELDS => $options['postdata'] ]; } - if ($options['enctype'] !== '') { - $context += [CURLOPT_ENCODING => $options['enctype']]; - } if ($options['debug']) { $context += [ CURLOPT_HEADER => true, diff --git a/resources/db/patches/0160~settings.sql b/resources/db/patches/0160~settings.sql new file mode 100644 index 000000000..7cdc7da43 --- /dev/null +++ b/resources/db/patches/0160~settings.sql @@ -0,0 +1,9 @@ +INSERT IGNORE INTO settings (section, subsection, name, value, hint, setting) +VALUES ( + 'APIs', + '', + 'trakttvclientkey', + '', + 'The Trakt.tv API v2 Client ID (SHA256 hash - 64 characters long string). Used for movie and tv lookups.', + 'trakttvclientkey' +); \ No newline at end of file diff --git a/www/pages/details.php b/www/pages/details.php index 9bc0b1d36..30fc98511 100644 --- a/www/pages/details.php +++ b/www/pages/details.php @@ -72,7 +72,7 @@ if (isset($_GET["id"])) $mov = $movie->getMovieInfo($data['imdbid']); $trakt = new TraktTv(); - $traktSummary = $trakt->traktMoviesummary('tt' . $data['imdbid'], true); + $traktSummary = $trakt->movieSummary('tt' . $data['imdbid'], 'full'); if ($traktSummary !== false && isset($traktSummary['trailer']) && $traktSummary['trailer'] !== '' && diff --git a/www/templates/nntmux/views/admin/site-edit.tpl b/www/templates/nntmux/views/admin/site-edit.tpl index dd5fdb46c..3aa76205a 100644 --- a/www/templates/nntmux/views/admin/site-edit.tpl +++ b/www/templates/nntmux/views/admin/site-edit.tpl @@ -240,10 +240,10 @@ - + - -
The trakt.tv api key. Used for movie and tv lookups.
+ +
The Trakt.tv API v2 Client ID (SHA256 hash - 64 characters long string). Used for movie and tv lookups.