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
+ example.com API results
+
+
+
+
+
+ -
+
+ 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}