From ccc2d5195806d047b759adaa24f8530ffcb54820 Mon Sep 17 00:00:00 2001 From: DariusIII Date: Sun, 25 Oct 2015 00:59:26 +0200 Subject: [PATCH] Add changes from nZEDb/dev-tv branch --- Changelog | 2 + docs/newznab_api_specification.txt | 778 ++++++++++++++++++ newznab/Capabilities.php | 11 +- newznab/Releases.php | 71 +- newznab/Videos.php | 37 +- newznab/processing/Videos.php | 4 + newznab/processing/tv/TV.php | 393 +++++---- newznab/processing/tv/TVDB.php | 132 +-- newznab/processing/tv/TvRage.php | 344 +++++--- www/admin/show-delete.php | 5 +- www/admin/show-edit.php | 4 +- www/pages/api.php | 317 ++----- www/pages/series.php | 19 +- www/pages/smartyTV.php | 68 ++ .../charisma/templates/frontend/apicaps.tpl | 35 +- .../charisma/templates/frontend/apidetail.tpl | 151 ++-- .../charisma/templates/frontend/apiresult.tpl | 81 +- .../omicron/templates/frontend/apicaps.tpl | 35 +- .../omicron/templates/frontend/apidetail.tpl | 149 ++-- .../omicron/templates/frontend/apiresult.tpl | 81 +- 20 files changed, 1721 insertions(+), 996 deletions(-) create mode 100755 docs/newznab_api_specification.txt create mode 100644 www/pages/smartyTV.php diff --git a/Changelog b/Changelog index 76ae7c083..f840ada3a 100755 --- a/Changelog +++ b/Changelog @@ -1,3 +1,5 @@ +2015-10-24 DariusIII + Upd: Add latest changes from nZEDb/dev-tv branch 2015-10-23 DariusIII Upd: Update api, Releases, anime etc Chg: Add missing genres and groups output to api diff --git a/docs/newznab_api_specification.txt b/docs/newznab_api_specification.txt new file mode 100755 index 000000000..c159e2bd1 --- /dev/null +++ b/docs/newznab_api_specification.txt @@ -0,0 +1,778 @@ + newznab Usenet Searching Web API + + v0.4 + 2015-05-23 + +Authors: +ensi ensisoft@gmail.com +newznab http://newznab.com/ +nZEDb https://github.com/nZEDb/nZEDb + +1. Introduction +2. Functions +2.1 CAPS +2.2 REGISTER +2.3 SEARCH +2.4 TV-SEARCH +2.5 MOVIE-SEARCH +2.6 DETAILS +3. Predefined Categories +4. Predefined Attributes +4.1 List of Attributes +4.2 Attribute example +5. nZEDb Error Codes +5.1 Error code example +6 Changelog + +1. Introduction + + This document describes the newznab/nZEDb Usenet Searching Web API. The API is designed to be implemented + by Usenet indexing sites, i.e. sites that index Usenet newsgroups through some means, typically + by downloading and inspecting the NNTP headers. The API is aimed for NZB aware client applications + to allow them to perform Usenet searches against nZEDb servers and receive NZB information in order + to facilitate direct downloading from Usenet without having to download any NNTP headers. + + This document does not describe the actual implementation of either the client or the server but just + describes the HTTP(S) interface and request/response sequences. + + Intended readers are server and client implementers. + +1.1 Notation + + This document uses the following notations: + + Parameters: "t=c" denotes a required HTTP query parameter. [o=json | o=xml] denotes optional + parameters with possible values. + + +2. Functions + + All functions are executed as HTTP(S) requests over TCP. All parameters are to be passed + as query parameters unless otherwise indicated. All returned XML/JSON data is UTF-8 encoded + unless otherwise specified. All query parameters should be UTF-8 and URL encoded, i.e. + query-param = URL-ENCODE(UTF8-ENCODE(param=value)). + + The functions are divided into two categories. Functions specific to searching and retrieving of items + and the their information such as SEARCH and TV-SEARCH and functions that are for site/user account + management such as CAPS and REGISTER. + + Any conforming implementation should support the CAPS and SEARCH functions. Other functions are optional + and if not supported will return the "203 Function Not Available" when invoked. + + + 2.1 CAPS + + Description: + CAPS function is used to query the server for supported features and the protocol version and other + meta data relevant to the implementation. This function does not require the client to provide any + login information but can be executed out of "login session". + + Important fields of the returned data: + server/version The version of the protocol implemented by the server. All implementations should be backwards compatible. + limits The limit and defaults to the number of search results returned. + retention Server retention (how many days NZB information is stored before being purged). + category Defines a searchable category which might have any number of subcategories. + category/id Unique category ID, can be either one of the standard category IDs or a site specific ID. + category/name Any descriptive name for the category. Can be site/language specific. + category/description A description of the contents of the category. + category/subcat A subcategory. + category/subcat/id/ Unique category ID, can be either one of the standard category IDs or a site specific ID. + category/subcat/name Any descriptive name for the category. Can be site/language specific. + category/subcat/description A description of the contents of the category. + + HTTP Method: + GET + + HTTP Response: + 200 OK + + Parameters: + t=caps Caps function, must always be "caps". + + Optional parameters: + o=xxx Output format, either "JSON" or "XML. Default is "XML". + + Examples: + --> GET http://servername.com/api?t=caps + <-- 200 OK + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2.2 REGISTER + + Description: + + REGISTER function is used for automatically creating and registering user account. + This is an optional function and may or may not be available at a site. It is also possible + that function is available but currently registrations at the site are closed. + + The only prerequisite for registering an account is a valid email address and any server policies. + It is at the server administration discretion to allow or deny registrations based on + for example the validity of the email address or the the current client host address. + + On successful registration a valid username, password and api key are returned to the caller + On error an appropriate error code is returned. + + HTTP Method: + GET + + HTTP Response: + 200 OK + + Parameters: + t=register Register function, must always be "register" + email=xxx A valid email address to be used for registration. (URL/UTF-8 encoded). + + Examples: + --> GET HTTP://servername.com/api?t=register&email=john.joe%40acme.com + <-- 200 OK + + + + + --> GET HTTP://servername.com/api?t=register&email=john.joe%40acme.com + <-- 200 OK + + + + --> GET HTTP://servername.com/api?t=register&email=john.joe%40acme.com + <-- 200 OK + + + + --> GET HTTP://servername.com/api?t=register&email=john.joe%40acme.com + <-- 200 OK + + + + + 2.3 SEARCH + + Description: + SEARCH function searches the index for items matching the search criteria. On successful + search the response contains a list of found items. Even if search matched nothing an empty + response set is created and returned. This function requires passing the user credentials. + + Searches that include categories that are not supported by the server are still executed + but the non-supported categories are simply skipped. This basically treats such a search + simply as a "no match" but allows the same query to be ran simultaneously against several + servers. + + The list of search categories specifies a logical OR condition. I.e. an item matching the + search input in any of the specified categories is considered a match and is returned. E.g. + a search searching for "linux" in "computer" and "ebook" categories searches for matching + items in "computer" and "ebook" but does not search for example the "movies" category. + Items found in either group are then combined into a single result set. If the input string + for search is empty all items (within the server/query limits) are returned for the + matching categories. + + When performing the query the categories to be searched are concatenated into a single + query parameter by , (comma). For example "cat=200,300,400", which is then URL encoded. + + The returned XML data stream is RSS 2.0 compliant and also contains additional information + in the extra namespace. + + Response-offset field identifies the current subset of all the matches that are being + transmitted in the response. In other words, if a search for "disco" finds more matches + than the server is capable of transmitting in a single response, the response needs to be + split into several responses. Then it is the clients responsibility to repeat the same + query with same parameters but specify an increased offset in order to return the next + set of results. + + If offset query parameter is not used response data contains items between 0 offset - limit. + If offset query parameter is out of bounds an empty result set is returned. + + Important fields of the returned data (RSS): + title Title of the found item. + guid A globally unique (GUID) item identifier. + pubdate The publishing date in RSS date object as specified by RFC822/2822. (not the Usenet date) + category The category the NZB belongs to. (This is human readable for RSS. More precise category is found in additional data) + enclosure The NZB url + + HTTP Method: + GET + + HTTP Response: + 200 OK + + Parameters: + t=search Search function, must always be "search" + apikey=xxxx User's key as provided by the service provider. + + Optional parameters: + q=xxxx Search input (URL/UTF-8 encoded). Case insensitive. + limit=123 Upper limit for the number of items to be returned. + cat=xxx List of categories to search delimited by "," + o=xxx Output format, either "JSON" or "XML". Default is "XML". + extended=1 Return extended information in the search results. (See DETAILS). + del=1 Delete the item from a users cart on download. + maxage=123 Only return results which were posted to usenet in the last x days. + offset=50 The 0 based query offset defining which part of the response we want. + + Examples: + --> GET http://servername.com/api?t=search&apikey=xxxxx&q=a%20tv%20show + <-- 200 OK + + + + + example.com</tile> + <description>example.com API results</description> + <!-- + More RSS content + --> + + <!-- offset is the current offset of the response total is the total number of items found by the query --> + <newznab:response offset="0" total="2344"/> + + <item> + <!-- Standard RSS 2.0 Data --> + <title>A.Tv.Show.S06E05.DVDRIP.XviD + http://servername.com/rss/viewnzb/e9c515e02346086e3a477a5436d7bc8c + http://servername.com/rss/nzb/e9c515e02346086e3a477a5436d7bc8c&i=1&r=18cf9f0a736041465e3bd521d00a90b9 + http://servername.com/rss/viewnzb/e9c515e02346086e3a477a5436d7bc8c#comments + Sun, 06 Jun 2010 17:29:23 +0100 + TV > XviD + Some TV show + + + + + + + + + + + + // no items matched the search criteria + --> GET http://servername.com/api?t=search&apikey=xxxxx&q=linux%20image + <-- 200 OK + + + + + + + + // Query could not be completed because user credentials are broken + --> GET http://servername.com/api?t=search&apikey=xxxxx&q=linux%20image + <-- 200 OK + + + + + // Query could not be completed because it was malformed + --> GET http://servername.com/api?t=search&apikey=xxxxx&q=linux%20image + <-- 200 OK + + + + 2.4 TV-SEARCH + + Description: + TV-SEARCH function searches the index in the TV category for items matching the search criteria. + The criteria includes query string and in addition information about season and episode. + On successful search the response contains a list of items that matched the query. Even if the + search matched nothing an empty but valid response is created and returned. This function + requires passing the user credentials. + + It is important to note, that all parameters are treated as AND operations execept for rid, tvdbid, + traktid, tvmazeid, imdbid, and tmdbid. Supplying any combination (some, none, all) of these values will + return results applicable for each value respective to the other AND parameters. + + The returned XML data stream is RSS 2.0 compliant and also contains additional information + in the extra namespace and optionally TV specific information + + HTTP Method: + GET + + HTTP Response: + 200 OK + + Parameters: + t=tvsearch TV-Search function, must always be "tvsearch". + apikey=xxx User's key as provided by the service provider. + + Optional parameters: + limit=123 Upper limit for the number of items to be returned, e.g. 123. + rid=xxxx TVRage id of the item being queried. + tvdbid=xxxx TVDB id of the item being queried. + traktid=xxxx TraktTV id of the item being queried. + tvmazeid=xxxx TVMaze id of the item being queried. + imdbid=xxxx IMDB id of the item being queried. + tmdbid=xxxx TMDB id of the item being queried. + cat=xxx List of categories to search delimited by "," + season=xxxx Season string, e.g S13 or 13 for the item being queried. Can also be YYYY for Daily Show. + q=xxxx Search input (URL/UTF-8 encoded). Case insensitive. + ep=xxx Episode string, e.g E13 or 13 for the item being queried. Can also be MM/DD for Daily Show. + o=xml Output format, either "JSON" or "XML". Default is "XML". + extended=1 Return extended information in the search results + del=1 Delete the item from a users cart on download. + maxage=123 Only return results which were posted to usenet in the last x days. + offset=50 The 0 based query offset defining which part of the response we want. + + Examples: + --> GET http://servername.com/api?t=tvsearch&apikey=xxxq=lost&season=S03 + <-- 200 OK + + + + example.com + example.com API results + + + + + + + + Land.of.the.Lost.S03E02.Survival.Kit.iNTERNAL.DVDRip.XViD-SPRiNTER + http://servername.com/rss/viewnzb/e9c515e02346086e3a477a5436d7bc8c + http://servername.com/rss/nzb/e9c515e02346086e3a477a5436d7bc8c&i=1&r=18cf9f0a736041465e3bd521d00a90b9 + http://servername.com/rss/viewnzb/e9c515e02346086e3a477a5436d7bc8c#comments + Sun, 06 Jun 2010 17:29:23 +0100 + TV > XviD + Some TV show + + + + + + + + + + + + Lost.S03E01.720p.BluRay.DTS.x264.INTERNAL-hV + http://servername.com/rss/viewnzb/e9c515e02346086e3a477a5436d7bc8c + http://servername.com/rss/nzb/e9c515e02346086e3a477a5436d7bc8c&i=1&r=18cf9f0a736041465e3bd521d00a90b9 + http://servername.com/rss/viewnzb/e9c515e02346086e3a477a5436d7bc8c#comments + Sun, 06 Jun 2010 17:29:23 +0100 + TV > XviD + Some TV show + + + + + + + + + + + + + + + + 2.5 MOVIE-SEARCH + + Description: + MOVIE-SEARCH function searches the index for items matching an IMDB id or search query. + On successful search the response contains a list of items that matched the query. Even if the + search matched nothing an empty but valid response is created and returned. This function + requires passing the user credentials. + + The returned XML data stream is RSS 2.0 compliant and also contains additional information + in the extra namespace and optionally movie specific information. + + HTTP Method: + GET + + HTTP Response: + 200 OK + + Parameters: + t=movie Movie-Search function, must always be "movie". + apikey=xxx User's key as provided by the service provider. + + Optional parameters: + limit=123 Upper limit for the number of items to be returned, e.g. 123. + imdbid=xxxx IMDB id of the item being queried e.g. 0058935. + cat=xxx List of categories to search delimited by "," + q=xxxx Search input (URL/UTF-8 encoded). Case insensitive. + o=xml Output format, either "JSON" or "XML". Default is "XML". + extended=1 Return extended information in the search results + del=1 Delete the item from a users cart on download. + maxage=123 Only return results which were posted to usenet in the last x days. + offset=50 The 0 based query offset defining which part of the response we want. + + Examples: + --> GET http://servername.com/api?t=movie&apikey=xxx&imdbid=0058935 + <-- 200 OK + + + + example.com + example.com API results + + + + + + + + Movie.Name.720p.BluRay.DTS.x264 + http://servername.com/rss/viewnzb/e9c515e02346086e3a477a5436d7bc8c + http://servername.com/rss/nzb/e9c515e02346086e3a477a5436d7bc8c&i=1&r=18cf9f0a736041465e3bd521d00a90b9 + http://servername.com/rss/viewnzb/e9c515e02346086e3a477a5436d7bc8c#comments + Sun, 06 Jun 2010 17:29:23 +0100 + Movie > XviD + Some movie + + + + + + + + + + + + 2.6 DETAILS + + Description: + DETAILS function returns all information for a particular Usenet (NZB) item. The response + contains the generic RSS part + full extra information + full type/category specific information. + + HTTP Method: + GET + + HTTP Response: + 200 OK + + Parameters: + t=details Details function, must always be "details". + guid=xxxx The GUID of the item being queried. + apikey=xxxx User's key as provided by the service provider. + + Optional parameters: + o=xxx Output format, either "JSON" or "XML". Default is "XML". + del=1 Delete the item from a users cart on download. + + Example: + --> GET http://servername.com/api?t=details&apikey=xxxxx&guid=xxxxxxxxx + <-- 200 OK + + + + + + A.Tv.Show.S06E05.DVDRIP.XviD + http://servername.com/rss/viewnzb/e9c515e02346086e3a477a5436d7bc8c + http://servername.com/rss/nzb/e9c515e02346086e3a477a5436d7bc8c&i=1&r=18cf9f0a736041465e3bd521d00a90b9 + http://servername.com/rss/viewnzb/e9c515e02346086e3a477a5436d7bc8c#comments + Sun, 06 Jun 2010 17:29:23 +0100 + TV > XviD + Some TV show + + + + + + + + + + + + + + + + + + // Query could not be completed because it was malformed + --> GET http://servername.com/api?t=details&apikey=xxxxx&guid=xxxxxxxxx + <-- 200 OK + + + + // Query could not be completed because no such item was available + --> GET http://servername.com/api?t=details&apikey=xxxxx&guid=xxxxxxxxx + <-- 200 OK + + + + // Query could not be completed because user credentials are broken + --> GET http://servername.com/api?t=details&apikey=xxxxx&guid=xxxxxxxxx + <-- 200 OK + + + + + +3. Predefined Categories + + In order to facilitate operation that does not rely on a particular natural language, e.g. english + a set of predefined category IDs have been defined. It is possible to define custom categories + in the custom category range. Each category is given a range for a set of subcategories. It is possible + for an item to belong to several categories at the same time. + + Category Range Category Name Comments + 0000-0999 Reserved + 1000-1999 Console + 2000-2999 Movies + 3000-3999 Audio + 4000-4999 PC + 5000-5999 TV + 6000-6999 XXX + 7000-7999 Other + 8000-8999 Books + 9000-99999 Reserved Reserved for future expansion + 100000- Custom Site specific category range. Defined in CAPS + + Categories Category Name + + 0000 Reserved + 1000 Console All of console + 1010 Console/NDS Nintendo DS + 1020 Console/PSP Sony Playstation Portable + 1030 Console/Wii Nintendo Wii + 1040 Console/Xbox Microsoft XBox + 1050 Console/Xbox 360 Microsoft XBox 360 + 1060 Console/Wiiware/VC Wii homebrew + 1070 Console/XBOX 360 DLC Microsoft XBox 360 Downloadable Content + 1080 Console/PS3 Playstation 3 + 1090 Console/Other Misc Console + 1110 Console/3DS Nintendo 3DS + 1120 Console/PS Vita Playstation Vita + 1130 Console/WiiU Nintento Wii U + 1140 Console/Xbox One Xbox One + 1180 Console/PS4 Playstation 4 + 2000 Movies All of movies + 2010 Movies/Foreign Non english movies + 2020 Movies/Other Misc movies + 2030 Movies/SD Standard definition movies + 2040 Movies/HD High definition movies (720p+) + 2050 Movies/3D 3D movies + 2060 Movies/BluRay Full BR movies + 2070 Movies/DVD Full DVD movies + 2080 Movies/WEBDL WEB-DL movies + 3000 Audio All of audio + 3010 Audio/MP3 Mp3 music + 3020 Audio/Video Music videos + 3030 Audio/Audiobook Books in audio format + 3040 Audio/Lossless Lossless music + 3050 Audio/Other Misc music + 3060 Audio/Foreign Non english music. + 4000 PC All of PC + 4010 PC/0day Apps and games not released in ISO. + 4020 PC/ISO CD-ROM images/DVD Images + 4030 PC/Mac OS X apps and games + 4040 PC/Phone-Other Misc mobile phone software + 4050 PC/Games PC Games + 4060 PC/Phone-IOS IOS apps + 4070 PC/Phone-Android Android apps + 5000 TV All of TV + 5010 TV/WEB-DL WEB-DL TV + 5020 TV/FOREIGN FOREIGN TV + 5030 TV/SD SD TV + 5040 TV/HD HD TV + 5050 TV/OTHER Other TV Content + 5060 TV/Sport Sports + 5070 TV/Anime Anime + 5080 TV/Documentary Documentaries + 6000 XXX All of XXX + 6010 XXX/DVD Full DVD's + 6020 XXX/WMV WMV rips + 6030 XXX/XviD dvdrips + 6040 XXX/x264 HD Porn + 6050 XXX/Other Misc Porn + 6060 XXX/Imageset Sets of porn images + 6070 XXX/Packs Packs of multiple porn videos + 7000 Other All of Other + 7010 Other/Misc Anything that could not get categorized + 7020 Other/Hashed Anything with a hashed name + 8000 Books All of Books + 8010 Books/Ebook Ebooks + 8020 Books/Comics Comics Ebooks + 8030 Books/Magazines Magazines + 8040 Books/Technical Technical books + 8050 Books/Other Misc books + 8060 Books/Foreign Non english books + 100000- Custom Specific to a site + + +4. PREDEFINED ATTRIBUTES + + A set of known attributes for items in different categories has been defined. + Its possible that not all attributes are available at all times. Therefore a + client application should not rely on any particular attributes being in the + returned data but should take this list as an optional extra information. + However attributes marked with * are always available. + + Additionally, not all attributes are applicable to all items. The category + information can be used to check which attributes area available for which + category items. + + All attributes are defined using XML namespace syntax. + e.g. xmlns:newznab="http://www.newznab.com/DTD/2010/feeds/attributes/" + + 4.1 List of Attributes + + Attribute Category Description Example value + + size * ALL Size in bytes "252322" + category * ALL Item's category "5004" + files ALL Number of files "4" + poster ALL NNTP Poster "yenc@power-post" + group ALL NNTP Group(s) "a.b.warez, a.b.teevee" + team ALL Team doing the release "DiAMOND" + grabs ALL Number of times item downloaded "1" + password ALL Whether the archive is passworded "0" no, "1" rar pass, "2" contains inner archive + comments ALL Number of comments "2" + usenetdate ALL Date posted to usenet "Tue, 22 Jun 2010 06:54:22 +0100" + info ALL Info (.nfo) file URL "http://somesite/stuff/info.php?id=1234" + year ALL Release year "2009" + season TV Numeric season "1" + episode TV Numeric episode within the season "1" + videos_id TV, Movies, Anime Local Video ID "1" + tv_episodes_id TV Local TV Episode ID "1" + tvdbid TV TVDB ID. (www.thetvdb.com) "153021" + traktid TV TraktTV ID. (www.trakt.tv) "1393" + rageid TV TVRage ID. (www.tvrage.com) "25056" + tvrageid TV TVRage ID. (www.tvrage.com) "25056" + tvmazeid TV TVMaze ID. (www.tvmaze.com) "73" + imdbid TV IMDB ID for show. (www.imdb.com) "tt1520211" + tmdbid TV TMDB ID for show. (www.themoviedb.com) "1402" + title TV TV Show Title. (www.tvrage.com) "Duck and Cover" + firstaired TV TV Show Air date. (www.tvrage.com) "Tue, 22 Jun 2010 06:54:22 +0100" + anidbid Anime AniDB.net ID. (www.anidb.net) "10445" + video TV, Movies Video codec "x264" + audio TV, Movies, Audio Audio codec "AC3 2.0 @ 384 kbs" + resolution TV, Movies Video resolution "1280x716 1.78:1" + framerate TV, Movies Video fps "23.976 fps" + language TV, Movies, Audio Natural languages "English" + subs TV, Movies Subtitles "English, Spanish" + imdb TV, Movies IMDb ID (www.imdb.com) "0104409" + genre TV, Movies Genre "Horror" + + + + 4.2 Attribute Example + + Example attribute declarations within element. + + + + + + +5. nZEDb Error Codes + + Under normal circumstances i.e. when the HTTP request/response sequence is successfully completed + nZEDb implementations always respond with HTTP 200 OK. However this does not mean that the + query was semantically correct. It simply means that the HTTP part of the sequence was successful. + One then must check the actual response body/data to see if the request was completed + without errors. + + In case of a nZEDb error the response contains an error code and an a description of the error. + + The error codes have been defined into different ranges. 100-199 Account/user credentials specific + error codes, 200-299 API call specific error codes, 300-399 content specific error codes and finally + 900-999 Other error codes. + + Error code Description + + 100 Incorrect user credentials + 101 Account suspended + 102 Insufficient privileges/not authorised + 103 Registration denied + 104 Registrations are closed + 105 Invalid registration (Email Address Taken) + 106 Invalid registration (Email Address Bad Format) + 107 Registration Failed (Data error) + + 200 Missing parameter + 201 Incorrect parameter + 202 No such function. (Function not defined in this specification). + 203 Function not available. (Optional function is not implemented). + + 300 No such item. + + 500 Request limit reached + 501 Download limit reached + + 900 Unknown error + + 5.1 Error code example + + // Query could not be completed because user credentials are broken + --> GET http://servername.com/api?t=details&apikey=xxxxx&guid=xxxxxxxxx + <-- 200 OK + + + +6 Changelog + + 2015-10-24 ruhllatio + Add new attribute returns. + Update supported tv-search methods. + Add audio-search capability and make it unavailable with no params. + 2015-05-23 kevinlekiller + Fix spelling issues. + Fix indentation issues. + Add missing categories. + Add missing error codes. \ No newline at end of file diff --git a/newznab/Capabilities.php b/newznab/Capabilities.php index 5eb7bcf16..37078c25c 100644 --- a/newznab/Capabilities.php +++ b/newznab/Capabilities.php @@ -62,13 +62,10 @@ class Capabilities 'open' => $this->pdo->getSetting('registerstatus') == 0 ? 'yes' : 'no' ], 'searching' => [ - ['search' => 'yes'], - ['supportedParams' => 'q'], - ['tv-search' => 'yes'], - ['supportedParams' => 'q, vid, tvdbid, traktid, rid, tvmazeid, imdbid, tmdbid, season, ep'], - ['movie-search' => 'yes'], - ['supportedParams' => 'q'], - ['audio-search' => 'yes'] + 'search' => ['available' => 'yes', 'supportedParams' => 'q'], + 'tv-search' => ['available' => 'yes', 'supportedParams' => 'q,vid,tvdbid,traktid,rid,tvmazeid,imdbid,tmdbid,season,ep'], + 'movie-search' => ['available' => 'yes', 'supportedParams' => 'q,imdbid'], + 'audio-search' => ['available' => 'no', 'supportedParams' => ''] ] ]; } diff --git a/newznab/Releases.php b/newznab/Releases.php index df7ad7843..4404eac98 100755 --- a/newznab/Releases.php +++ b/newznab/Releases.php @@ -209,11 +209,13 @@ class Releases g.name AS group_name, rn.id AS nfoid, re.releaseid AS reid, + v.tvdb, v.trakt, v.tvrage, v.tvmaze, v.imdb, v.tmdb, tve.title, tve.firstaired FROM releases r STRAIGHT_JOIN groups g ON g.id = r.groupid STRAIGHT_JOIN category c ON c.id = r.categoryid INNER JOIN category cp ON cp.id = c.parentid + LEFT OUTER JOIN videos v ON r.videos_id = v.id LEFT OUTER JOIN tv_episodes tve ON r.tv_episodes_id = tve.id LEFT OUTER JOIN releasevideo re ON re.releaseid = r.id LEFT OUTER JOIN releasenfo rn ON rn.releaseid = r.id @@ -885,9 +887,11 @@ class Releases rn.id AS nfoid, re.releaseid AS reid, cp.id AS categoryparentid, - tve.firstaired, + v.tvdb, v.trakt, v.tvrage, v.tvmaze, v.imdb, v.tmdb, + tve.firstaired FROM releases r LEFT OUTER JOIN releasevideo re ON re.releaseid = r.id + LEFT OUTER JOIN videos v ON r.videos_id = v.id LEFT OUTER JOIN tv_episodes tve ON r.tv_episodes_id = tve.id LEFT OUTER JOIN releasenfo rn ON rn.releaseid = r.id INNER JOIN groups ON groups.id = r.groupid @@ -918,15 +922,10 @@ class Releases } /** - * @param $videosId - * @param $tvdbId - * @param $traktId - * @param $tvrageId - * @param $tvmazeId - * @param $imdbId - * @param $tmdbId + * @param array $siteIdArr * @param string $series * @param string $episode + * @param string $airdate * @param int $offset * @param int $limit * @param string $name @@ -935,35 +934,45 @@ class Releases * * @return array */ - public function searchShows($videosId, $tvdbId, $traktId, $tvrageId, $tvmazeId, $imdbId, $tmdbId, $series = '', - $episode = '', $offset = 0, $limit = 100, $name = '', $cat = [-1], $maxAge = -1) + public function searchShows($siteIdArr = array(), $series = '', $episode = '', $airdate = '', $offset = 0, + $limit = 100, $name = '', $cat = [-1], $maxAge = -1) { + $siteSQL = array(); + + if (is_array($siteIdArr)) { + foreach ($siteIdArr as $column => $Id) { + if ($Id > 0) { + $siteSQL[] = sprintf('v.%s = %d', $column, $Id); + } + } + } + + $siteCount = count($siteSQL); + $whereSql = sprintf( "%s WHERE r.categoryid BETWEEN 5000 AND 5999 AND v.type = 0 AND r.nzbstatus = %d - AND r.passwordstatus %s %s %s %s %s %s %s %s %s %s %s %s %s", + AND r.passwordstatus %s + AND (%s) + %s %s %s %s %s %s", ($name !== '' ? $this->releaseSearch->getFullTextJoinString() : ''), NZB::NZB_ADDED, $this->showPasswords, - ($videosId > 0 ? sprintf(' AND v.id = %d ', $videosId) : ''), - ($tvdbId > 0 ? sprintf(' AND v.tvdb = %d ', $tvdbId) : ''), - ($traktId > 0 ? sprintf(' AND v.trakt = %d ', $traktId) : ''), - ($tvrageId > 0 ? sprintf(' AND v.tvrage = %d ', $tvrageId) : ''), - ($tvmazeId > 0 ? sprintf(' AND v.tvmaze = %d ', $tvmazeId) : ''), - ($imdbId > 0 ? sprintf(' AND v.imdb = %d ', $imdbId) : ''), - ($tmdbId > 0 ? sprintf(' AND v.tmdb = %d ', $tmdbId) : ''), - ($series != '' ? sprintf(' AND tve.series = %d', (int)preg_replace('/^s0*/i', '', $series)): ''), - ($episode != '' ? sprintf(' AND tve.episode = %d', (int)preg_replace('/^e0*/i', '', $episode)): ''), + ($siteCount > 0 ? implode(' OR ', $siteSQL) : '1=1'), + ($series != '' ? sprintf('AND tve.series = %d', (int)preg_replace('/^s0*/i', '', $series)): ''), + ($episode != '' ? sprintf('AND tve.episode = %d', (int)preg_replace('/^e0*/i', '', $episode)): ''), + ($airdate != '' ? sprintf('AND DATE(tve.firstaired) = %s', $this->pdo->escapeString($airdate)) : ''), ($name !== '' ? $this->releaseSearch->getSearchSQL(['searchname' => $name]) : ''), $this->categorySQL($cat), - ($maxAge > 0 ? sprintf(' AND r.postdate > NOW() - INTERVAL %d DAY ', $maxAge) : '') + ($maxAge > 0 ? sprintf('AND r.postdate > NOW() - INTERVAL %d DAY', $maxAge) : '') ); $baseSql = sprintf( "SELECT r.*, - v.title, v.countries_id, v.started, v.imdb, v.tmdb, v.tvmaze, v.tvrage, v.source, + v.title, v.countries_id, v.started, v.tvdb, v.trakt, + v.imdb, v.tmdb, v.tvmaze, v.tvrage, v.source, tvi.summary, tvi.publisher, tvi.image, tve.series, tve.episode, tve.se_complete, tve.title, tve.firstaired, tve.summary, CONCAT(cp.title, ' > ', c.title) AS category_name, @@ -1310,20 +1319,20 @@ class Releases } /** - * @param int $anidbID + * @param $anidbID * - * @return mixed + * @return bool|\PDOStatement */ public function removeAnidbIdFromReleases($anidbID) { - $res = $this->pdo->queryOneRow( - sprintf('SELECT COUNT(r.id) AS num FROM releases r WHERE anidbid = %d', $anidbID) + return $this->pdo->queryExec( + sprintf(' + UPDATE releases + SET anidbid = -1 + WHERE anidbid = %d', + $anidbID + ) ); - $this->pdo->queryExec( - sprintf('UPDATE releases SET anidbid = -1, episode = NULL, tvtitle = NULL, tvairdate = NULL WHERE anidbid = %d', $anidbID) - ); - - return ($res === false ? 0 : $res['num']); } /** diff --git a/newznab/Videos.php b/newznab/Videos.php index 617d71eef..2b212a5b0 100644 --- a/newznab/Videos.php +++ b/newznab/Videos.php @@ -45,6 +45,8 @@ Class Videos } /** + * Retrieves a range of all shows for the show-edit admin list + * * @param $start * @param $num * @param string $showname @@ -79,6 +81,8 @@ Class Videos } /** + * Returns a count of all shows -- usually used by pager + * * @param string $showname * * @return mixed @@ -93,6 +97,7 @@ Class Videos sprintf(" SELECT COUNT(v.id) AS num FROM videos v + INNER JOIN tv_info tvi ON v.id = tvi.videos_id WHERE 1=1 %s", $rsql ) @@ -101,6 +106,8 @@ Class Videos } /** + * Retrieves and returns a list of shows with eligible releases + * * @param $uid * @param string $letter * @param string $showname @@ -123,21 +130,21 @@ Class Videos } $qry = sprintf(" - SELECT v.* FROM ( - SELECT v.*, - tve.firstaired AS prevdate, tve.title AS previnfo, - tvi.publisher, - us.id AS userseriesid - FROM videos v - INNER JOIN releases r ON r.videos_id = v.id - INNER JOIN tv_info tvi ON r.videos_id = tvi.videos_id - INNER JOIN tv_episodes tve ON v.id = tve.videos_id AND DATE(tve.firstaired) <= DATE(NOW()) - LEFT OUTER JOIN userseries us ON v.id = us.videos_id AND us.userid = %d - WHERE %s - %s %s - ORDER BY tve.firstaired DESC) v - GROUP BY v.id - ORDER BY v.title ASC", + SELECT v.* FROM + (SELECT v.*, + tve.firstaired AS prevdate, tve.title AS previnfo, + tvi.publisher, + us.id AS userseriesid + FROM videos v + INNER JOIN releases r ON r.videos_id = v.id + INNER JOIN tv_info tvi ON r.videos_id = tvi.videos_id + INNER JOIN tv_episodes tve ON v.id = tve.videos_id AND tve.firstaired <= NOW() + LEFT OUTER JOIN userseries us ON v.id = us.videos_id AND us.userid = %d + WHERE %s + %s %s + ORDER BY tve.firstaired DESC) v + GROUP BY v.id + ORDER BY v.title ASC", $uid, $this->catWhere, $rsql, diff --git a/newznab/processing/Videos.php b/newznab/processing/Videos.php index 21ab5ba1e..6896abad7 100644 --- a/newznab/processing/Videos.php +++ b/newznab/processing/Videos.php @@ -29,6 +29,10 @@ use newznab\db\Settings; */ abstract class Videos { + // Video Type Identifiers + const TYPE_TV = 0; // Type of video is a TV Programme/Show + const TYPE_FILM = 1; // Type of video is a Film/Movie + const TYPE_ANIME = 2; // Type of video is a Anime /** * @var \newznab\db\Settings */ diff --git a/newznab/processing/tv/TV.php b/newznab/processing/tv/TV.php index 04f91c3d0..3e5222a8b 100644 --- a/newznab/processing/tv/TV.php +++ b/newznab/processing/tv/TV.php @@ -4,7 +4,8 @@ namespace newznab\processing\tv; use newznab\processing\Videos; /** - * Class TV + * Class TV -- abstract extension of Videos + * Contains functions suitable for re-use in all TV scrapers */ abstract class TV extends Videos { @@ -29,11 +30,6 @@ abstract class TV extends Videos const PROCESS_TMDB = -5; // Process TMDB Sixth const NO_MATCH_FOUND = -6; // Failed All Methods - // Video Type Identifiers - const TYPE_TV = 0; // Type of video is a TV Show - const TYPE_FILM = 1; // Type of video is a TV Show - const TYPE_ANIME = 2; // Type of video is a TV Show - /** * @var bool */ @@ -61,14 +57,22 @@ abstract class TV extends Videos $this->tvqty = ($this->pdo->getSetting('maxrageprocessed') != '') ? $this->pdo->getSetting('maxrageprocessed') : 75; } + /** + * Retrieve banner image from site using its API. + * + * @param $videoID + * @param $siteId + * + * @return mixed + */ abstract protected function getBanner($videoID, $siteId); /** * Retrieve info of TV episode from site using its API. * - * @param integer $siteId - * @param integer $series - * @param integer $episode + * @param integer $siteId + * @param integer $series + * @param integer $episode * * @return array|false False on failure, an array of information fields otherwise. */ @@ -87,17 +91,19 @@ abstract class TV extends Videos /** * Retrieve info of TV programme from site using it's API. * - * @param string $name Title of programme to look up. Usually a cleaned up version from releases table. + * @param string $name Title of programme to look up. Usually a cleaned up version from releases table. * - * @return array|false False on failure, an array of information fields otherwise. + * @return array|false False on failure, an array of information fields otherwise. */ abstract protected function getShowInfo($name); /** - * @param string $groupID - * @param string $guidChar - * @param int $lookupSetting - * @param int $status + * Retrieve releases for TV processing + * + * @param string $groupID -- ID of the usenet group to process + * @param string $guidChar -- threading method by first guid character + * @param int $lookupSetting -- whether or not to use the API + * @param int $status -- release processing status of tv_episodes_id * * @return bool|int|\PDOStatement */ @@ -121,7 +127,7 @@ abstract class TV extends Videos LIMIT %d", $status, $this->catWhere, - ($groupID === '' ? '' : 'AND r.group_id = ' . $groupID), + ($groupID === '' ? '' : 'AND r.groupid = ' . $groupID), ($guidChar === '' ? '' : 'AND r.guid ' . $this->pdo->likeString($guidChar, false, true)), ($lookupSetting == 2 ? 'AND r.isrenamed = 1' : ''), $this->tvqty @@ -131,59 +137,71 @@ abstract class TV extends Videos } /** + * Updates the release when match for the current scraper is found + * * @param $videoId * @param $releaseId * @param int $episodeId */ public function setVideoIdFound($videoId, $releaseId, $episodeId) { $this->pdo->queryExec( - sprintf(' - UPDATE releases - SET videos_id = %d, tv_episodes_id = %d - WHERE %s - AND id = %d', - $videoId, - $episodeId, - $this->catWhere, - $releaseId - ) + sprintf(' + UPDATE releases + SET videos_id = %d, tv_episodes_id = %d + WHERE %s + AND id = %d', + $videoId, + $episodeId, + $this->catWhere, + $releaseId + ) ); } /** + * Updates the release tv_episodes_id status when scraper match is not found + * * @param $status * @param $Id */ public function setVideoNotFound($status, $Id) { $this->pdo->queryExec( - sprintf(' - UPDATE releases - SET tv_episodes_id = %d - WHERE %s - AND id = %d', - $status, - $this->catWhere, - $Id - ) + sprintf(' + UPDATE releases + SET tv_episodes_id = %d + WHERE %s + AND id = %d', + $status, + $this->catWhere, + $Id + ) ); } /** + * Inserts a new video ID into the database for TV shows + * If a duplicate is found it is handle by calling update instead + * + * @param $title * @param $column * @param $siteId - * @param $title * @param $summary * @param $country * @param $started * @param $publisher * @param $source - * + * @param int $tvdbId + * @param int $traktId + * @param int $tvrageId + * @param int $tvmazeId * @param int $imdbId + * @param int $tmdbId * * @return int */ - public function add($column, $siteId, $title, $summary, $country, $started, $publisher, $source, $imdbId = 0) + public function add($title, $column, $siteId, $summary, $country, $started, $publisher, $source, $tvdbId = 0, + $traktId = 0, $tvrageId = 0, $tvmazeId = 0, $imdbId = 0, $tmdbId = 0) { if ($country !== '') { $country = $this->countryCode($country); @@ -200,34 +218,40 @@ abstract class TV extends Videos if ($videoId === false) { $videoId = $this->pdo->queryInsert( - sprintf(' - INSERT INTO videos (%s, type, title, countries_id, started, source, imdb) - VALUES (%s, 0, %s, %s, %s, %d, %d)', - $column, - $siteId, - $this->pdo->escapeString($title), - $this->pdo->escapeString((isset($country) ? $country : '')), - $this->pdo->escapeString($started), - $source, - $imdbId - ) + sprintf(' + INSERT INTO videos + (type, title, countries_id, started, source, tvdb, trakt, tvrage, tvmaze, imdb, tmdb) + VALUES (0, %s, %s, %s, %d, %d, %d, %d, %d, %d, %d)', + $this->pdo->escapeString($title), + $this->pdo->escapeString((isset($country) ? $country : '')), + $this->pdo->escapeString($started), + $source, + $tvdbId, + $traktId, + $tvrageId, + $tvmazeId, + $imdbId, + $tmdbId + ) ); $this->pdo->queryInsert( - sprintf(" - INSERT INTO tv_info (videos_id, summary, publisher) - VALUES (%d, %s, %s)", - $videoId, - $this->pdo->escapeString($summary), - $this->pdo->escapeString($publisher) - ) + sprintf(" + INSERT INTO tv_info (videos_id, summary, publisher) + VALUES (%d, %s, %s)", + $videoId, + $this->pdo->escapeString($summary), + $this->pdo->escapeString($publisher) + ) ); } else { - $this->update($videoId, $column, $siteId, $country, $imdbId); + $this->update($videoId, $country, $tvdbId, $traktId, $tvrageId, $tvmazeId, $imdbId, $tmdbId); } return (int)$videoId; } /** + * Inserts a new TV episode into the tv_episodes table following a match to a Video ID + * * @param $videoId * @param $seriesNo * @param $episodeNo @@ -245,15 +269,17 @@ abstract class TV extends Videos if ($episodeId === false) { $episodeId = $this->pdo->queryInsert( sprintf(' - INSERT INTO tv_episodes (videos_id, series, episode, se_complete, title, firstaired, summary) - VALUES (%d, %d, %d, %s, %s, %s, %s)', + INSERT INTO tv_episodes (videos_id, series, episode, se_complete, title, firstaired, summary) + VALUES (%d, %d, %d, %s, %s, %s, %s) + ON DUPLICATE KEY update se_complete = %s', $videoId, $seriesNo, $episodeNo, $this->pdo->escapeString($seComplete), $this->pdo->escapeString($title), $this->pdo->escapeString($firstaired), - $this->pdo->escapeString($summary) + $this->pdo->escapeString($summary), + $this->pdo->escapeString($seComplete) ) ); } @@ -261,34 +287,46 @@ abstract class TV extends Videos } // If the video already exists, update the site specific column to collect its ID for that scrape + /** * @param $videoId - * @param $column - * @param $siteId * @param string $country - * @param $imdbId + * @param int $tvdbId + * @param int $traktId + * @param int $tvrageId + * @param int $tvmazeId + * @param int $imdbId + * @param int $tmdbId */ - public function update($videoId, $column, $siteId, $country = '', $imdbId = 0) + public function update($videoId, $country = '', $tvdbId = 0, $traktId = 0, $tvrageId = 0, + $tvmazeId = 0, $imdbId = 0, $tmdbId = 0) { if ($country !== '') { $country = $this->countryCode($country); } + $ifString = 'IF(%s = 0, %s, %s)'; + $this->pdo->queryExec( - sprintf(' - UPDATE videos - SET %s = %d, countries_id = %s, imdb = %d - WHERE id = %d', - $column, - $siteId, - $this->pdo->escapeString((isset($country) ? $country : '')), - ($imdbId > 0 ? $imdbId : 0), - $videoId - ) + sprintf(' + UPDATE videos + SET countries_id = %s, tvdb = %s, trakt = %s, tvrage = %s, tvmaze = %s, imdb = %s, tmdb = %s + WHERE id = %d', + $this->pdo->escapeString((isset($country) ? $country : '')), + sprintf($ifString, 'tvdb', $tvdbId, 'tvdb'), + sprintf($ifString, 'trakt', $traktId, 'trakt'), + sprintf($ifString, 'tvrage', $tvrageId, 'tvrage'), + sprintf($ifString, 'tvmaze', $tvmazeId, 'tvmaze'), + sprintf($ifString, 'imdb', $imdbId, 'imdb'), + sprintf($ifString, 'tmdb', $tmdbId, 'tmdb'), + $videoId + ) ); } /** + * Deletes a TV show entirely from all child tables via the Video ID + * * @param $id * * @return bool|\PDOStatement @@ -296,34 +334,37 @@ abstract class TV extends Videos public function delete($id) { return $this->pdo->queryExec( - sprintf(" - DELETE v, tvi, tve - FROM videos v - LEFT JOIN tv_info tvi ON v.id = tvi.videos_id - LEFT JOIN tv_episodes tve ON v.id = tve.videos_id - WHERE id = %d", - $id - ) + sprintf(" + DELETE v, tvi, tve + FROM videos v + LEFT JOIN tv_info tvi ON v.id = tvi.videos_id + LEFT JOIN tv_episodes tve ON v.id = tve.videos_id + WHERE v.id = %d", + $id + ) ); } /** + * Sets the TV show's image column to found (1) + * * @param $videoId */ public function setCoverFound($videoId) { $this->pdo->queryExec( sprintf(" - UPDATE tv_info - SET image = 1 - WHERE videos_id = %d", - $videoId + UPDATE tv_info + SET image = 1 + WHERE videos_id = %d", + $videoId ) ); } /** - * Get videos info for a title. + * Attempt a local lookup via the title first by exact match and then by like. + * Returns a false for no match or the Video ID of the match. * * @param $title * @@ -391,49 +432,59 @@ abstract class TV extends Videos } /** + * Supplementary function for getByTitle that queries for exact match + * + * * @param $title * * @return array|bool */ public function getByTitleQuery($title) { + $return = false; if ($title) { - return $this->pdo->queryOneRow( - sprintf(" - SELECT id - FROM videos - WHERE title = %s - AND type = 0", - $this->pdo->escapeString($title) - ) + $return = $this->pdo->queryOneRow( + sprintf(" + SELECT id + FROM videos + WHERE title = %s + AND type = 0", + $this->pdo->escapeString($title) + ) ); } + return $return; } /** + * Supplementary function for getByTitle that queries for a like match + * * @param $title * * @return array|bool */ public function getByTitleLikeQuery($title) { + $return = false; $string = '"\'"'; if ($title) { - return $this->pdo->queryOneRow( - sprintf(" - SELECT id - FROM videos - WHERE REPLACE(REPLACE(title, %s, ''), '!', '') %s - AND type = 0", - $string, - $this->pdo->likeString(rtrim($title, '%'), false, false) - ) + $return = $this->pdo->queryOneRow( + sprintf(" + SELECT id + FROM videos + WHERE REPLACE(REPLACE(title, %s, ''), '!', '') %s + AND type = 0", + $string, + $this->pdo->likeString(rtrim($title, '%'), false, false) + ) ); } + return $return; } /** - * Get site column from a Video ID. + * Get site ID from a Video ID and the site's respective column. + * Returns the ID value or false if none found * * @param string $column * @param int $id @@ -443,23 +494,29 @@ abstract class TV extends Videos public function getSiteByID($column, $id) { $videoArr = $this->pdo->queryOneRow( - sprintf(" - SELECT %s - FROM videos - WHERE id = %d", - $column, - $id - ) + sprintf(" + SELECT %s + FROM videos + WHERE id = %d", + $column, + $id + ) ); return (isset($videoArr[$column]) ? $videoArr[$column] : false); } /** - * @param $id - * @param $series - * @param $episode + * Retrieves the Episode ID using the Video ID and either: + * season/episode numbers OR the airdate * - * @return bool + * Returns the Episode ID or false if not found + * + * @param $id + * @param $series + * @param $episode + * @param string $airdate + * + * @return int|bool */ public function getBySeasonEp($id, $series, $episode, $airdate = '') { @@ -469,14 +526,14 @@ abstract class TV extends Videos $queryString = sprintf('DATE(firstaired) = %s', $this->pdo->escapeString($airdate)); } $episodeArr = $this->pdo->queryOneRow( - sprintf(" - SELECT id - FROM tv_episodes - WHERE videos_id = %d - AND %s", - $id, - $queryString - ) + sprintf(" + SELECT id + FROM tv_episodes + WHERE videos_id = %d + AND %s", + $id, + $queryString + ) ); return (isset($episodeArr['id']) ? $episodeArr['id'] : false); } @@ -492,39 +549,46 @@ abstract class TV extends Videos { if (!is_array($country) && strlen($country) > 2) { $code = $this->pdo->queryOneRow( - sprintf(' - SELECT code - FROM countries - WHERE name = %s', - $this->pdo->escapeString($country) - ) + sprintf(' + SELECT id + FROM countries + WHERE country = %s + OR iso3 = %1\$s', + $this->pdo->escapeString($country) + ) ); - if (isset($code['code'])) { - return $code['code']; + if (isset($code['id'])) { + return $code['id']; } } return ''; } /** - * @param $videoID + * Returns (true) if episodes for a given Video ID exist or don't (false) * - * @return array|bool + * @param $videoId + * + * @return bool */ - public function checkIfNoEpisodes($videoId) + public function countEpsByVideoID($videoId) { $count = $this->pdo->queryOneRow( - sprintf(' - SELECT count(id) AS num - FROM tv_episodes - WHERE videos_id = %d', - $videoId - ) + sprintf(' + SELECT count(id) AS num + FROM tv_episodes + WHERE videos_id = %d', + $videoId + ) ); return (isset($count['num']) && (int)$count['num'] > 0 ? true : false); } /** + * Supplementary to parseNameEpSeason + * Cleans a derived local 'showname' for better matching probability + * Returns the cleaned string + * * @param $str * * @return string @@ -552,6 +616,9 @@ abstract class TV extends Videos } /** + * Parses a release searchname for specific TV show data + * Returns an array of show data + * * @param $relname * * @return array|bool @@ -748,49 +815,23 @@ abstract class TV extends Videos } /** + * Simple function that compares two strings of text + * Returns percentage of similarity + * * @param $ourName - * @param $tvrName + * @param $scrapeName + * @param $probability * * @return bool|float */ - public function checkMatch($ourName, $tvrName) + public function checkMatch($ourName, $scrapeName, $probability) { - // Clean up name ($ourName is already clean). - $tvrName = $this->cleanName($tvrName); - $tvrName = preg_replace('/ of /i', '', $tvrName); - $ourName = preg_replace('/ of /i', '', $ourName); + similar_text($ourName, $scrapeName, $matchpct); - // Create our arrays. - $ourArr = explode(' ', $ourName); - $tvrArr = explode(' ', $tvrName); - - // Set our match counts. - $numMatches = 0; - $totalMatches = sizeof($ourArr) + sizeof($tvrArr); - - // Loop through each array matching again the opposite value, if they match increment! - foreach ($ourArr as $oname) { - if (preg_match('/ ' . preg_quote($oname, '/') . ' /i', ' ' . $tvrName . ' ')) { - $numMatches++; - } - } - foreach ($tvrArr as $tname) { - if (preg_match('/ ' . preg_quote($tname, '/') . ' /i', ' ' . $ourName . ' ')) { - $numMatches++; - } - } - - // Check what we're left with. - if ($numMatches <= 0) { - return false; - } else { - $matchpct = ($numMatches / $totalMatches) * 100; - } - - if ($matchpct >= TvRage::MATCH_PROBABILITY) { + if ($matchpct >= $probability) { return $matchpct; } else { - return false; + return 0; } } diff --git a/newznab/processing/tv/TVDB.php b/newznab/processing/tv/TVDB.php index 297f01b0a..a93e25500 100644 --- a/newznab/processing/tv/TVDB.php +++ b/newznab/processing/tv/TVDB.php @@ -5,7 +5,7 @@ use libs\Moinax\TVDB\Client; use newznab\ReleaseImage; /** - * Class TVDB + * Class TVDB -- functions used to post process releases against TVDB */ class TVDB extends TV { @@ -59,6 +59,9 @@ class TVDB extends TV } /** + * Main processing director function for TVDB + * Calls work query function and initiates processing + * * @param $groupID * @param $guidChar * @param $processTV @@ -111,22 +114,25 @@ class TVDB extends TV if (is_array($tvdbShow)) { $tvdbShow['country'] = (isset($release['country']) && strlen($release['country']) == 2 - ? (string)$release['country'] - : '' + ? (string)$release['country'] + : '' ); $videoId = $this->add( - $tvdbShow['column'], - $tvdbShow['siteid'], - $tvdbShow['title'], - $tvdbShow['summary'], - $tvdbShow['country'], - $tvdbShow['started'], - $tvdbShow['publisher'], - $tvdbShow['source'], - $tvdbShow['imdbid'] + $tvdbShow['title'], + $tvdbShow['column'], + $tvdbShow['siteid'], + $tvdbShow['summary'], + $tvdbShow['country'], + $tvdbShow['started'], + $tvdbShow['publisher'], + $tvdbShow['source'], + $tvdbShow['tvdbid'], + 0, 0, 0, + $tvdbShow['imdbid'], + 0 ); - $tvdbid = (int)$tvdbShow['siteid']; + $tvdbid = (int)$tvdbShow['tvdbid']; } } else if ($this->echooutput) { echo $this->pdo->log->primaryOver("Video ID for ") . @@ -142,32 +148,31 @@ class TVDB extends TV $episodeNo = preg_replace('/^E0*/', '', $release['episode']); // Download all episodes if new show to reduce API/bandwidth usage - if ($this->checkIfNoEpisodes($videoId) === false) { + if ($this->countEpsByVideoID($videoId) === false) { $this->getEpisodeInfo($tvdbid, -1, -1, '', $videoId); } // Check if we have the episode for this video ID $episode = $this->getBySeasonEp($videoId, $seasonNo, $episodeNo, $release['airdate']); - if ($episode === false && $lookupSetting) { // Send the request for the episode to TVDB $tvdbEpisode = $this->getEpisodeInfo( - $tvdbid, - $seasonNo, - $episodeNo, - $release['airdate'] + $tvdbid, + $seasonNo, + $episodeNo, + $release['airdate'] ); if ($tvdbEpisode) { $episode = $this->addEpisode( - $videoId, - $tvdbEpisode['season'], - $tvdbEpisode['episode'], - $tvdbEpisode['se_complete'], - $tvdbEpisode['title'], - $tvdbEpisode['firstaired'], - $tvdbEpisode['summary'] + $videoId, + $tvdbEpisode['season'], + $tvdbEpisode['episode'], + $tvdbEpisode['se_complete'], + $tvdbEpisode['title'], + $tvdbEpisode['firstaired'], + $tvdbEpisode['summary'] ); } } @@ -176,7 +181,7 @@ class TVDB extends TV // Mark the releases video and episode IDs $this->setVideoIdFound($videoId, $row['id'], $episode); if ($this->echooutput) { - echo $this->pdo->log->primary("Found TVDB Match!"); + echo $this->pdo->log->primary("Found TVDB Match!"); } continue; } @@ -187,12 +192,23 @@ class TVDB extends TV } } + /** + * Placeholder for Videos getBanner + * + * @param $videoID + * @param $siteId + * + * @return bool + */ protected function getBanner($videoID, $siteId) { return false; } /** + * Calls the API to perform initial show name match to TVDB title + * Returns a formatted array of show data or false if no match + * * @param $cleanName * * @return array|bool @@ -217,21 +233,24 @@ class TVDB extends TV } // Check each show title for similarity and then find the highest similar value - similar_text($show->name, $cleanName, $matchProb); + $matchPercent = $this->checkMatch($show->name, $cleanName, self::MATCH_PROBABILITY); if (NN_DEBUG) { - echo PHP_EOL . sprintf('Match Percentage: %d percent between %s and %s', $matchProb, $show->name, $cleanName) . PHP_EOL; + echo PHP_EOL . sprintf('Match Percentage: %d percent between %s and %s', $matchPercent, $show->name, $cleanName) . PHP_EOL; } - if ($matchProb >= self::MATCH_PROBABILITY && $matchProb > $highestMatch) { - $highestMatch = $matchProb; + // If new match has a higher percentage, set as new matched title + if ($matchPercent > $highestMatch) { + $highestMatch = $matchPercent; $highest = $show; } + + // Check for show aliases and try match those too if (is_array($show->aliasNames) && !empty($show->aliasNames)) { foreach ($show->aliasNames as $key => $name) { - similar_text($name, $cleanName, $matchProb); - if ($matchProb >= self::MATCH_PROBABILITY && $matchProb > $highestMatch) { - $highestMatch = $matchProb; + $matchPercent = $this->CheckMatch($name, $cleanName, $matchPercent); + if ($matchPercent > $highestMatch) { + $highestMatch = $matchPercent; $highest = $show; } } @@ -246,6 +265,8 @@ class TVDB extends TV } /** + * Retrieves the poster art for the processed show + * * @param $videoId * @param $showId * @@ -254,11 +275,11 @@ class TVDB extends TV protected function getPoster($videoId, $showId) { $hascover = (new ReleaseImage($this->pdo))->saveImage( - $videoId, - sprintf($this->posterUrl, $showId), - $this->imgSavePath, - '', - '' + $videoId, + sprintf($this->posterUrl, $showId), + $this->imgSavePath, + '', + '' ); if ($hascover == 1) { $this->setCoverFound($videoId); @@ -266,6 +287,9 @@ class TVDB extends TV } /** + * Gets the specific episode info for the parsed release after match + * Returns a formatted array of episode data or false if no match + * * @param integer $tvdbid * @param integer $season * @param integer $episode @@ -321,6 +345,9 @@ class TVDB extends TV } /** + * Assigns API show response values to a formatted array for insertion + * Returns the formatted array + * * @param $show * * @return array @@ -328,21 +355,25 @@ class TVDB extends TV private function formatShowArr($show) { $show->firstAired->setTimezone($this->timeZone); - preg_match('/tt(?P\d{7})$/i', $show->imdbId, $imdb); + preg_match('/tt(?P\d{6,7})$/i', $show->imdbId, $imdb); return [ - 'column' => (string)'tvdb', - 'siteid' => (int)$show->id, - 'title' => (string)$show->name, - 'summary' => (string)$show->overview, - 'started' => (string)$show->firstAired->format($this->timeFormat), - 'publisher' => (string)$show->network, - 'source' => (int)parent::SOURCE_TVDB, - 'imdbid' => (int)(isset($imdb['imdbid']) ? $imdb['imdbid'] : 0) - ]; + 'tvdbid' => (int)$show->id, + 'column' => 'tvdb', + 'siteid' => (int)$show->id, + 'title' => (string)$show->name, + 'summary' => (string)$show->overview, + 'started' => (string)$show->firstAired->format($this->timeFormat), + 'publisher' => (string)$show->network, + 'source' => (int)parent::SOURCE_TVDB, + 'imdbid' => (int)(isset($imdb['imdbid']) ? $imdb['imdbid'] : 0) + ]; } /** + * Assigns API episode response values to a formatted array for insertion + * Returns the formatted array + * * @param $episode * * @return array @@ -362,6 +393,9 @@ class TVDB extends TV } /** + * Checks API response returns have all REQUIRED attributes set + * Returns true or false + * * @param $array * @param $type * diff --git a/newznab/processing/tv/TvRage.php b/newznab/processing/tv/TvRage.php index af0bccf9b..f1db38c03 100644 --- a/newznab/processing/tv/TvRage.php +++ b/newznab/processing/tv/TvRage.php @@ -5,22 +5,69 @@ use newznab\utility\Utility; use newznab\ReleaseImage; /** - * Class TvRage + * Class TvRage - functions used to post process releases against TvRage */ class TvRage extends TV { + const APIKEY = '7FwjZ8loweFcOhHfnU3E'; const MATCH_PROBABILITY = 75; + /** + * @var array|bool|int|string + */ public $rageqty; + + /** + * @var string + */ public $showInfoUrl = 'http://www.tvrage.com/shows/id-'; + + /** + * @var string + */ public $showQuickInfoURL = 'http://services.tvrage.com/tools/quickinfo.php?show='; + + /** + * @var string + */ public $xmlFullSearchUrl = 'http://services.tvrage.com/feeds/full_search.php?show='; + + /** + * @var string + */ public $xmlShowInfoUrl = 'http://services.tvrage.com/feeds/showinfo.php?sid='; + + /** + * @var string + */ public $xmlFullShowInfoUrl = 'http://services.tvrage.com/feeds/full_show_info.php?sid='; + + /** + * @var string + */ public $xmlEpisodeInfoUrl; + + /** + * @var string + */ public $imgSavePath; + /** + * @var int|bool + */ + private $videoId; + + /** + * @var string + */ + private $posterUrl; + + /** + * @var + */ + private $rageId; + /** * @param array $options Class instances / Echo to cli? */ @@ -32,6 +79,14 @@ class TvRage extends TV $this->imgSavePath = NN_COVERS . 'tvrage' . DS; } + /** + * Main function to begin TvRage processing + * + * @param string $groupID + * @param string $guidChar + * @param int $lookupSetting + * @param bool|false $local + */ public function processTvRage($groupID = '', $guidChar = '', $lookupSetting = 1, $local = false) { $res = $this->getTvReleases($groupID, $guidChar, $local, parent::PROCESS_TVRAGE); @@ -44,47 +99,51 @@ class TvRage extends TV if ($res instanceof \Traversable) { foreach ($res as $arr) { + $this->rageId = $this->rageId = false; $show = $this->parseNameEpSeason($arr['searchname']); if (is_array($show) && $show['name'] != '') { // Find the Video ID if it already exists by checking the title. - $video = $this->getByTitle($show['cleanname']); + $this->videoId = $this->getByTitle($show['cleanname']); // Force local lookup only if ($local == true) { $lookupSetting = false; } - if ($video === false && $lookupSetting) { + if ($this->videoId === false && $lookupSetting) { // If it doesnt exist locally and lookups are allowed lets try to get it. if ($this->echooutput) { echo $this->pdo->log->primaryOver("Video ID for ") . $this->pdo->log->headerOver($show['cleanname']) . $this->pdo->log->primary(" not found in local db, checking web."); } - $tvrShow = $this->getRageMatch($show); + $tvrShow = $this->getShowInfo($show); if ($tvrShow !== false && is_array($tvrShow)) { // Get all tv info and add show. - $this->updateRageInfo($tvrShow['showid'], $tvrShow); + $this->rageId = $tvrShow['showid']; + $this->updateRageInfo($this->rageId, $tvrShow); } else { $this->setVideoNotFound(parent::PROCESS_TVMAZE, $arr['id']); } - } else if ($video > 0) { + } + if ($this->videoId > 0) { if ($this->echooutput) { echo $this->pdo->log->primaryOver("Video ID for ") . $this->pdo->log->headerOver($show['cleanname']) . $this->pdo->log->primary(" found in local db, setting tvrage ID and attempting episode lookup."); } - $episodeId = $this->getBySeasonEp($video['id'], $show['season'], $show['episode']); + $episodeId = $this->getBySeasonEp($this->videoId, $show['season'], $show['episode']); if ($episodeId === false) { - $epinfo = $this->getEpisodeInfo($video['tvrage'], $show['season'], $show['episode']); + $epinfo = $this->getEpisodeInfo($this->rageId, $show['season'], $show['episode']); if ($epinfo !== false && isset($epinfo['airdate']) && !empty($epinfo['title'])) { $tvairdate = $this->pdo->escapeString($this->checkDate($epinfo['airdate'])); $tvtitle = $this->pdo->escapeString(trim($epinfo['title'])); - $seComplete = 'S' . $show['season'] . 'E' . $show['episode']; - $episodeId = $this->addEpisode($video['id'], $show['season'], $show['episode'], $seComplete, $tvairdate, $tvtitle, ''); + $seComplete = 'S' . sprintf('%02s', $show['season']) . 'E' . sprintf('%02s', $show['episode']); + $episodeId = $this->addEpisode($this->videoId, $show['season'], $show['episode'], $seComplete, $tvairdate, $tvtitle, ''); } } - $this->setVideoIdFound($video, $arr['id'], $episodeId); + echo $this->pdo->log->primary("Found TV Rage Match!"); + $this->setVideoIdFound($this->videoId, $arr['id'], $episodeId); // Cant find videos_id, so set tv_episodes_id to PROCESS_TVMAZE. } else { $this->setVideoNotFound(parent::PROCESS_TVMAZE, $arr['id']); @@ -97,9 +156,49 @@ class TvRage extends TV } } + /** + * Placeholder for Videos getBanner + * + * @param $videoID + * @param $siteId + * + * @return bool + */ + protected function getBanner($videoID, $siteId) + { + return false; + } + + /** + * Retrieves poster image from TvRage through ReleaseImage + * + * @param int $videoId + * @param int $siteId + * + * @return null + */ + protected function getPoster($videoId, $siteId) + { + $hascover = (new ReleaseImage($this->pdo))->saveImage( + $videoId, + $this->posterUrl, + $this->imgSavePath, + '', + '' + ); + if ($hascover == 1) { + $this->setCoverFound($videoId); + } + } + + /** + * Formats and inserts the TvRage match and calls the download of the cover image + * + * @param $rageid + * @param $tvrShow + */ public function updateRageInfo($rageid, $tvrShow) { - $hasCover = 0; $country = ''; if (isset($tvrShow['country']) && !empty($tvrShow['country'])) { @@ -111,13 +210,35 @@ class TvRage extends TV if (isset($rInfo['desc']) && !empty($rInfo['desc'])) { $summary = $rInfo['desc']; } - + $this->videoId = $this->add( + $tvrShow['title'], + 'tvrage', + $rageid, + $summary, + $country, + $tvrShow['started'], + $tvrShow['publisher'], + parent::SOURCE_TVRAGE, + 0, + 0, + $rageid + ); if (isset($rInfo['imgurl']) && !empty($rInfo['imgurl'])) { - $hasCover = (new ReleaseImage($this->pdo))->saveImage($rageid, $rInfo['imgurl'], $this->imgSavePath, '', ''); + $this->posterUrl = $rInfo['imgurl']; + $this->getPoster($this->videoId, $this->rageId); } - $this->add('tvrage', $rageid, $tvrShow['title'], $summary, $country, $tvrShow['publisher'], $hasCover, parent::SOURCE_TVRAGE); } + /** + * Retrieves episode specific information once a RageID is matched + * Returns episode info array if matched, else false + * + * @param int $rageid + * @param int $series + * @param int $episode + * + * @return array|bool + */ public function getEpisodeInfo($rageid, $series, $episode) { $result = false; @@ -144,6 +265,9 @@ class TvRage extends TV } /** + * Scrapes additional fields not offered through the standard API + * Returns an array of additional params or false if no matched response + * * @param string $rageid * * @return array|bool|mixed @@ -151,7 +275,7 @@ class TvRage extends TV public function getRageInfoFromService($rageid) { $result = false; - // Full search gives us the akas. + // Standard show info search as AKAs not needed. $xml = Utility::getUrl(['url' => $this->xmlShowInfoUrl . $rageid]); if ($xml !== false) { $arrXml = Utility::objectsIntoArray(simplexml_load_string($xml)); @@ -165,6 +289,14 @@ class TvRage extends TV return $result; } + /** + * Queries for show description and the cover image info + * Returns an array of the additional parameters or seemingly useless array + * + * @param $rageid + * + * @return array + */ public function getRageInfoFromPage($rageid) { $result = ['desc' => '', 'imgurl' => '']; @@ -195,158 +327,104 @@ class TvRage extends TV return $result; } - public function getRageMatch($showInfo) + /** + * Main function for matching a releae searchname to a TvRage title + * Returns basic show information array or -1 int if no match + * + * @param $showInfo + * + * @return array|int + */ + public function getShowInfo($showInfo) { + $matchedTitle = -1; $title = $showInfo['cleanname']; // Full search gives us the akas. $xml = Utility::getUrl(['url' => $this->xmlFullSearchUrl . urlencode(strtolower($title))]); if ($xml !== false) { $arrXml = @Utility::objectsIntoArray(simplexml_load_string($xml)); - if (isset($arrXml['show']) && is_array($arrXml)) { - // We got a valid xml response - $titleMatches = $urlMatches = $akaMatches = []; + // CheckXML Response is valid before processing + if (isset($arrXml['show']) && is_array($arrXml)) { + + // We got exactly 1 match so lets convert it to an array so we can use it in the logic below. if (isset($arrXml['show']['showid'])) { - // We got exactly 1 match so lets convert it to an array so we can use it in the logic below. - $newArr = []; $newArr[] = $arrXml['show']; unset($arrXml); $arrXml['show'] = $newArr; } - foreach ($arrXml['show'] as $arr) { - $tvrlink = ''; + $highestPercent = 0; - // Get a match percentage based on our name and the name returned from tvr. - $titlepct = $this->checkMatch($title, $arr['name']); - if ($titlepct !== false) { - $titleMatches[$titlepct][] = [ - 'title' => $arr['name'], - 'showid' => $arr['showid'], - 'country' => $this->countryCode($arr['country']), - 'publisher' => $arr['network'], - 'started' => date('m-d-Y', strtotime($arr['started'])), - 'tvr' => $arr - ]; + foreach ($arrXml['show'] as $arr) { + + if ($title == $arr['name']) { + $matchedTitle = [ + 'title' => $arr['name'], + 'showid' => $arr['showid'], + 'country' => $this->countryCode($arr['country']), + 'publisher' => $arr['network'], + 'started' => date('Y-m-d', strtotime($arr['started'])), + 'tvr' => $arr + ]; + break; } - // Get a match percentage based on our name and the url returned from tvr. - if (isset($arr['link']) && preg_match('/tvrage\.com\/((?!shows)[^\/]*)$/i', $arr['link'], $tvrlink)) { - $urltitle = str_replace('_', ' ', $tvrlink[1]); - $urlpct = $this->checkMatch($title, $urltitle); - if ($urlpct !== false) { - $urlMatches[$urlpct][] = [ - 'title' => $urltitle, - 'showid' => $arr['showid'], - 'country' => $this->countryCode($arr['country']), - 'publisher' => $arr['network'], - 'started' => date('m-d-Y', strtotime($arr['started'])), - 'tvr' => $arr - ]; - } + // Get a match percentage based on our name and the name returned from tvr. + $matchPercent = $this->checkMatch($title, $arr['name'], self::MATCH_PROBABILITY); + if ($matchPercent > $highestPercent) { + $matchedTitle = [ + 'title' => $arr['name'], + 'showid' => $arr['showid'], + 'country' => $this->countryCode($arr['country']), + 'publisher' => $arr['network'], + 'started' => date('Y-m-d', strtotime($arr['started'])), + 'tvr' => $arr + ]; + $highestPercent = $matchPercent; } // Check if there are any akas for this result and get a match percentage for them too. if (isset($arr['akas']['aka'])) { if (is_array($arr['akas']['aka'])) { - // Multuple akas. + // Multiple akas. foreach ($arr['akas']['aka'] as $aka) { - $akapct = $this->checkMatch($title, $aka); - if ($akapct !== false) { - $akaMatches[$akapct][] = [ - 'title' => $aka, - 'showid' => $arr['showid'], - 'country' => $this->countryCode($arr['country']), - 'publisher' => $arr['network'], - 'started' => date('m-d-Y', strtotime($arr['started'])), - 'tvr' => $arr - ]; + $matchPercent = $this->checkMatch($title, $aka, self::MATCH_PROBABILITY); + if ($matchPercent > $highestPercent) { + $matchedTitle = [ + 'title' => $arr['name'], + 'showid' => $arr['showid'], + 'country' => $this->countryCode($arr['country']), + 'publisher' => $arr['network'], + 'started' => date('Y-m-d', strtotime($arr['started'])), + 'tvr' => $arr + ]; + $highestPercent = $matchPercent; } } } else { // One aka. - $akapct = $this->checkMatch($title, $arr['akas']['aka']); - if ($akapct !== false) { - $akaMatches[$akapct][] = [ - 'title' => $arr['akas']['aka'], - 'showid' => $arr['showid'], - 'country' => $this->countryCode($arr['country']), - 'publisher' => $arr['network'], - 'started' => date('m-d-Y', strtotime($arr['started'])), - 'tvr' => $arr - ]; + $matchPercent = $this->checkMatch($title, $arr['akas']['aka'], self::MATCH_PROBABILITY); + if ($matchPercent > $highestPercent) { + $matchedTitle = [ + 'title' => $arr['name'], + 'showid' => $arr['showid'], + 'country' => $this->countryCode($arr['country']), + 'publisher' => $arr['network'], + 'started' => date('Y-m-d', strtotime($arr['started'])), + 'tvr' => $arr + ]; + $highestPercent = $matchPercent; } } } } - - // Reverse sort our matches so highest matches are first. - krsort($titleMatches); - krsort($urlMatches); - krsort($akaMatches); - - // Look for 100% title matches first. - if (isset($titleMatches[100])) { - if ($this->echooutput) { - echo $this->pdo->log->primary('Found 100% match: "' . $titleMatches[100][0]['title'] . '"'); - } - return $titleMatches[100][0]; - } - - // Look for 100% url matches next. - if (isset($urlMatches[100])) { - if ($this->echooutput) { - echo $this->pdo->log->primary('Found 100% url match: "' . $urlMatches[100][0]['title'] . '"'); - } - return $urlMatches[100][0]; - } - - // Look for 100% aka matches next. - if (isset($akaMatches[100])) { - if ($this->echooutput) { - echo $this->pdo->log->primary('Found 100% aka match: "' . $akaMatches[100][0]['title'] . '"'); - } - return $akaMatches[100][0]; - } - - // No 100% matches, loop through what we got and if our next closest match is more than TvRage::MATCH_PROBABILITY % of the title lets take it. - foreach ($titleMatches as $mk => $mv) { - // Since its not 100 match if we have country info lets use that to make sure we get the right show. - if (isset($showInfo['country']) && !empty($showInfo['country']) && !empty($mv[0]['country'])) { - if (strtolower($showInfo['country']) != strtolower($mv[0]['country'])) { - continue; - } - } - - if ($this->echooutput) { - echo $this->pdo->log->primary('Found ' . $mk . '% match: "' . $titleMatches[$mk][0]['title'] . '"'); - } - return $titleMatches[$mk][0]; - } - - // Same as above but for akas. - foreach ($akaMatches as $ak => $av) { - if (isset($showInfo['country']) && !empty($showInfo['country']) && !empty($av[0]['country'])) { - if (strtolower($showInfo['country']) != strtolower($av[0]['country'])) { - continue; - } - } - - if ($this->echooutput) { - echo $this->pdo->log->primary('Found ' . $ak . '% aka match: "' . $akaMatches[$ak][0]['title'] . '"'); - } - return $akaMatches[$ak][0]; - } - - return false; } else { if ($this->echooutput) { echo $this->pdo->log->primary('Nothing returned from tvrage.'); } - return false; } - } else { - return -1; } + return $matchedTitle; } } diff --git a/www/admin/show-delete.php b/www/admin/show-delete.php index c6d703c2a..419cf27c7 100755 --- a/www/admin/show-delete.php +++ b/www/admin/show-delete.php @@ -1,12 +1,11 @@ $page->settings]))->delete($_GET['id']); + (new smartyTV(['Settings' => $page->settings]))->delete($_GET['id']); } $referrer = $_SERVER['HTTP_REFERER']; diff --git a/www/admin/show-edit.php b/www/admin/show-edit.php index 50352510b..b2e54fc55 100755 --- a/www/admin/show-edit.php +++ b/www/admin/show-edit.php @@ -1,11 +1,11 @@ $page->settings]); +$tv = new smartyTV(['Settings' => $page->settings]); $video = new Videos(['Settings' => $page->settings]); switch ((isset($_REQUEST['action']) ? $_REQUEST['action'] : 'view')) { diff --git a/www/pages/api.php b/www/pages/api.php index 5cfb8dede..ab2de93c7 100644 --- a/www/pages/api.php +++ b/www/pages/api.php @@ -1,17 +1,10 @@ users->isLoggedIn()) { if ($function != 'c' && $function != 'r') { if (!isset($_GET['apikey'])) { showApiError(200, 'Missing parameter (apikey)'); - } - $res = $page->users->getByRssToken($_GET['apikey']); - $apiKey = $_GET['apikey']; + } else { + $res = $page->users->getByRssToken($_GET['apikey']); + $apiKey = $_GET['apikey']; - if (!$res) { - showApiError(100, 'Incorrect user credentials (wrong API key)'); - } + if (!$res) { + showApiError(100, 'Incorrect user credentials (wrong API key)'); + } - $uid = $res['id']; - $catExclusions = $page->users->getCategoryExclusion($uid); - // - // A hash of the users ip to record against the api hit - // - if ($page->settings->getSetting('storeuserips') == 1) - $hosthash = $page->users->getHostHash($_SERVER["REMOTE_ADDR"], $page->settings->getSetting('siteseed')); - $maxRequests = $res['apirequests']; + $uid = $res['id']; + $catExclusions = $page->users->getCategoryExclusion($uid); + $maxRequests = $res['apirequests']; + } } } @@ -171,16 +135,30 @@ switch ($function) { $page->users->addApiRequest($uid, $_SERVER['REQUEST_URI']); $offset = offset(); + $siteIdArr = [ + 'id' => (isset($_GET['vid']) ? $_GET['vid'] : '0'), + 'tvdb' => (isset($_GET['tvdbid']) ? $_GET['tvdbid'] : '0'), + 'trakt' => (isset($_GET['traktid']) ? $_GET['traktid'] : '0'), + 'tvrage' => (isset($_GET['rid']) ? $_GET['rid'] : '0'), + 'tvmaze' => (isset($_GET['tvmazeid']) ? $_GET['tvmazeid'] : '0'), + 'imdb' => (isset($_GET['imdbid']) ? $_GET['imdbid'] : '0'), + 'tmdb' => (isset($_GET['tmdbid']) ? $_GET['tmdbid'] : '0') + ]; + + if (isset($_GET['season']) && isset($_GET['ep'])) { + if (preg_match('#\d{4}#i', $_GET['season'], $year) && stripos($_GET['ep'], '/') !== false) { + $airdate = $year[0] . '/' . $_GET['ep']; + } else { + $series = $_GET['season']; + $episode = $_GET['ep']; + } + } + $relData = $releases->searchShows( - (isset($_GET['vid']) ? $_GET['vid'] : '0'), - (isset($_GET['tvdbid']) ? $_GET['tvdbid'] : '0'), - (isset($_GET['traktid']) ? $_GET['traktid'] : '0'), - (isset($_GET['rid']) ? $_GET['rid'] : '0'), - (isset($_GET['tvmazeid']) ? $_GET['tvmazeid'] : '0'), - (isset($_GET['imdbid']) ? $_GET['imdbid'] : '0'), - (isset($_GET['tmdbid']) ? $_GET['tmdbid'] : '0'), - (isset($_GET['season']) ? $_GET['season'] : ''), - (isset($_GET['ep']) ? $_GET['ep'] : ''), + $siteIdArr, + (isset($series) ? $series : ''), + (isset($episode) ? $episode : ''), + (isset($airdate) ? $airdate : ''), $offset, limit(), (isset($_GET['q']) ? $_GET['q'] : ''), @@ -192,181 +170,6 @@ switch ($function) { printOutput($relData, $outputXML, $page, $offset); break; - // - // get nfo - // - case "gn": - if (!isset($_GET["id"])) - showApiError(200); - - $page->users->addApiRequest($uid, $_SERVER['REQUEST_URI']); - - $relData = $releases->getByGuid($_GET["id"]); - if (!$relData) - showApiError(300); - - $nfo = $releases->getReleaseNfo($relData["id"], true); - if (!$nfo) - showApiError(300); - - $nforaw = Utility::cp437toUTF($nfo["nfo"]); - $page->smarty->assign('release',$relData); - $page->smarty->assign('nfo',$nfo); - $page->smarty->assign('nfoutf',$nforaw); - - if (isset($_GET["raw"])) - { - header("Content-type: text/x-nfo"); - header("Content-Disposition: attachment; filename=".str_replace(" ", "_", $relData["searchname"]).".nfo"); - echo $nforaw; - die(); - } - else - { - $page->smarty->assign('rsstitle',"NFO"); - $page->smarty->assign('rssdesc',"NFO"); - $content = trim($page->smarty->fetch('apinfo.tpl')); - - printOutput($relData, $outputXML, $page, $offset); - } - break; - - // - // get comments - // - case "co": - if (!isset($_GET["id"])) - showApiError(200); - - $page->users->addApiRequest($uid, $_SERVER['REQUEST_URI']); - - $data = $rc->getCommentsByGuid($_GET["id"]); - if ($data) - $relData = $data; - else - $relData = []; - - $page->smarty->assign('comments',$relData); - $page->smarty->assign('rsstitle',"API Comments"); - $page->smarty->assign('rssdesc',"API Comments"); - $content = trim($page->smarty->fetch('apicomments.tpl')); - - printOutput($relData, $outputXML, $page, $offset); - - break; - - // - // add comment - // - case "ca": - if (!isset($_GET["id"])) - showApiError(200); - - if (!isset($_GET["text"])) - showApiError(200); - - $page->users->addApiRequest($uid, $_SERVER['REQUEST_URI']); - - $relData = $releases->getByGuid($_GET["id"]); - if ($relData) - { - $ret = $rc->addComment($relData["id"], $relData["gid"], $_GET["text"], $uid, $_SERVER['REMOTE_ADDR']); - - $content = "\n"; - $content.= "\n"; - - printOutput($content, $outputXML, $page); - } - else - { - showApiError(300); - } - - break; - - // - // search book releases - // - case "b": - if (isset($_GET["author"]) && $_GET["author"]=="" && isset($_GET["title"]) && $_GET["title"]=="") - showApiError(200); - - $maxage = -1; - if (isset($_GET["maxage"])) - { - if ($_GET["maxage"]=="") - showApiError(200); - elseif (!is_numeric($_GET["maxage"])) - showApiError(201); - else - $maxage = $_GET["maxage"]; - } - - $page->users->addApiRequest($uid, $_SERVER['REQUEST_URI']); - - $limit = 100; - if (isset($_GET["limit"]) && is_numeric($_GET["limit"]) && $_GET["limit"] < 100) - $limit = $_GET["limit"]; - - $offset = 0; - if (isset($_GET["offset"]) && is_numeric($_GET["offset"])) - $offset = $_GET["offset"]; - $relData = $releases->searchBook((isset($_GET["author"]) ? $_GET["author"] : ""), (isset($_GET["title"]) ? $_GET["title"] : ""), $offset, $limit, $maxage ); - - $page->smarty->assign('offset',$offset); - $page->smarty->assign('releases',$relData); - $output = trim($page->smarty->fetch('apiresult.tpl')); - - printOutput($relData, $outputXML, $page, $offset); - break; - - // - // search music releases - // - case "mu": - if (isset($_GET["artist"]) && $_GET["artist"]=="" && isset($_GET["album"]) && $_GET["album"]=="") - showApiError(200); - $categoryId = []; - if (isset($_GET["cat"])) - $categoryId = explode(",",$_GET["cat"]); - else - $categoryId[] = -1; - - $maxage = -1; - if (isset($_GET["maxage"])) - { - if ($_GET["maxage"]=="") - showApiError(200); - elseif (!is_numeric($_GET["maxage"])) - showApiError(201); - else - $maxage = $_GET["maxage"]; - } - - $genreId = []; - if (isset($_GET["genre"])) - $genreId = explode(",",$_GET["genre"]); - else - $genreId[] = -1; - - $page->users->addApiRequest($uid, $_SERVER['REQUEST_URI']); - - $limit = 100; - if (isset($_GET["limit"]) && is_numeric($_GET["limit"]) && $_GET["limit"] < 100) - $limit = $_GET["limit"]; - - $offset = 0; - if (isset($_GET["offset"]) && is_numeric($_GET["offset"])) - $offset = $_GET["offset"]; - $relData = $releases->searchAudio((isset($_GET["artist"]) ? $_GET["artist"] : ""), (isset($_GET["album"]) ? $_GET["album"] : ""), (isset($_GET["label"]) ? $_GET["label"] : ""), (isset($_GET["track"]) ? $_GET["track"] : ""), (isset($_GET["year"]) ? $_GET["year"] : ""), $genreId, $offset, $limit, $categoryId, $maxage ); - - $page->smarty->assign('offset',$offset); - $page->smarty->assign('releases',$relData); - $output = trim($page->smarty->fetch('apiresult.tpl')); - - printOutput($relData, $outputXML, $page, $offset); - break; - // Search movie releases. case 'm': verifyEmptyParameter('q'); @@ -387,7 +190,7 @@ switch ($function) { ); addCoverURL($relData, - function ($release) { + function($release) { return Utility::getCoverURL(['type' => 'movies', 'id' => $release['imdbid']]); } ); @@ -439,13 +242,13 @@ switch ($function) { // Capabilities request. case 'c': + //get categories $category = new Category(['Settings' => $page->settings]); - $page->smarty->assign('parentcatlist', $category->getForMenu()); - $group = $groups->getActive(); - $page->smarty->assign('grps', $group); - $genre = $genres->getGenres('', true); - $page->smarty->assign('genres', $genre); - header('Content-type: text/xml'); + $cats = $category->getForMenu(); + + //insert cats into template variable + $page->smarty->assign('parentcatlist', $cats); + if ($outputXML) { //use apicaps.tpl if xml is requested $response = $page->smarty->fetch('apicaps.tpl'); header('Content-type: text/xml'); @@ -462,7 +265,6 @@ switch ($function) { echo $response; } break; - // Register request. case 'r': verifyEmptyParameter('email'); @@ -488,7 +290,7 @@ switch ($function) { // Register. $userDefault = $page->users->getDefaultRole(); - $uid = $page->users->signup( + $uid = $page->users->signUp( $username, $password, $_GET['email'], $_SERVER['REMOTE_ADDR'], $userDefault['id'], $userDefault['defaultinvites'] ); @@ -498,13 +300,15 @@ switch ($function) { showApiError(107); } - header('Content-type: text/xml'); - echo + $response = "\n" . '\n"; + header('Content-type: text/xml'); + header('Content-Length: ' . strlen($response) ); + echo $response; break; } @@ -568,9 +372,14 @@ function showApiError($errorCode = 900, $errorText = '') } } + $response = + "\n" . + '\n"; header('Content-type: text/xml'); - header('X-newznab: API ERROR [' . $errorCode . '] ' . $errorText); - exit("\n\n"); + header('Content-Length: ' . strlen($response) ); + header('X-nZEDb: API ERROR [' . $errorCode . '] ' . $errorText); + + exit($response); } /** @@ -601,7 +410,7 @@ function categoryID() $categoryID[] = -1; if (isset($_GET['cat'])) { $categoryIDs = urldecode($_GET['cat']); - // Append Web-DL category ID if HD present for SickBeard / NZBDrone compatibility. + // Append Web-DL category ID if HD present for SickBeard / Sonarr compatibility. if (strpos($categoryIDs, (string)Category::CAT_TV_HD) !== false && strpos($categoryIDs, (string)Category::CAT_TV_WEBDL) === false) { $categoryIDs .= (',' . Category::CAT_TV_WEBDL); @@ -655,13 +464,9 @@ function printOutput($data, $xml = true, $page, $offset = 0) echo $response; } else { $response = encodeAsJSON($data); - if ($response != false) { - header('Content-type: application/json'); - header('Content-Length: ' . strlen($response)); - echo $response; - } else { - echo 'No data returned or error occured'; - } + header('Content-type: application/json'); + header('Content-Length: ' . strlen($response)); + echo $response; } } diff --git a/www/pages/series.php b/www/pages/series.php index 1cef2eec3..26948fcc0 100644 --- a/www/pages/series.php +++ b/www/pages/series.php @@ -20,10 +20,10 @@ if (isset($_GET["id"]) && ctype_digit($_GET['id'])) { $category = $_REQUEST["t"]; } - $catarray = []; + $catarray = array(); $catarray[] = $category; - $rel = $releases->searchShows($_GET["id"], 0, 0, 0, 0, 0, 0, '', '', 0, 1000, "", $catarray, -1); + $rel = $releases->searchShows(['id' => $_GET["id"]], '', '', '', 0, 1000, '', $catarray, -1); $show = $tvshow->getByVideoID($_GET['id']); if (!$show) { @@ -34,7 +34,7 @@ if (isset($_GET["id"]) && ctype_digit($_GET['id'])) { $myshows = $us->getShow($page->users->currentUserId(), $show['id']); // Sort releases by season, episode, date posted. - $series = $episode = $posted = []; + $series = $episode = $posted = array(); foreach ($rel as $rlk => $rlv) { $series[$rlk] = $rlv['series']; $episode[$rlk] = $rlv['episode']; @@ -42,7 +42,7 @@ if (isset($_GET["id"]) && ctype_digit($_GET['id'])) { } array_multisort($series, SORT_DESC, $episode, SORT_DESC, $posted, SORT_DESC, $rel); - $series = []; + $series = array(); foreach ($rel as $r) { $series[$r['series']][$r['episode']][] = $r; } @@ -52,13 +52,11 @@ if (isset($_GET["id"]) && ctype_digit($_GET['id'])) { $page->smarty->assign('myshows', $myshows); //get series name(s), description, country and genre - $seriestitles = $seriesdescription = $seriescountry = []; + $seriestitles = $seriesdescription = $seriescountry = array(); $seriestitles[] = $show['title']; - if (is_array($show['summary']) && !empty($show['summary'])) { - $seriessummary = $show['summary'][0]; - } else { - $seriessummary = $show['summary']; + if (!empty($show['summary'])) { + $seriessummary[] = $show['summary']; } if (!empty($show['countries_id'])) { @@ -67,7 +65,7 @@ if (isset($_GET["id"]) && ctype_digit($_GET['id'])) { $seriestitles = implode('/', array_map("trim", $seriestitles)); $page->smarty->assign('seriestitles', $seriestitles); - $page->smarty->assign('seriessummary', $seriessummary); + $page->smarty->assign('seriessummary', array_shift($seriessummary)); $page->smarty->assign('seriescountry', array_shift($seriescountry)); $page->title = "Series"; @@ -81,7 +79,6 @@ if (isset($_GET["id"]) && ctype_digit($_GET['id'])) { } else { $cdata = array('title' => ''); $catid = ''; - $page->smarty->assign("catname", "All"); } $page->smarty->assign('catname', $cdata['title']); $page->smarty->assign('category', $catid); diff --git a/www/pages/smartyTV.php b/www/pages/smartyTV.php new file mode 100644 index 000000000..533d34978 --- /dev/null +++ b/www/pages/smartyTV.php @@ -0,0 +1,68 @@ +. + * @author niel + * @copyright 2015 nZEDb + */ +require_once '../../newznab/processing/tv/TV.php'; + +use newznab\processing\tv\TV; + +class smartyTV extends TV +{ + protected function getBanner($videoID, $siteId) + { + } + + /** + * Retrieve info of TV episode from site using its API. + * + * @param integer $siteId + * @param integer $series + * @param integer $episode + * + * @return array|false False on failure, an array of information fields otherwise. + */ + protected function getEpisodeInfo($siteId, $series, $episode) + { + } + + /** + * Retrieve poster image for TV episode from site using its API. + * + * @param integer $videoId ID from videos table. + * @param integer $siteId ID that this site uses for the programme. + * + * @return null + */ + protected function getPoster($videoId, $siteId) + { + } + + /** + * Retrieve info of TV programme from site using it's API. + * + * @param string $name Title of programme to look up. Usually a cleaned up version from releases table. + * + * @return array|false False on failure, an array of information fields otherwise. + */ + protected function getShowInfo($name) + { + } +} + +?> diff --git a/www/themes/charisma/templates/frontend/apicaps.tpl b/www/themes/charisma/templates/frontend/apicaps.tpl index 3be9a5a85..9822ca4fa 100644 --- a/www/themes/charisma/templates/frontend/apicaps.tpl +++ b/www/themes/charisma/templates/frontend/apicaps.tpl @@ -1,37 +1,24 @@ - style != "/"}{$serverroot}theme/{$site->style}/images/banner.jpg{else}{$serverroot}images/banner.jpg{/if}"/> + - + + + - - - - + + + + + {foreach from=$parentcatlist item=parentcat} - + {foreach from=$parentcat.subcatlist item=subcat} - + {/foreach} {/foreach} - - {foreach from=$grps item=grp} - - {/foreach} - - - {foreach from=$genres item=genre} - - {/foreach} - \ No newline at end of file diff --git a/www/themes/charisma/templates/frontend/apidetail.tpl b/www/themes/charisma/templates/frontend/apidetail.tpl index 3c51bed9b..ae60551fe 100644 --- a/www/themes/charisma/templates/frontend/apidetail.tpl +++ b/www/themes/charisma/templates/frontend/apidetail.tpl @@ -1,8 +1,7 @@ - + - + {$site->title|escape} {$site->title|escape} Api Detail {$serverroot} @@ -19,121 +18,67 @@ {$release.searchname} {$serverroot}details/{$release.guid} - {$serverroot}getnzb/{$release.guid}.nzb&i={$uid} - &r={$rsstoken}{if $del=="1"}&del=1{/if} + {$serverroot}getnzb/{$release.guid}.nzb&i={$uid}&r={$rsstoken}{if $del=="1"}&del=1{/if} {$serverroot}details/{$release.guid}#comments {$release.adddate|phpdate_format:"DATE_RSS"} {$release.category_name|escape:html} {$release.searchname} - + {foreach from=$release.category_ids|parray:"," item=cat} - + {/foreach} - - - - - {if $release.season != ""} - - {/if} - {if $release.episode != ""} - - {/if} - {if $release.videos_id != "-1" && $release.videos_id != "-2"} - + + + + {if $release.videos_id > 0 && $release.tv_episodes_id > 0} + {if $release.title != ""} - + {/if} - {if $result.firstaired != ""} - + {if $release.series > 0} + + {/if} + {if $release.episode > 0} + + {/if} + {if $release.firstaired != ""} + + {/if} + {if $release.tvdb > 0} + + {/if} + {if $release.trakt > 0} + + {/if} + {if $release.tvrage > 0} + + + {/if} + {if $release.tvmaze > 0} + + {/if} + {if $release.imdb > 0} + {/if} {/if} {if $release.imdbid != ""} - + {/if} - {if $mov.title != ""} - + {if $release.tmdb > 0} + {/if} - {if $mov.tagline != ""} - + {if $release.anidbid > 0} + {/if} - {if $mov.plot != ""} - + + + + + + {if $release.coverurl != ""} + {/if} - {if $mov.rating != ""} - - {/if} - {if $mov.genre != ""} - - {/if} - {if $mov.year != ""} - - {/if} - {if $mov.director != ""} - - {/if} - {if $mov.actors != ""} - - {/if} - {if $mov.cover == 1} - - {/if} - {if $mov.backdrop == 1} - - {/if} - {if $release.musicinfoid != "" && $release.mi_title != ""} - - {/if} - {if $release.musicinfoid != "" && $release.mi_artist != ""} - - {/if} - {if $release.musicinfoid != "" && $release.mi_publisher != ""} - - {/if} - {if $release.musicinfoid != "" && $release.mi_tracks != ""} - - {/if} - {if $release.musicinfoid != "" && $release.mi_review != ""} - - {/if} - {if $release.musicinfoid != "" && $release.mi_cover == "1"} - - {/if} - {if $release.musicinfoid != "" && $release.music_genrename != ""} - - {/if} - {if $release.bookinfoid != "" && $release.bi_author != ""} - - {/if} - {if $release.bookinfoid != "" && $release.bi_title != ""} - - {/if} - {if $release.bookinfoid != "" && $release.bi_cover == "1"} - - {/if} - {if $release.bookinfoid != "" && $release.bi_review != ""} - - {/if} - {if $release.bookinfoid != "" && $release.bi_publishdate != ""} - - {/if} - {if $release.bookinfoid != "" && $release.bi_publisher != ""} - - {/if} - {if $release.bookinfoid != "" && $release.bi_pages != ""} - - {/if} - {if $release.bookinfoid != "" && $release.bi_isbn != ""} - - {/if} - - - - - {/foreach} - \ No newline at end of file + diff --git a/www/themes/charisma/templates/frontend/apiresult.tpl b/www/themes/charisma/templates/frontend/apiresult.tpl index f18cd13a7..b5615612e 100644 --- a/www/themes/charisma/templates/frontend/apiresult.tpl +++ b/www/themes/charisma/templates/frontend/apiresult.tpl @@ -1,8 +1,7 @@ - + - + {$site->title|escape} {$site->title|escape} API Results {$serverroot} @@ -15,7 +14,7 @@ {$serverroot} Visit {$site->title|escape} - {$site->strapline|escape} - + {foreach from=$releases item=release} {$release.searchname|escape:html} @@ -25,41 +24,63 @@ {$release.adddate|phpdate_format:"DATE_RSS"} {$release.category_name|escape:html} {$release.searchname|escape:html} - + {foreach from=$release.category_ids|parray:"," item=cat} - + {/foreach} - + {if isset($release.coverurl) && $release.coverurl != ""} - + {/if} {if $extended == "1"} - - - {if $release.series != ""} - - {/if} - {if $release.episode != ""} - - {/if} - {if $release.videos_id > 0} + + + {if $release.videos_id > 0 && $release.tv_episodes_id > 0} - {/if} - {if $release.title != ""} - - {/if} - {if $release.firstaired != ""} - + + {if $release.title != ""} + + {/if} + {if $release.series > 0} + + {/if} + {if $release.episode > 0} + + {/if} + {if $release.firstaired != ''} + + {/if} + {if $release.tvdb > 0} + + {/if} + {if $release.trakt > 0} + + {/if} + {if $release.tvrage > 0} + + + {/if} + {if $release.tvmaze > 0} + + {/if} + {if $release.imdb > 0} + + {/if} + {if $release.tmdb > 0} + + {/if} {/if} {if $release.imdbid != ""} - + {/if} - - - - - + {if $release.anidbid > 0} + + {/if} + + + + + {/if} {/foreach} diff --git a/www/themes/omicron/templates/frontend/apicaps.tpl b/www/themes/omicron/templates/frontend/apicaps.tpl index 8cdd2a482..9822ca4fa 100644 --- a/www/themes/omicron/templates/frontend/apicaps.tpl +++ b/www/themes/omicron/templates/frontend/apicaps.tpl @@ -1,37 +1,24 @@ - style != "/"}{$serverroot}theme/{$site->style}/images/banner.jpg{else}{$serverroot}images/banner.jpg{/if}"/> + - + + + - - - - + + + + + {foreach from=$parentcatlist item=parentcat} - + {foreach from=$parentcat.subcatlist item=subcat} - + {/foreach} {/foreach} - - {foreach from=$grps item=grp} - - {/foreach} - - - {foreach from=$genres item=genre} - - {/foreach} - \ No newline at end of file diff --git a/www/themes/omicron/templates/frontend/apidetail.tpl b/www/themes/omicron/templates/frontend/apidetail.tpl index da0d625e3..ae60551fe 100644 --- a/www/themes/omicron/templates/frontend/apidetail.tpl +++ b/www/themes/omicron/templates/frontend/apidetail.tpl @@ -1,8 +1,7 @@ - + - + {$site->title|escape} {$site->title|escape} Api Detail {$serverroot} @@ -19,121 +18,67 @@ {$release.searchname} {$serverroot}details/{$release.guid} - {$serverroot}getnzb/{$release.guid}.nzb&i={$uid} - &r={$rsstoken}{if $del=="1"}&del=1{/if} + {$serverroot}getnzb/{$release.guid}.nzb&i={$uid}&r={$rsstoken}{if $del=="1"}&del=1{/if} {$serverroot}details/{$release.guid}#comments {$release.adddate|phpdate_format:"DATE_RSS"} {$release.category_name|escape:html} {$release.searchname} - + {foreach from=$release.category_ids|parray:"," item=cat} - + {/foreach} - - - - - {if $release.season != ""} - - {/if} - {if $release.episode != ""} - - {/if} - {if $release.videos_id != "-1" && $release.videos_id != "-2"} - + + + + {if $release.videos_id > 0 && $release.tv_episodes_id > 0} + {if $release.title != ""} - + + {/if} + {if $release.series > 0} + + {/if} + {if $release.episode > 0} + {/if} {if $release.firstaired != ""} - + + {/if} + {if $release.tvdb > 0} + + {/if} + {if $release.trakt > 0} + + {/if} + {if $release.tvrage > 0} + + + {/if} + {if $release.tvmaze > 0} + + {/if} + {if $release.imdb > 0} + {/if} {/if} {if $release.imdbid != ""} - + {/if} - {if $mov.title != ""} - + {if $release.tmdb > 0} + {/if} - {if $mov.tagline != ""} - + {if $release.anidbid > 0} + {/if} - {if $mov.plot != ""} - + + + + + + {if $release.coverurl != ""} + {/if} - {if $mov.rating != ""} - - {/if} - {if $mov.genre != ""} - - {/if} - {if $mov.year != ""} - - {/if} - {if $mov.director != ""} - - {/if} - {if $mov.actors != ""} - - {/if} - {if $mov.cover == 1} - - {/if} - {if $mov.backdrop == 1} - - {/if} - {if $release.musicinfoid != "" && $release.mi_title != ""} - - {/if} - {if $release.musicinfoid != "" && $release.mi_artist != ""} - - {/if} - {if $release.musicinfoid != "" && $release.mi_publisher != ""} - - {/if} - {if $release.musicinfoid != "" && $release.mi_tracks != ""} - - {/if} - {if $release.musicinfoid != "" && $release.mi_review != ""} - - {/if} - {if $release.musicinfoid != "" && $release.mi_cover == "1"} - - {/if} - {if $release.musicinfoid != "" && $release.music_genrename != ""} - - {/if} - {if $release.bookinfoid != "" && $release.bi_author != ""} - - {/if} - {if $release.bookinfoid != "" && $release.bi_title != ""} - - {/if} - {if $release.bookinfoid != "" && $release.bi_cover == "1"} - - {/if} - {if $release.bookinfoid != "" && $release.bi_review != ""} - - {/if} - {if $release.bookinfoid != "" && $release.bi_publishdate != ""} - - {/if} - {if $release.bookinfoid != "" && $release.bi_publisher != ""} - - {/if} - {if $release.bookinfoid != "" && $release.bi_pages != ""} - - {/if} - {if $release.bookinfoid != "" && $release.bi_isbn != ""} - - {/if} - - - - - {/foreach} - \ No newline at end of file + diff --git a/www/themes/omicron/templates/frontend/apiresult.tpl b/www/themes/omicron/templates/frontend/apiresult.tpl index f18cd13a7..b5615612e 100644 --- a/www/themes/omicron/templates/frontend/apiresult.tpl +++ b/www/themes/omicron/templates/frontend/apiresult.tpl @@ -1,8 +1,7 @@ - + - + {$site->title|escape} {$site->title|escape} API Results {$serverroot} @@ -15,7 +14,7 @@ {$serverroot} Visit {$site->title|escape} - {$site->strapline|escape} - + {foreach from=$releases item=release} {$release.searchname|escape:html} @@ -25,41 +24,63 @@ {$release.adddate|phpdate_format:"DATE_RSS"} {$release.category_name|escape:html} {$release.searchname|escape:html} - + {foreach from=$release.category_ids|parray:"," item=cat} - + {/foreach} - + {if isset($release.coverurl) && $release.coverurl != ""} - + {/if} {if $extended == "1"} - - - {if $release.series != ""} - - {/if} - {if $release.episode != ""} - - {/if} - {if $release.videos_id > 0} + + + {if $release.videos_id > 0 && $release.tv_episodes_id > 0} - {/if} - {if $release.title != ""} - - {/if} - {if $release.firstaired != ""} - + + {if $release.title != ""} + + {/if} + {if $release.series > 0} + + {/if} + {if $release.episode > 0} + + {/if} + {if $release.firstaired != ''} + + {/if} + {if $release.tvdb > 0} + + {/if} + {if $release.trakt > 0} + + {/if} + {if $release.tvrage > 0} + + + {/if} + {if $release.tvmaze > 0} + + {/if} + {if $release.imdb > 0} + + {/if} + {if $release.tmdb > 0} + + {/if} {/if} {if $release.imdbid != ""} - + {/if} - - - - - + {if $release.anidbid > 0} + + {/if} + + + + + {/if} {/foreach}