diff --git a/gui/slick/views/config_general.mako b/gui/slick/views/config_general.mako index 7ba2e140106051a99565f9183671a4a18d9b3743..ddba429bc05e201ae75328411fb3def7f7031462 100644 --- a/gui/slick/views/config_general.mako +++ b/gui/slick/views/config_general.mako @@ -618,7 +618,7 @@ <span class="component-title">Use proxy for indexers</span> <span class="component-desc"> <input type="checkbox" name="proxy_indexers" id="proxy_indexers" ${('', 'checked="checked"')[bool(sickbeard.PROXY_INDEXERS)]}/> - <p>use proxy host for connecting to indexers (thetvdb, tvrage)</p> + <p>use proxy host for connecting to indexers (thetvdb)</p> </span> </label> </div> diff --git a/gui/slick/views/home_addShows.mako b/gui/slick/views/home_addShows.mako index 689fa78208a6385d0562d0ee3d1694a3574dcf8f..09b79ae5f2c00b8eadd51676d3e8425aad6e668a 100644 --- a/gui/slick/views/home_addShows.mako +++ b/gui/slick/views/home_addShows.mako @@ -16,7 +16,7 @@ <div class="button"><div class="icon-addnewshow"></div></div> <div class="buttontext"> <h3>Add New Show</h3> - <p>For shows that you haven't downloaded yet, this option finds a show on theTVDB.com and TVRage.com, creates a directory for its episodes, and adds it to SickRage.</p> + <p>For shows that you haven't downloaded yet, this option finds a show on theTVDB.com, creates a directory for it's episodes, and adds it to SickRage.</p> </div> </a> diff --git a/gui/slick/views/home_newShow.mako b/gui/slick/views/home_newShow.mako index feac31ed28a42af1e5e2c9d14f1adcda1096604c..75f827b2898d70ecaa7017be07fe5920962671b9 100644 --- a/gui/slick/views/home_newShow.mako +++ b/gui/slick/views/home_newShow.mako @@ -33,7 +33,7 @@ <form id="addShowForm" method="post" action="${sbRoot}/home/addShows/addNewShow" accept-charset="utf-8"> <fieldset class="sectionwrap"> - <legend class="legendStep">Find a show on the TVDB or TVRAGE</legend> + <legend class="legendStep">Find a show on theTVDB</legend> <div class="stepDiv"> <input type="hidden" id="indexer_timeout" value="${sickbeard.INDEXER_TIMEOUT}" /> @@ -54,7 +54,7 @@ <option value="0" ${('', 'selected="selected"')[provided_indexer == 0]}>All Indexers</option> % for indexer in indexers: <option value="${indexer}" ${('', 'selected="selected"')[provided_indexer == indexer]}> - ${(indexers[indexer], ''.join((indexers[indexer], ' **')))[indexers[indexer] == 'TVRage']} + ${indexers[indexer]} </option> % endfor </select> @@ -63,9 +63,7 @@ <br /><br /> <b>*</b> This will only affect the language of the retrieved metadata file contents and episode filenames.<br /> - This <b>DOES NOT</b> allow SickRage to download non-english TV episodes!<br /> - <b>** IMPORTANT: </b> TVRAGE indexer implementation doesn't currently support <b>specials</b> and <b>banners/posters</b>.<br /> - <br /> + This <b>DOES NOT</b> allow SickRage to download non-english TV episodes!<br /><br /> <div id="searchResults" style="height: 100%;"><br/></div> % endif diff --git a/gui/slick/views/trendingShows.mako b/gui/slick/views/trendingShows.mako index 3d37297a2b8c9bcc4cc3001d553364c1f1bdd474..6db8fe07f6ac6b50a11e3daf3c74f3af64c56e57 100644 --- a/gui/slick/views/trendingShows.mako +++ b/gui/slick/views/trendingShows.mako @@ -91,10 +91,10 @@ $(document).ready(function(){ <p>${int(cur_show['show']['rating']*10)}% <img src="${sbRoot}/images/heart.png"></p> <i>${cur_show['show']['votes']} votes</i> <div class="traktShowTitleIcons"> - <a href="${sbRoot}/home/addShows/addTraktShow?indexer_id=${cur_show['show']['ids']['tvdb'] or cur_show['show']['ids']['tvrage']}&showName=${cur_show['show']['title']}" class="btn btn-xs">Add Show</a> -% if blacklist: + <a href="${sbRoot}/home/addShows/addTraktShow?indexer_id=${cur_show['show']['ids']['tvdb']}&showName=${cur_show['show']['title']}" class="btn btn-xs">Add Show</a> + % if blacklist: <a href="${sbRoot}/home/addShows/addShowToBlacklist?indexer_id=${cur_show['show']['ids']['tvdb'] or cur_show['show']['ids']['tvrage']}" class="btn btn-xs">Remove Show</a> -% endif + % endif </div> </div> </div> diff --git a/lib/tmdb_api/test_tmdb_api.py b/lib/tmdb_api/test_tmdb_api.py index 21f70a273a03b566d834872a735eb5097a2982af..e3e9dfb76d5cd657dbb0f3db156980a763626523 100644 --- a/lib/tmdb_api/test_tmdb_api.py +++ b/lib/tmdb_api/test_tmdb_api.py @@ -23,12 +23,11 @@ except ImportError: class TVCheck(unittest.TestCase): def testTVInfo(self): - id = 1396 - name = 'UFC' + name = u'Game of Thrones' tmdb = TMDB(TMDB_API_KEY) - find = tmdb.Find(23281) - response = find.info({'external_source': 'tvrage_id'}) - self.assertTrue(hasattr(response, name)) + find = tmdb.Find(121361) + response = find.info({'external_source': 'tvdb_id'}) + self.assertEqual(response['tv_results'][0]['name'], name) def testTVSearch(self): id = 1396 diff --git a/lib/tvrage_api/__init__.py b/lib/tvrage_api/__init__.py deleted file mode 100644 index fb885164122f148a54b0d6a323475490f19f792c..0000000000000000000000000000000000000000 --- a/lib/tvrage_api/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ - -__version__ = '1.0' -__author__ = 'echel0n' -__license__ = 'BSD' diff --git a/lib/tvrage_api/tvrage_api.py b/lib/tvrage_api/tvrage_api.py deleted file mode 100644 index 89923d11705cb3c99ec9978ca56e0b01a5c14f4c..0000000000000000000000000000000000000000 --- a/lib/tvrage_api/tvrage_api.py +++ /dev/null @@ -1,722 +0,0 @@ -# !/usr/bin/env python2 -# encoding:utf-8 -# author:echel0n -# project:tvrage_api -#repository:http://github.com/echel0n/tvrage_api -#license:unlicense (http://unlicense.org/) - -""" -Modified from http://github.com/dbr/tvrage_api -Simple-to-use Python interface to The TVRage's API (tvrage.com) -""" -from functools import wraps -import traceback - -__author__ = "echel0n" -__version__ = "1.0" - -import os -import re -import time -import getpass -import tempfile -import warnings -import logging -import datetime as dt -import requests -from requests import exceptions -import xmltodict - -try: - import xml.etree.cElementTree as ElementTree -except ImportError: - import xml.etree.ElementTree as ElementTree - -from dateutil.parser import parse -from cachecontrol import CacheControl, caches - -from tvrage_ui import BaseUI -from tvrage_exceptions import (tvrage_error, tvrage_userabort, tvrage_shownotfound, tvrage_showincomplete, - tvrage_seasonnotfound, tvrage_episodenotfound, tvrage_attributenotfound) - - -def log(): - return logging.getLogger("tvrage_api") - - -def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None): - """Retry calling the decorated function using an exponential backoff. - - http://www.saltycrane.com/blog/2009/11/trying-out-retry-decorator-python/ - original from: http://wiki.python.org/moin/PythonDecoratorLibrary#Retry - - :param ExceptionToCheck: the exception to check. may be a tuple of - exceptions to check - :type ExceptionToCheck: Exception or tuple - :param tries: number of times to try (not retry) before giving up - :type tries: int - :param delay: initial delay between retries in seconds - :type delay: int - :param backoff: backoff multiplier e.g. value of 2 will double the delay - each retry - :type backoff: int - :param logger: logger to use. If None, print - :type logger: logging.Logger instance - """ - - def deco_retry(f): - - @wraps(f) - def f_retry(*args, **kwargs): - mtries, mdelay = tries, delay - while mtries > 1: - try: - return f(*args, **kwargs) - except ExceptionToCheck, e: - msg = "%s, Retrying in %d seconds..." % (str(e), mdelay) - if logger: - logger.warning(msg) - else: - print msg - time.sleep(mdelay) - mtries -= 1 - mdelay *= backoff - return f(*args, **kwargs) - - return f_retry # true decorator - - return deco_retry - - -class ShowContainer(dict): - """Simple dict that holds a series of Show instances - """ - - def __init__(self): - self._stack = [] - self._lastgc = time.time() - - def __setitem__(self, key, value): - self._stack.append(key) - - #keep only the 100th latest results - if time.time() - self._lastgc > 20: - for o in self._stack[:-100]: - del self[o] - - self._stack = self._stack[-100:] - - self._lastgc = time.time() - - super(ShowContainer, self).__setitem__(key, value) - - -class Show(dict): - """Holds a dict of seasons, and show data. - """ - - def __init__(self): - dict.__init__(self) - self.data = {} - - def __repr__(self): - return "<Show %s (containing %s seasons)>" % ( - self.data.get(u'seriesname', 'instance'), - len(self) - ) - - def __getattr__(self, key): - if key in self: - # Key is an episode, return it - return self[key] - - if key in self.data: - # Non-numeric request is for show-data - return self.data[key] - - raise AttributeError - - def __getitem__(self, key): - if key in self: - # Key is an episode, return it - return dict.__getitem__(self, key) - - if key in self.data: - # Non-numeric request is for show-data - return dict.__getitem__(self.data, key) - - # Data wasn't found, raise appropriate error - if isinstance(key, int) or key.isdigit(): - # Episode number x was not found - raise tvrage_seasonnotfound("Could not find season %s" % (repr(key))) - else: - # If it's not numeric, it must be an attribute name, which - # doesn't exist, so attribute error. - raise tvrage_attributenotfound("Cannot find attribute %s" % (repr(key))) - - def airedOn(self, date): - ret = self.search(str(date), 'firstaired') - if len(ret) == 0: - raise tvrage_episodenotfound("Could not find any episodes that aired on %s" % date) - return ret - - def search(self, term=None, key=None): - """ - Search all episodes in show. Can search all data, or a specific key (for - example, episodename) - - Always returns an array (can be empty). First index contains the first - match, and so on. - - Each array index is an Episode() instance, so doing - search_results[0]['episodename'] will retrieve the episode name of the - first match. - - Search terms are converted to lower case (unicode) strings. - """ - results = [] - for cur_season in self.values(): - searchresult = cur_season.search(term=term, key=key) - if len(searchresult) != 0: - results.extend(searchresult) - - return results - - -class Season(dict): - def __init__(self, show=None): - """The show attribute points to the parent show - """ - self.show = show - - def __repr__(self): - return "<Season instance (containing %s episodes)>" % ( - len(self.keys()) - ) - - def __getattr__(self, episode_number): - if episode_number in self: - return self[episode_number] - raise AttributeError - - def __getitem__(self, episode_number): - if episode_number not in self: - raise tvrage_episodenotfound("Could not find episode %s" % (repr(episode_number))) - else: - return dict.__getitem__(self, episode_number) - - def search(self, term=None, key=None): - """Search all episodes in season, returns a list of matching Episode - instances. - """ - results = [] - for ep in self.values(): - searchresult = ep.search(term=term, key=key) - if searchresult is not None: - results.append( - searchresult - ) - return results - - -class Episode(dict): - def __init__(self, season=None): - """The season attribute points to the parent season - """ - self.season = season - - def __repr__(self): - seasno = int(self.get(u'seasonnumber', 0)) - epno = int(self.get(u'episodenumber', 0)) - epname = self.get(u'episodename') - if epname is not None: - return "<Episode %02dx%02d - %s>" % (seasno, epno, epname) - else: - return "<Episode %02dx%02d>" % (seasno, epno) - - def __getattr__(self, key): - if key in self: - return self[key] - raise AttributeError - - def __getitem__(self, key): - try: - return dict.__getitem__(self, key) - except KeyError: - raise tvrage_attributenotfound("Cannot find attribute %s" % (repr(key))) - - def search(self, term=None, key=None): - """Search episode data for term, if it matches, return the Episode (self). - The key parameter can be used to limit the search to a specific element, - for example, episodename. - - This primarily for use use by Show.search and Season.search. - """ - if term == None: - raise TypeError("must supply string to search for (contents)") - - term = unicode(term).lower() - for cur_key, cur_value in self.items(): - cur_key, cur_value = unicode(cur_key).lower(), unicode(cur_value).lower() - if key is not None and cur_key != key: - # Do not search this key - continue - if cur_value.find(unicode(term).lower()) > -1: - return self - - -class TVRage: - """Create easy-to-use interface to name of season/episode name""" - - def __init__(self, - interactive=False, - select_first=False, - debug=False, - cache=True, - banners=False, - actors=False, - custom_ui=None, - language=None, - search_all_languages=False, - apikey=None, - forceConnect=False, - useZip=False, - dvdorder=False, - proxy=None): - - """ - cache (True/False/str/unicode/urllib2 opener): - Retrieved XML are persisted to to disc. If true, stores in - tvrage_api folder under your systems TEMP_DIR, if set to - str/unicode instance it will use this as the cache - location. If False, disables caching. Can also be passed - an arbitrary Python object, which is used as a urllib2 - opener, which should be created by urllib2.build_opener - - forceConnect (bool): - If true it will always try to connect to tvrage.com even if we - recently timed out. By default it will wait one minute before - trying again, and any requests within that one minute window will - return an exception immediately. - """ - - self.shows = ShowContainer() # Holds all Show classes - self.corrections = {} # Holds show-name to show_id mapping - - self.config = {} - - if apikey is not None: - self.config['apikey'] = apikey - else: - self.config['apikey'] = "Uhewg1Rr0o62fvZvUIZt" # tvdb_api's API key - - self.config['debug_enabled'] = debug # show debugging messages - - self.config['custom_ui'] = custom_ui - - self.config['proxy'] = proxy - - if cache is True: - self.config['cache_enabled'] = True - self.config['cache_location'] = self._getTempDir() - elif cache is False: - self.config['cache_enabled'] = False - elif isinstance(cache, basestring): - self.config['cache_enabled'] = True - self.config['cache_location'] = cache - else: - raise ValueError("Invalid value for Cache %r (type was %s)" % (cache, type(cache))) - - self.config['session'] = requests.Session() - - if self.config['debug_enabled']: - warnings.warn("The debug argument to tvrage_api.__init__ will be removed in the next version. " - "To enable debug messages, use the following code before importing: " - "import logging; logging.basicConfig(level=logging.DEBUG)") - logging.basicConfig(level=logging.DEBUG) - - - # List of language from http://tvrage.com/api/0629B785CE550C8D/languages.xml - # Hard-coded here as it is realtively static, and saves another HTTP request, as - # recommended on http://tvrage.com/wiki/index.php/API:languages.xml - self.config['valid_languages'] = [ - "da", "fi", "nl", "de", "it", "es", "fr", "pl", "hu", "el", "tr", - "ru", "he", "ja", "pt", "zh", "cs", "sl", "hr", "ko", "en", "sv", "no" - ] - - # tvrage.com should be based around numeric language codes, - # but to link to a series like http://tvrage.com/?tab=series&id=79349&lid=16 - # requires the language ID, thus this mapping is required (mainly - # for usage in tvrage_ui - internally tvrage_api will use the language abbreviations) - self.config['langabbv_to_id'] = {'el': 20, 'en': 7, 'zh': 27, - 'it': 15, 'cs': 28, 'es': 16, 'ru': 22, 'nl': 13, 'pt': 26, 'no': 9, - 'tr': 21, 'pl': 18, 'fr': 17, 'hr': 31, 'de': 14, 'da': 10, 'fi': 11, - 'hu': 19, 'ja': 25, 'he': 24, 'ko': 32, 'sv': 8, 'sl': 30} - - if language is None: - self.config['language'] = 'en' - else: - if language not in self.config['valid_languages']: - raise ValueError("Invalid language %s, options are: %s" % ( - language, self.config['valid_languages'] - )) - else: - self.config['language'] = language - - # The following url_ configs are based of the - # http://tvrage.com/wiki/index.php/Programmers_API - - self.config['base_url'] = "http://services.tvrage.com" - - self.config['url_getSeries'] = u"%(base_url)s/feeds/search.php" % self.config - self.config['params_getSeries'] = {"show": ""} - - self.config['url_epInfo'] = u"%(base_url)s/myfeeds/episode_list.php" % self.config - self.config['params_epInfo'] = {"key": self.config['apikey'], "sid": ""} - - self.config['url_seriesInfo'] = u"%(base_url)s/myfeeds/showinfo.php" % self.config - self.config['params_seriesInfo'] = {"key": self.config['apikey'], "sid": ""} - - self.config['url_updtes_all'] = u"%(base_url)s/myfeeds/currentshows.php" % self.config - - def _getTempDir(self): - """Returns the [system temp dir]/tvrage_api-u501 (or - tvrage_api-myuser) - """ - if hasattr(os, 'getuid'): - uid = "u%d" % (os.getuid()) - else: - # For Windows - try: - uid = getpass.getuser() - except ImportError: - return os.path.join(tempfile.gettempdir(), "tvrage_api") - - return os.path.join(tempfile.gettempdir(), "tvrage_api-%s" % (uid)) - - @retry(tvrage_error) - def _loadUrl(self, url, params=None): - try: - log().debug("Retrieving URL %s" % url) - - # get response from TVRage - if self.config['cache_enabled']: - session = CacheControl(sess=self.config['session'], cache=caches.FileCache(self.config['cache_location']), cache_etags=False) - if self.config['proxy']: - log().debug("Using proxy for URL: %s" % url) - session.proxies = { - "http": self.config['proxy'], - "https": self.config['proxy'], - } - - resp = session.get(url.strip(), params=params) - else: - resp = requests.get(url.strip(), params=params) - - resp.raise_for_status() - except requests.exceptions.HTTPError, e: - raise tvrage_error("HTTP error " + str(e.errno) + " while loading URL " + str(url)) - except requests.exceptions.ConnectionError, e: - raise tvrage_error("Connection error " + str(e.message) + " while loading URL " + str(url)) - except requests.exceptions.Timeout, e: - raise tvrage_error("Connection timed out " + str(e.message) + " while loading URL " + str(url)) - except Exception: - raise tvrage_error("Unknown exception while loading URL " + url + ": " + traceback.format_exc()) - - def remap_keys(path, key, value): - name_map = { - 'showid': 'id', - 'showname': 'seriesname', - 'name': 'seriesname', - 'summary': 'overview', - 'started': 'firstaired', - 'genres': 'genre', - 'airtime': 'airs_time', - 'airday': 'airs_dayofweek', - 'image': 'fanart', - 'epnum': 'absolute_number', - 'title': 'episodename', - 'airdate': 'firstaired', - 'screencap': 'filename', - 'seasonnum': 'episodenumber' - } - - status_map = { - 'returning series': 'Continuing', - 'canceled/ended': 'Ended', - 'tbd/on the bubble': 'Continuing', - 'in development': 'Continuing', - 'new series': 'Continuing', - 'never aired': 'Ended', - 'final season': 'Continuing', - 'on hiatus': 'Continuing', - 'pilot ordered': 'Continuing', - 'pilot rejected': 'Ended', - 'canceled': 'Ended', - 'ended': 'Ended', - '': 'Unknown', - } - - try: - key = name_map[key.lower()] - except (ValueError, TypeError, KeyError): - key = key.lower() - - # clean up value and do type changes - if value: - if isinstance(value, dict): - if key == 'status': - try: - value = status_map[str(value).lower()] - if not value: - raise - except: - value = 'Unknown' - - if key == 'network': - value = value['#text'] - - if key == 'genre': - value = value['genre'] - if not value: - value = [] - if not isinstance(value, list): - value = [value] - value = filter(None, value) - value = '|' + '|'.join(value) + '|' - - try: - if key == 'firstaired' and value in "0000-00-00": - new_value = str(dt.date.fromordinal(1)) - new_value = re.sub("([-]0{2}){1,}", "", new_value) - fixDate = parse(new_value, fuzzy=True).date() - value = fixDate.strftime("%Y-%m-%d") - elif key == 'firstaired': - value = parse(value, fuzzy=True).date() - value = value.strftime("%Y-%m-%d") - except: - pass - - return (key, value) - - try: - return xmltodict.parse(resp.content.decode('utf-8'), postprocessor=remap_keys) - except: - return dict([(u'data', None)]) - - def _getetsrc(self, url, params=None): - """Loads a URL using caching, returns an ElementTree of the source - """ - - try: - return self._loadUrl(url, params).values()[0] - except Exception, e: - raise tvrage_error(e) - - def _setItem(self, sid, seas, ep, attrib, value): - """Creates a new episode, creating Show(), Season() and - Episode()s as required. Called by _getShowData to populate show - - Since the nice-to-use tvrage[1][24]['name] interface - makes it impossible to do tvrage[1][24]['name] = "name" - and still be capable of checking if an episode exists - so we can raise tvrage_shownotfound, we have a slightly - less pretty method of setting items.. but since the API - is supposed to be read-only, this is the best way to - do it! - The problem is that calling tvrage[1][24]['episodename'] = "name" - calls __getitem__ on tvrage[1], there is no way to check if - tvrage.__dict__ should have a key "1" before we auto-create it - """ - if sid not in self.shows: - self.shows[sid] = Show() - if seas not in self.shows[sid]: - self.shows[sid][seas] = Season(show=self.shows[sid]) - if ep not in self.shows[sid][seas]: - self.shows[sid][seas][ep] = Episode(season=self.shows[sid][seas]) - self.shows[sid][seas][ep][attrib] = value - - def _setShowData(self, sid, key, value): - """Sets self.shows[sid] to a new Show instance, or sets the data - """ - if sid not in self.shows: - self.shows[sid] = Show() - self.shows[sid].data[key] = value - - def _cleanData(self, data): - """Cleans up strings returned by tvrage.com - - Issues corrected: - - Replaces & with & - - Trailing whitespace - """ - - if isinstance(data, basestring): - data = data.replace(u"&", u"&") - data = data.strip() - - return data - - def search(self, series): - """This searches tvrage.com for the series name - and returns the result list - """ - series = series.encode("utf-8") - log().debug("Searching for show %s" % series) - self.config['params_getSeries']['show'] = series - - results = self._getetsrc(self.config['url_getSeries'], self.config['params_getSeries']) - if not results: - return - - return results.values()[0] - - def _getSeries(self, series): - """This searches tvrage.com for the series name, - If a custom_ui UI is configured, it uses this to select the correct - series. If not, and interactive == True, ConsoleUI is used, if not - BaseUI is used to select the first result. - """ - allSeries = self.search(series) - if not allSeries: - log().debug('Series result returned zero') - raise tvrage_shownotfound("Show search returned zero results (cannot find show on TVRAGE)") - - if not isinstance(allSeries, list): - allSeries = [allSeries] - - if self.config['custom_ui'] is not None: - log().debug("Using custom UI %s" % (repr(self.config['custom_ui']))) - CustomUI = self.config['custom_ui'] - ui = CustomUI(config=self.config) - else: - log().debug('Auto-selecting first search result using BaseUI') - ui = BaseUI(config=self.config) - - return ui.selectSeries(allSeries) - - def _getShowData(self, sid, getEpInfo=False): - """Takes a series ID, gets the epInfo URL and parses the TVRAGE - XML file into the shows dict in layout: - shows[series_id][season_number][episode_number] - """ - - # Parse show information - log().debug('Getting all series data for %s' % (sid)) - self.config['params_seriesInfo']['sid'] = sid - seriesInfoEt = self._getetsrc( - self.config['url_seriesInfo'], - self.config['params_seriesInfo'] - ) - - if not seriesInfoEt: - log().debug('Series result returned zero') - raise tvrage_error("Series result returned zero") - - # get series data - for k, v in seriesInfoEt.items(): - if v is not None: - v = self._cleanData(v) - - self._setShowData(sid, k, v) - - # get episode data - if getEpInfo: - # Parse episode data - log().debug('Getting all episodes of %s' % (sid)) - self.config['params_epInfo']['sid'] = sid - epsEt = self._getetsrc(self.config['url_epInfo'], self.config['params_epInfo']) - - if not epsEt: - log().debug('Series results incomplete') - raise tvrage_showincomplete( - "Show search returned incomplete results (cannot find complete show on TVRAGE)") - - if 'episodelist' not in epsEt: - return False - - seasons = epsEt['episodelist']['season'] - if not isinstance(seasons, list): - seasons = [seasons] - - for season in seasons: - seas_no = int(season['@no']) - - episodes = season['episode'] - if not isinstance(episodes, list): - episodes = [episodes] - - for episode in episodes: - ep_no = int(episode['episodenumber']) - - for k, v in episode.items(): - k = k.lower() - - if v is not None: - if k == 'link': - v = v.rsplit('/', 1)[1] - k = 'id' - else: - v = self._cleanData(v) - - self._setItem(sid, seas_no, ep_no, k, v) - - return True - - def _nameToSid(self, name): - """Takes show name, returns the correct series ID (if the show has - already been grabbed), or grabs all episodes and returns - the correct SID. - """ - if name in self.corrections: - log().debug('Correcting %s to %s' % (name, self.corrections[name])) - return self.corrections[name] - else: - log().debug('Getting show %s' % (name)) - selected_series = self._getSeries(name) - if isinstance(selected_series, dict): - selected_series = [selected_series] - sids = list(int(x['id']) for x in selected_series if self._getShowData(int(x['id']))) - self.corrections.update(dict((x['seriesname'], int(x['id'])) for x in selected_series)) - return sids - - def __getitem__(self, key): - """Handles tvrage_instance['seriesname'] calls. - The dict index should be the show id - """ - if isinstance(key, (int, long)): - # Item is integer, treat as show id - if key not in self.shows: - self._getShowData(key, True) - return self.shows[key] - - key = str(key).lower() - self.config['searchterm'] = key - selected_series = self._getSeries(key) - if isinstance(selected_series, dict): - selected_series = [selected_series] - [[self._setShowData(show['id'], k, v) for k, v in show.items()] for show in selected_series] - return selected_series - #test = self._getSeries(key) - #sids = self._nameToSid(key) - #return list(self.shows[sid] for sid in sids) - - def __repr__(self): - return str(self.shows) - - -def main(): - """Simple example of using tvrage_api - it just - grabs an episode name interactively. - """ - import logging - - logging.basicConfig(level=logging.DEBUG) - - tvrage_instance = TVRage(cache=False) - print tvrage_instance['Lost']['seriesname'] - print tvrage_instance['Lost'][1][4]['episodename'] - - -if __name__ == '__main__': - main() diff --git a/lib/tvrage_api/tvrage_cache.py b/lib/tvrage_api/tvrage_cache.py deleted file mode 100644 index 9f58ff864e29c9f3a86a41e74b5b6a461eb93ad5..0000000000000000000000000000000000000000 --- a/lib/tvrage_api/tvrage_cache.py +++ /dev/null @@ -1,251 +0,0 @@ -#!/usr/bin/env python2 -#encoding:utf-8 -#author:echel0n -#project:tvrage_api -#repository:http://github.com/echel0n/tvrage_api -#license:unlicense (http://unlicense.org/) - -""" -urllib2 caching handler -Modified from http://code.activestate.com/recipes/491261/ -""" -from __future__ import with_statement - -__author__ = "echel0n" -__version__ = "1.0" - -import os -import time -import errno -import httplib -import urllib2 -import StringIO -from hashlib import md5 -from threading import RLock - -cache_lock = RLock() - -def locked_function(origfunc): - """Decorator to execute function under lock""" - def wrapped(*args, **kwargs): - cache_lock.acquire() - try: - return origfunc(*args, **kwargs) - finally: - cache_lock.release() - return wrapped - -def calculate_cache_path(cache_location, url): - """Checks if [cache_location]/[hash_of_url].headers and .body exist - """ - thumb = md5(url).hexdigest() - header = os.path.join(cache_location, thumb + ".headers") - body = os.path.join(cache_location, thumb + ".body") - return header, body - -def check_cache_time(path, max_age): - """Checks if a file has been created/modified in the [last max_age] seconds. - False means the file is too old (or doesn't exist), True means it is - up-to-date and valid""" - if not os.path.isfile(path): - return False - cache_modified_time = os.stat(path).st_mtime - time_now = time.time() - if cache_modified_time < time_now - max_age: - # Cache is old - return False - else: - return True - -@locked_function -def exists_in_cache(cache_location, url, max_age): - """Returns if header AND body cache file exist (and are up-to-date)""" - hpath, bpath = calculate_cache_path(cache_location, url) - if os.path.exists(hpath) and os.path.exists(bpath): - return( - check_cache_time(hpath, max_age) - and check_cache_time(bpath, max_age) - ) - else: - # File does not exist - return False - -@locked_function -def store_in_cache(cache_location, url, response): - """Tries to store response in cache.""" - hpath, bpath = calculate_cache_path(cache_location, url) - try: - outf = open(hpath, "wb") - headers = str(response.info()) - outf.write(headers) - outf.close() - - outf = open(bpath, "wb") - outf.write(response.read()) - outf.close() - except IOError: - return True - else: - return False - -@locked_function -def delete_from_cache(cache_location, url): - """Deletes a response in cache.""" - hpath, bpath = calculate_cache_path(cache_location, url) - try: - if os.path.exists(hpath): - os.remove(hpath) - if os.path.exists(bpath): - os.remove(bpath) - except IOError: - return True - else: - return False - -class CacheHandler(urllib2.BaseHandler): - """Stores responses in a persistant on-disk cache. - - If a subsequent GET request is made for the same URL, the stored - response is returned, saving time, resources and bandwidth - """ - @locked_function - def __init__(self, cache_location, max_age = 21600): - """The location of the cache directory""" - self.max_age = max_age - self.cache_location = cache_location - if not os.path.exists(self.cache_location): - try: - os.mkdir(self.cache_location) - except OSError, e: - if e.errno == errno.EEXIST and os.path.isdir(self.cache_location): - # File exists, and it's a directory, - # another process beat us to creating this dir, that's OK. - pass - else: - # Our target dir is already a file, or different error, - # relay the error! - raise - - def default_open(self, request): - """Handles GET requests, if the response is cached it returns it - """ - if request.get_method() != "GET": - return None # let the next handler try to handle the request - - if exists_in_cache( - self.cache_location, request.get_full_url(), self.max_age - ): - return CachedResponse( - self.cache_location, - request.get_full_url(), - set_cache_header = True - ) - else: - return None - - def http_response(self, request, response): - """Gets a HTTP response, if it was a GET request and the status code - starts with 2 (200 OK etc) it caches it and returns a CachedResponse - """ - if (request.get_method() == "GET" - and str(response.code).startswith("2") - ): - if 'x-local-cache' not in response.info(): - # Response is not cached - set_cache_header = store_in_cache( - self.cache_location, - request.get_full_url(), - response - ) - else: - set_cache_header = True - - return CachedResponse( - self.cache_location, - request.get_full_url(), - set_cache_header = set_cache_header - ) - else: - return response - -class CachedResponse(StringIO.StringIO): - """An urllib2.response-like object for cached responses. - - To determine if a response is cached or coming directly from - the network, check the x-local-cache header rather than the object type. - """ - - @locked_function - def __init__(self, cache_location, url, set_cache_header=True): - self.cache_location = cache_location - hpath, bpath = calculate_cache_path(cache_location, url) - - StringIO.StringIO.__init__(self, file(bpath, "rb").read()) - - self.url = url - self.code = 200 - self.msg = "OK" - headerbuf = file(hpath, "rb").read() - if set_cache_header: - headerbuf += "x-local-cache: %s\r\n" % (bpath) - self.headers = httplib.HTTPMessage(StringIO.StringIO(headerbuf)) - - def info(self): - """Returns headers - """ - return self.headers - - def geturl(self): - """Returns original URL - """ - return self.url - - @locked_function - def recache(self): - new_request = urllib2.urlopen(self.url) - set_cache_header = store_in_cache( - self.cache_location, - new_request.url, - new_request - ) - CachedResponse.__init__(self, self.cache_location, self.url, True) - - @locked_function - def delete_cache(self): - delete_from_cache( - self.cache_location, - self.url - ) - - -if __name__ == "__main__": - def main(): - """Quick test/example of CacheHandler""" - opener = urllib2.build_opener(CacheHandler("/tmp/")) - response = opener.open("http://google.com") - print response.headers - print "Response:", response.read() - - response.recache() - print response.headers - print "After recache:", response.read() - - # Test usage in threads - from threading import Thread - class CacheThreadTest(Thread): - lastdata = None - def run(self): - req = opener.open("http://google.com") - newdata = req.read() - if self.lastdata is None: - self.lastdata = newdata - assert self.lastdata == newdata, "Data was not consistent, uhoh" - req.recache() - threads = [CacheThreadTest() for x in range(50)] - print "Starting threads" - [t.start() for t in threads] - print "..done" - print "Joining threads" - [t.join() for t in threads] - print "..done" - main() diff --git a/lib/tvrage_api/tvrage_exceptions.py b/lib/tvrage_api/tvrage_exceptions.py deleted file mode 100644 index 69b918b6447bdfd8b0011ddd7f7bddfae38e51e4..0000000000000000000000000000000000000000 --- a/lib/tvrage_api/tvrage_exceptions.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python2 -# encoding:utf-8 -#author:echel0n -#project:tvrage_api -#repository:http://github.com/echel0n/tvrage_api -#license:unlicense (http://unlicense.org/) - -"""Custom exceptions used or raised by tvrage_api""" - -__author__ = "echel0n" -__version__ = "1.0" - -__all__ = ["tvrage_error", "tvrage_userabort", "tvrage_shownotfound", "tvrage_showincomplete", - "tvrage_seasonnotfound", "tvrage_episodenotfound", "tvrage_attributenotfound"] - - -class tvrage_exception(Exception): - """Any exception generated by tvrage_api - """ - pass - - -class tvrage_error(tvrage_exception): - """An error with tvrage.com (Cannot connect, for example) - """ - pass - - -class tvrage_userabort(tvrage_exception): - """User aborted the interactive selection (via - the q command, ^c etc) - """ - pass - - -class tvrage_shownotfound(tvrage_exception): - """Show cannot be found on tvrage.com (non-existant show) - """ - pass - - -class tvrage_showincomplete(tvrage_exception): - """Show found but incomplete on tvrage.com (incomplete show) - """ - pass - - -class tvrage_seasonnotfound(tvrage_exception): - """Season cannot be found on tvrage.com - """ - pass - - -class tvrage_episodenotfound(tvrage_exception): - """Episode cannot be found on tvrage.com - """ - pass - - -class tvrage_attributenotfound(tvrage_exception): - """Raised if an episode does not have the requested - attribute (such as a episode name) - """ - pass diff --git a/lib/tvrage_api/tvrage_ui.py b/lib/tvrage_api/tvrage_ui.py deleted file mode 100644 index 64e54d6e0b2c75289f140c7469feaa290dc46ef1..0000000000000000000000000000000000000000 --- a/lib/tvrage_api/tvrage_ui.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python2 -#encoding:utf-8 -#author:echel0n -#project:tvrage_api -#repository:http://github.com/echel0n/tvrage_api -#license:unlicense (http://unlicense.org/) - -"""Contains included user interface for TVRage show selection""" - -__author__ = "echel0n" -__version__ = "1.0" - -import logging -import warnings - -def log(): - return logging.getLogger(__name__) - -class BaseUI: - """Default non-interactive UI, which auto-selects first results - """ - def __init__(self, config, log = None): - self.config = config - if log is not None: - warnings.warn("the UI's log parameter is deprecated, instead use\n" - "use import logging; logging.getLogger('ui').info('blah')\n" - "The self.log attribute will be removed in the next version") - self.log = logging.getLogger(__name__) - - def selectSeries(self, allSeries): - return allSeries[0] \ No newline at end of file diff --git a/readme.md b/readme.md index 4779a9fc73dd58c2737f6d5695e6b7f7dc7edc4a..3c6d1fdb3f2de833a16e9905cc14aa407d32652f 100644 --- a/readme.md +++ b/readme.md @@ -12,11 +12,10 @@ Automatic Video Library Manager for TV Shows. It watches for new episodes of you - Automatic torrent/nzb searching, downloading, and processing at the qualities you want - Largest list of supported torrent and nzb providers, both public and private - Can notify Kodi, XBMC, Growl, Trakt, Twitter, and more when new episodes are available - - Searches TheTVDB.com, TVRage.com, and AniDB.net for shows, seasons, episodes, and metadata + - Searches TheTVDB.com and AniDB.net for shows, seasons, episodes, and metadata - Episode status management allows for mass failing seasons/episodes to force retrying - DVD Order numbering for returning the results in DVD order instead of Air-By-Date order - Allows you to choose which indexer to have SickRage search its show info from when importing - - SickRage can easily tell if info for an existing show comes from TheTVDB or TVRage when importing - Automatic XEM Scene Numbering/Naming for seasons/episodes - Available for any platform, uses a simple HTTP interface - Specials and multi-episode torrent/nzb support diff --git a/sickbeard/indexers/indexer_config.py b/sickbeard/indexers/indexer_config.py index f19cd68cd004cf8cab602667614ad3e93af7383b..ee1d77a95f8bbf28d97823005d9afc37b1c69400 100644 --- a/sickbeard/indexers/indexer_config.py +++ b/sickbeard/indexers/indexer_config.py @@ -1,8 +1,9 @@ from tvdb_api.tvdb_api import Tvdb -from tvrage_api.tvrage_api import TVRage import requests INDEXER_TVDB = 1 + +#Must keep INDEXER_TVRAGE = 2 initConfig = {} @@ -10,13 +11,15 @@ indexerConfig = {} initConfig['valid_languages'] = [ "da", "fi", "nl", "de", "it", "es", "fr", "pl", "hu", "el", "tr", - "ru", "he", "ja", "pt", "zh", "cs", "sl", "hr", "ko", "en", "sv", "no"] + "ru", "he", "ja", "pt", "zh", "cs", "sl", "hr", "ko", "en", "sv", "no" +] initConfig['langabbv_to_id'] = { 'el': 20, 'en': 7, 'zh': 27, 'it': 15, 'cs': 28, 'es': 16, 'ru': 22, 'nl': 13, 'pt': 26, 'no': 9, 'tr': 21, 'pl': 18, 'fr': 17, 'hr': 31, 'de': 14, 'da': 10, 'fi': 11, - 'hu': 19, 'ja': 25, 'he': 24, 'ko': 32, 'sv': 8, 'sl': 30} + 'hu': 19, 'ja': 25, 'he': 24, 'ko': 32, 'sv': 8, 'sl': 30 +} indexerConfig[INDEXER_TVDB] = { 'id': INDEXER_TVDB, @@ -25,17 +28,7 @@ indexerConfig[INDEXER_TVDB] = { 'api_params': {'apikey': 'F9C450E78D99172E', 'language': 'en', 'useZip': True, - }, - 'session': requests.Session() -} - -indexerConfig[INDEXER_TVRAGE] = { - 'id': INDEXER_TVRAGE, - 'name': 'TVRage', - 'module': TVRage, - 'api_params': {'apikey': 'Uhewg1Rr0o62fvZvUIZt', - 'language': 'en', - }, + }, 'session': requests.Session() } @@ -46,11 +39,3 @@ indexerConfig[INDEXER_TVDB]['icon'] = 'thetvdb16.png' indexerConfig[INDEXER_TVDB]['scene_loc'] = 'http://sickragetv.github.io/sb_tvdb_scene_exceptions/exceptions.txt' indexerConfig[INDEXER_TVDB]['show_url'] = 'http://thetvdb.com/?tab=series&id=' indexerConfig[INDEXER_TVDB]['base_url'] = 'http://thetvdb.com/api/%(apikey)s/series/' % indexerConfig[INDEXER_TVDB]['api_params'] - -# TVRAGE Indexer Settings -indexerConfig[INDEXER_TVRAGE]['trakt_id'] = 'tvrage_id' -indexerConfig[INDEXER_TVRAGE]['xem_origin'] = 'rage' -indexerConfig[INDEXER_TVRAGE]['icon'] = 'tvrage16.png' -indexerConfig[INDEXER_TVRAGE]['scene_loc'] = 'http://sickragetv.github.io/sr_tvrage_scene_exceptions/exceptions.txt' -indexerConfig[INDEXER_TVRAGE]['show_url'] = 'http://tvrage.com/shows/id-' -indexerConfig[INDEXER_TVRAGE]['base_url'] = 'http://tvrage.com/showinfo.php?key=%(apikey)s&sid=' % indexerConfig[INDEXER_TVRAGE]['api_params'] diff --git a/sickbeard/indexers/indexer_exceptions.py b/sickbeard/indexers/indexer_exceptions.py index 1ba41a722f248c410e5f6233bc2418839b3c3bee..221f529661f32dcadc798725956de5bf23873b97 100644 --- a/sickbeard/indexers/indexer_exceptions.py +++ b/sickbeard/indexers/indexer_exceptions.py @@ -10,10 +10,6 @@ __author__ = "echel0n" __version__ = "1.0" -from tvrage_api.tvrage_exceptions import \ - tvrage_exception, tvrage_attributenotfound, tvrage_episodenotfound, tvrage_error, \ - tvrage_seasonnotfound, tvrage_shownotfound, tvrage_showincomplete, tvrage_userabort - from tvdb_api.tvdb_exceptions import \ tvdb_exception, tvdb_attributenotfound, tvdb_episodenotfound, tvdb_error, \ tvdb_seasonnotfound, tvdb_shownotfound, tvdb_showincomplete, tvdb_userabort @@ -25,15 +21,12 @@ indexerExcepts = ["indexer_exception", "indexer_error", "indexer_userabort", "in tvdbExcepts = ["tvdb_exception", "tvdb_error", "tvdb_userabort", "tvdb_shownotfound", "tvdb_showincomplete", "tvdb_seasonnotfound", "tvdb_episodenotfound", "tvdb_attributenotfound"] -tvrageExcepts = ["tvdb_exception", "tvrage_error", "tvrage_userabort", "tvrage_shownotfound", "tvrage_showincomplete", - "tvrage_seasonnotfound", "tvrage_episodenotfound", "tvrage_attributenotfound"] - # link API exceptions to our exception handler -indexer_exception = tvdb_exception, tvrage_exception -indexer_error = tvdb_error, tvrage_error -indexer_userabort = tvdb_userabort, tvrage_userabort -indexer_attributenotfound = tvdb_attributenotfound, tvrage_attributenotfound -indexer_episodenotfound = tvdb_episodenotfound, tvrage_episodenotfound -indexer_seasonnotfound = tvdb_seasonnotfound, tvrage_seasonnotfound -indexer_shownotfound = tvdb_shownotfound, tvrage_shownotfound -indexer_showincomplete = tvdb_showincomplete, tvrage_showincomplete +indexer_exception = tvdb_exception +indexer_error = tvdb_error +indexer_userabort = tvdb_userabort +indexer_attributenotfound = tvdb_attributenotfound +indexer_episodenotfound = tvdb_episodenotfound +indexer_seasonnotfound = tvdb_seasonnotfound +indexer_shownotfound = tvdb_shownotfound +indexer_showincomplete = tvdb_showincomplete diff --git a/sickbeard/metadata/generic.py b/sickbeard/metadata/generic.py index 672faa8264bd876e71f6e7833b7b94ba597ca951..7597fd4633cb3dc463ab1aa33713b944767a43e6 100644 --- a/sickbeard/metadata/generic.py +++ b/sickbeard/metadata/generic.py @@ -371,7 +371,7 @@ class GenericMetadata(): def _get_episode_thumb_url(self, ep_obj): """ Returns the URL to use for downloading an episode's thumbnail. Uses - theTVDB.com and TVRage.com data. + theTVDB.com data. ep_obj: a TVEpisode object for which to grab the thumb URL """ @@ -852,7 +852,7 @@ class GenericMetadata(): result[season] = {} - # find the correct season in the TVDB and TVRAGE object and just copy the dict into our result dict + # find the correct season in the TVDB object and just copy the dict into our result dict for seasonArtID in seasonsArtObj.keys(): if int(seasonsArtObj[seasonArtID]['season']) == season and seasonsArtObj[seasonArtID]['language'] == sickbeard.INDEXER_DEFAULT_LANGUAGE: result[season][seasonArtID] = seasonsArtObj[seasonArtID]['_bannerpath'] @@ -907,7 +907,7 @@ class GenericMetadata(): result[season] = {} - # find the correct season in the TVDB and TVRAGE object and just copy the dict into our result dict + # find the correct season in the TVDB object and just copy the dict into our result dict for seasonArtID in seasonsArtObj.keys(): if int(seasonsArtObj[seasonArtID]['season']) == season and seasonsArtObj[seasonArtID]['language'] == sickbeard.INDEXER_DEFAULT_LANGUAGE: result[season][seasonArtID] = seasonsArtObj[seasonArtID]['_bannerpath'] @@ -963,7 +963,8 @@ class GenericMetadata(): if 'thetvdb.com' in epg_url: indexer = 1 elif 'tvrage' in epg_url: - indexer = 2 + logger.log(u"Invalid Indexer ID (" + str(indexer_id) + "), not using metadata file because it has TVRage info", logger.WARNING) + return empty_return except Exception, e: diff --git a/sickbeard/name_cache.py b/sickbeard/name_cache.py index 8f00b35b077a3c0479120d02733129dd594161af..0429bff57805e5387ad20078fb0bc7f948ac7a12 100644 --- a/sickbeard/name_cache.py +++ b/sickbeard/name_cache.py @@ -26,9 +26,9 @@ nameCacheLock = threading.Lock() def addNameToCache(name, indexer_id=0): """ Adds the show & tvdb id to the scene_names table in cache.db. - + name: The show name to cache - indexer_id: the TVDB and TVRAGE id that this show should be cached with (can be None/0 for unknown) + indexer_id: the TVDB id that this show should be cached with (can be None/0 for unknown) """ global nameCache @@ -45,10 +45,10 @@ def addNameToCache(name, indexer_id=0): def retrieveNameFromCache(name): """ Looks up the given name in the scene_names table in cache.db. - + name: The show name to look up. - - Returns: the TVDB and TVRAGE id that resulted from the cache lookup or None if the show wasn't found in the cache + + Returns: the TVDB id that resulted from the cache lookup or None if the show wasn't found in the cache """ global nameCache diff --git a/sickbeard/notifiers/emby.py b/sickbeard/notifiers/emby.py index 7e8dc580f9cc6d68a3ced4a68c552372010f5f25..238be4b0fc7926b4ec0ead9e6c1314fed6aa2c08 100644 --- a/sickbeard/notifiers/emby.py +++ b/sickbeard/notifiers/emby.py @@ -91,7 +91,8 @@ class EMBYNotifier: if show.indexer == 1: provider = 'tvdb' elif show.indexer == 2: - provider = 'tvrage' + logger.log(u'EMBY: TVRage Provider no longer valid', logger.WARNING) + return False else: logger.log(u'EMBY: Provider unknown', logger.WARNING) return False diff --git a/sickbeard/providers/btn.py b/sickbeard/providers/btn.py index a3c477e56e93a7192a769a748c877098a16004d1..5d1680eae3aaef503e2808d49ceb8c85eb65aa7d 100644 --- a/sickbeard/providers/btn.py +++ b/sickbeard/providers/btn.py @@ -149,7 +149,7 @@ class BTNProvider(generic.TorrentProvider): except jsonrpclib.jsonrpc.ProtocolError, error: if error.message == 'Call Limit Exceeded': - logger.log(u"You have exceeded the limit of 150 calls per hour, per API key which is unique to your user account.", logger.WARNING) + logger.log(u"You have exceeded the limit of 150 calls per hour, per API key which is unique to your user account.", logger.WARNING) else: logger.log(u"JSON-RPC protocol error while accessing " + self.name + ": " + ex(error), logger.ERROR) parsedJSON = {'api-error': ex(error)} @@ -221,14 +221,11 @@ class BTNProvider(generic.TorrentProvider): if ep_obj.show.indexer == 1: current_params['tvdb'] = ep_obj.show.indexerid search_params.append(current_params) - elif ep_obj.show.indexer == 2: - current_params['tvrage'] = ep_obj.show.indexerid - search_params.append(current_params) else: name_exceptions = list( set(scene_exceptions.get_scene_exceptions(ep_obj.show.indexerid) + [ep_obj.show.name])) for name in name_exceptions: - # Search by name if we don't have tvdb or tvrage id + # Search by name if we don't have tvdb id current_params['series'] = sanitizeSceneName(name) search_params.append(current_params) @@ -259,9 +256,6 @@ class BTNProvider(generic.TorrentProvider): if ep_obj.show.indexer == 1: search_params['tvdb'] = ep_obj.show.indexerid to_return.append(search_params) - elif ep_obj.show.indexer == 2: - search_params['tvrage'] = ep_obj.show.indexerid - to_return.append(search_params) else: # add new query string for every exception name_exceptions = list( @@ -381,7 +375,7 @@ class BTNProvider(generic.TorrentProvider): addCacheEntry = False if not (showObj.air_by_date or showObj.sports): - if search_mode == 'sponly': + if search_mode == 'sponly': if len(parse_result.episode_numbers): logger.log( u"This is supposed to be a season pack search but the result " + title + " is not a valid season pack, skipping it", diff --git a/sickbeard/providers/newznab.py b/sickbeard/providers/newznab.py index db73bd7e944d9e4419421c3834cbf2298682875c..838bedff56b435c348180d983ef2f902d1b920f8 100644 --- a/sickbeard/providers/newznab.py +++ b/sickbeard/providers/newznab.py @@ -145,13 +145,6 @@ class NewznabProvider(generic.NZBProvider): else: cur_params['season'] = str(ep_obj.scene_season) - # search - rid = helpers.mapIndexersToShow(ep_obj.show)[2] - if rid: - cur_params['rid'] = rid - cur_params['attrs'] = "rageid" - to_return.append(dict(cur_params)) - if 'rid' in cur_params: cur_params.pop('rid') cur_params.pop('attrs') @@ -186,13 +179,6 @@ class NewznabProvider(generic.NZBProvider): params['season'] = ep_obj.scene_season params['ep'] = ep_obj.scene_episode - # search - rid = helpers.mapIndexersToShow(ep_obj.show)[2] - if rid: - params['rid'] = rid - params['attrs'] = "rageid" - to_return.append(dict(params)) - if 'rid' in params: params.pop('rid') params.pop('attrs') @@ -416,10 +402,6 @@ class NewznabCache(tvcache.TVCache): return None tvrageid = 0 - for attr in item['newznab_attr'] if isinstance(item['newznab_attr'], list) else [item['newznab_attr']]: - if attr['name'] == 'tvrageid' or attr['name'] == 'rageid': - tvrageid = int(attr['value'] or 0) - break logger.log(u"Attempting to add item from RSS to cache: " + title, logger.DEBUG) return self._addCacheEntry(title, url, indexer_id=tvrageid) diff --git a/sickbeard/providers/rarbg.py b/sickbeard/providers/rarbg.py index dc9cff4ace90a25c81d209f4cd893b3cae57ae1f..aecde2ee7e1d52ed5fe9bbb9f3ffbc84eba48dfd 100644 --- a/sickbeard/providers/rarbg.py +++ b/sickbeard/providers/rarbg.py @@ -36,7 +36,7 @@ from sickbeard import helpers from sickbeard import classes from sickbeard.exceptions import ex from requests.exceptions import RequestException -from sickbeard.indexers.indexer_config import INDEXER_TVDB,INDEXER_TVRAGE +from sickbeard.indexers.indexer_config import INDEXER_TVDB class GetOutOfLoop(Exception): @@ -63,7 +63,6 @@ class RarbgProvider(generic.TorrentProvider): 'listing': u'http://torrentapi.org/pubapi_v2.php?mode=list&app_id=sickrage', 'search': u'http://torrentapi.org/pubapi_v2.php?mode=search&app_id=sickrage&search_string={search_string}', 'search_tvdb': u'http://torrentapi.org/pubapi_v2.php?mode=search&app_id=sickrage&search_tvdb={tvdb}&search_string={search_string}', - 'search_tvrage': u'http://torrentapi.org/pubapi_v2.php?mode=search&app_id=sickrage&search_tvrage={tvrage}&search_string={search_string}', 'api_spec': u'https://rarbg.com/pubapi/apidocs.txt', } @@ -200,15 +199,11 @@ class RarbgProvider(generic.TorrentProvider): elif mode == 'Season': if ep_indexer == INDEXER_TVDB: searchURL = self.urls['search_tvdb'].format(search_string=search_string, tvdb=ep_indexerid) + self.defaultOptions - elif ep_indexer == INDEXER_TVRAGE: - searchURL = self.urls['search_tvrage'].format(search_string=search_string, tvrage=ep_indexerid) + self.defaultOptions else: searchURL = self.urls['search'].format(search_string=search_string) + self.defaultOptions elif mode == 'Episode': if ep_indexer == INDEXER_TVDB: searchURL = self.urls['search_tvdb'].format(search_string=search_string, tvdb=ep_indexerid) + self.defaultOptions - elif ep_indexer == INDEXER_TVRAGE: - searchURL = self.urls['search_tvrage'].format(search_string=search_string, tvrage=ep_indexerid) + self.defaultOptions else: searchURL = self.urls['search'].format(search_string=search_string) + self.defaultOptions else: @@ -260,9 +255,6 @@ class RarbgProvider(generic.TorrentProvider): if re.search('Cant find search_tvdb in database. Are you sure this imdb exists?', data): logger.log(u'{name} no results found. Search tvdb id do not exist on server.'.format(name=self.name), logger.DEBUG) raise GetOutOfLoop - if re.search('Cant find search_tvrage in database. Are you sure this imdb exists?', data): - logger.log(u'{name} no results found. Search tvrage id do not exist on server.'.format(name=self.name), logger.DEBUG) - raise GetOutOfLoop if re.search('Invalid token. Use get_token for a new one!', data): logger.log(u'{name} Invalid token, retrieving new token'.format(name=self.name), logger.DEBUG) retry = retry - 1 diff --git a/sickbeard/scene_numbering.py b/sickbeard/scene_numbering.py index 0a77ffdf24f21930c1f1a9d79992746ac6613675..11f7a9cd2b5776b7f50c873a1886f35901c78894 100644 --- a/sickbeard/scene_numbering.py +++ b/sickbeard/scene_numbering.py @@ -35,15 +35,15 @@ from sickbeard import helpers def get_scene_numbering(indexer_id, indexer, season, episode, fallback_to_xem=True): """ Returns a tuple, (season, episode), with the scene numbering (if there is one), - otherwise returns the xem numbering (if fallback_to_xem is set), otherwise - returns the TVDB and TVRAGE numbering. + otherwise returns the xem numbering (if fallback_to_xem is set), otherwise + returns the TVDB numbering. (so the return values will always be set) - + @param indexer_id: int @param season: int @param episode: int @param fallback_to_xem: bool If set (the default), check xem for matches if there is no local scene numbering - @return: (int, int) a tuple with (season, episode) + @return: (int, int) a tuple with (season, episode) """ if indexer_id is None or season is None or episode is None: return (season, episode) @@ -86,7 +86,7 @@ def get_scene_absolute_numbering(indexer_id, indexer, absolute_number, fallback_ """ Returns a tuple, (season, episode), with the scene numbering (if there is one), otherwise returns the xem numbering (if fallback_to_xem is set), otherwise - returns the TVDB and TVRAGE numbering. + returns the TVDB numbering. (so the return values will always be set) @param indexer_id: int @@ -136,7 +136,7 @@ def find_scene_absolute_numbering(indexer_id, indexer, absolute_number): def get_indexer_numbering(indexer_id, indexer, sceneSeason, sceneEpisode, fallback_to_xem=True): """ - Returns a tuple, (season, episode) with the TVDB and TVRAGE numbering for (sceneSeason, sceneEpisode) + Returns a tuple, (season, episode) with the TVDB numbering for (sceneSeason, sceneEpisode) (this works like the reverse of get_scene_numbering) """ if indexer_id is None or sceneSeason is None or sceneEpisode is None: @@ -160,7 +160,7 @@ def get_indexer_numbering(indexer_id, indexer, sceneSeason, sceneEpisode, fallba def get_indexer_absolute_numbering(indexer_id, indexer, sceneAbsoluteNumber, fallback_to_xem=True, scene_season=None): """ - Returns a tuple, (season, episode, absolute_number) with the TVDB and TVRAGE numbering for (sceneAbsoluteNumber) + Returns a tuple, (season, episode, absolute_number) with the TVDB absolute numbering for (sceneAbsoluteNumber) (this works like the reverse of get_absolute_numbering) """ if indexer_id is None or sceneAbsoluteNumber is None: @@ -192,7 +192,7 @@ def set_scene_numbering(indexer_id, indexer, season=None, episode=None, absolute """ Set scene numbering for a season/episode. To clear the scene numbering, leave both sceneSeason and sceneEpisode as None. - + """ if indexer_id is None: return @@ -227,7 +227,7 @@ def find_xem_numbering(indexer_id, indexer, season, episode): """ Returns the scene numbering, as retrieved from xem. Refreshes/Loads as needed. - + @param indexer_id: int @param season: int @param episode: int @@ -279,11 +279,11 @@ def find_xem_absolute_numbering(indexer_id, indexer, absolute_number): def get_indexer_numbering_for_xem(indexer_id, indexer, sceneSeason, sceneEpisode): """ Reverse of find_xem_numbering: lookup a tvdb season and episode using scene numbering - + @param indexer_id: int @param sceneSeason: int @param sceneEpisode: int - @return: (int, int) a tuple of (season, episode) + @return: (int, int) a tuple of (season, episode) """ if indexer_id is None or sceneSeason is None or sceneEpisode is None: return (sceneSeason, sceneEpisode) @@ -455,7 +455,7 @@ def get_xem_absolute_numbering_for_show(indexer_id, indexer): def xem_refresh(indexer_id, indexer, force=False): """ Refresh data from xem for a tv show - + @param indexer_id: int """ if not indexer_id or indexer_id < 1: @@ -548,46 +548,6 @@ def fix_xem_numbering(indexer_id, indexer): indexer_id = int(indexer_id) indexer = int(indexer) - # query = [{ - # "name": self.show.name, - # "seasons": [{ - # "episodes": [{ - # "episode_number": None, - # "name": None - # }], - # "season_number": None, - # }], - # "/tv/tv_program/number_of_seasons": [], - # "/tv/tv_program/number_of_episodes": [], - # "/tv/tv_program/thetvdb_id": [], - # "/tv/tv_program/tvrage_id": [], - # "type": "/tv/tv_program", - # }] - # - # - # url = 'https://www.googleapis.com/freebase/v1/mqlread' - # api_key = "AIzaSyCCHNp4dhVHxJYzbLiCE4y4a1rgTnX4fDE" - # params = { - # 'query': json.dumps(query), - # 'key': api_key - # } - # - # - # def get_from_api(url, params=None): - # """Build request and return results - # """ - # import xmltodict - # - # response = requests.get(url, params=params) - # if response.status_code == 200: - # try: - # return response.json() - # except ValueError: - # return xmltodict.parse(response.text)['Data'] - # - # # Get query results - # tmp = get_from_api(url, params=params)['result'] - myDB = db.DBConnection() rows = myDB.select( 'SELECT season, episode, absolute_number, scene_season, scene_episode, scene_absolute_number FROM tv_episodes WHERE indexer = ? and showid = ?', diff --git a/sickbeard/webapi.py b/sickbeard/webapi.py index 03199bceb40451d7df41d83ca8447c299a2132f6..48fc149bc868a430214ac3ecdc82ba2eeae34a41 100644 --- a/sickbeard/webapi.py +++ b/sickbeard/webapi.py @@ -67,7 +67,7 @@ except ImportError: from tornado.web import RequestHandler -indexer_ids = ["indexerid", "tvdbid", "tvrageid"] +indexer_ids = ["indexerid", "tvdbid"] dateFormat = "%Y-%m-%d" dateTimeFormat = "%Y-%m-%d %H:%M" @@ -341,8 +341,6 @@ class ApiCall(ApiHandler): if key in indexer_ids: if "tvdbid" in kwargs: key = "tvdbid" - elif "tvrageid" in kwargs: - key = "tvrageid" self.indexer = indexer_ids.index(key) @@ -788,7 +786,6 @@ class CMD_Episode(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, "full_path": { "desc": "show the full absolute path (if valid) instead of a relative path for the episode location"} } @@ -854,7 +851,6 @@ class CMD_EpisodeSearch(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, } } @@ -907,7 +903,6 @@ class CMD_EpisodeSetStatus(ApiCall): "episode": {"desc": "the episode number"}, "force": {"desc": "should we replace existing (downloaded) episodes or not"}, "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, } } @@ -1025,7 +1020,6 @@ class CMD_SubtitleSearch(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, } } @@ -1077,7 +1071,6 @@ class CMD_Exceptions(ApiCall): "optionalParameters": { "indexerid": {"desc": "unique id of a show"}, "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, } } @@ -1657,7 +1650,6 @@ class CMD_SickBeardSearchIndexers(ApiCall): "optionalParameters": {"name": {"desc": "name of the show you want to search for"}, "indexerid": {"desc": "unique id of a show"}, "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, "lang": {"desc": "the 2 letter abbreviation lang id"} } } @@ -1756,17 +1748,21 @@ class CMD_SickBeardSearchTVDB(CMD_SickBeardSearchIndexers): class CMD_SickBeardSearchTVRAGE(CMD_SickBeardSearchIndexers): + """ + Deprecated, TVRage is no more. + """ + _help = {"desc": "search for show on TVRage with a given string and language", "optionalParameters": {"name": {"desc": "name of the show you want to search for"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, "lang": {"desc": "the 2 letter abbreviation lang id"} } } def __init__(self, args, kwargs): - CMD_SickBeardSearchIndexers.__init__(self, args, kwargs) - self.indexerid, args = self.check_params(args, kwargs, "tvrageid", None, False, "int", []) + ApiCall.__init__(self, args, kwargs) + def run(self): + return _responds(RESULT_FAILURE, msg="TVRage is no more, invalid result") class CMD_SickBeardSetDefaults(ApiCall): _help = {"desc": "set sickrage user defaults", @@ -1892,7 +1888,6 @@ class CMD_Show(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, } } @@ -1958,8 +1953,6 @@ class CMD_Show(ApiCall): showDict["indexerid"] = showObj.indexerid showDict["tvdbid"] = helpers.mapIndexersToShow(showObj)[1] - showDict["tvrage_id"] = helpers.mapIndexersToShow(showObj)[2] - showDict["tvrage_name"] = showObj.name showDict["imdbid"] = showObj.imdbid showDict["network"] = showObj.network @@ -1986,7 +1979,6 @@ class CMD_ShowAddExisting(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, "initial": {"desc": "initial quality for the show"}, "archive": {"desc": "archive quality for the show"}, "flatten_folders": {"desc": "flatten subfolders for the show"}, @@ -2077,7 +2069,6 @@ class CMD_ShowAddNew(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, "initial": {"desc": "initial quality for the show"}, "location": {"desc": "base path for where the show folder is to be created"}, "archive": {"desc": "archive quality for the show"}, @@ -2248,7 +2239,6 @@ class CMD_ShowCache(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, } } @@ -2288,7 +2278,6 @@ class CMD_ShowDelete(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, "removefiles":{"desc": "Deletes the files, there is no going back!"}, } } @@ -2322,7 +2311,6 @@ class CMD_ShowGetQuality(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, } } @@ -2352,7 +2340,6 @@ class CMD_ShowGetPoster(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, } } @@ -2379,7 +2366,6 @@ class CMD_ShowGetBanner(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, } } @@ -2410,9 +2396,6 @@ class CMD_ShowGetNetworkLogo(ApiCall): "tvdbid": { "desc": "TheTVDB.com unique id of a show", }, - "tvrageid": { - "desc": "TVRage.con unique id of a show", - }, }, } @@ -2441,7 +2424,6 @@ class CMD_ShowGetFanArt(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, }, } @@ -2467,7 +2449,6 @@ class CMD_ShowPause(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, "pause": {"desc": "set the pause state of the show"} } } @@ -2502,7 +2483,6 @@ class CMD_ShowRefresh(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, } } @@ -2534,7 +2514,6 @@ class CMD_ShowSeasonList(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, "sort": {"desc": "change the sort order from descending to ascending"} } } @@ -2576,7 +2555,6 @@ class CMD_ShowSeasons(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, "season": {"desc": "the season number"}, } } @@ -2648,7 +2626,6 @@ class CMD_ShowSetQuality(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, "initial": {"desc": "initial quality for the show"}, "archive": {"desc": "archive quality for the show"} } @@ -2716,7 +2693,6 @@ class CMD_ShowStats(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, } } @@ -2825,7 +2801,6 @@ class CMD_ShowUpdate(ApiCall): }, "optionalParameters": { "tvdbid": {"desc": "thetvdb.com unique id of a show"}, - "tvrageid": {"desc": "tvrage.com unique id of a show"}, } } @@ -2885,8 +2860,6 @@ class CMD_Shows(ApiCall): "anime": curShow.anime, "indexerid": curShow.indexerid, "tvdbid": indexerShow[1], - "tvrage_id": indexerShow[2], - "tvrage_name": curShow.name, "network": curShow.network, "show_name": curShow.name, "status": curShow.status, diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 47cee47fb716997fdb2fec96415119fd95fbf3ba..7c65a2024e4f437cc038b72465a955db6c281730 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -2441,9 +2441,7 @@ class HomeAddShows(Home): show = {} show['show']=show_detail try: - tvdb_id = int(show['show']['ids']['tvdb']) - tvrage_id = int(show['show']['ids']['tvrage'] or 0) - if not helpers.findCertainShow(sickbeard.showList, [tvdb_id, tvrage_id]): + if not helpers.findCertainShow(sickbeard.showList, [int(show['show']['ids']['tvdb'])]): if show['show']['ids']['tvdb'] not in (lshow['show']['ids']['tvdb'] for lshow in library_shows): if not_liked_show: if show['show']['ids']['tvdb'] not in (show['show']['ids']['tvdb'] for show in not_liked_show if show['type'] == 'show'): @@ -2497,9 +2495,7 @@ class HomeAddShows(Home): library_shows = trakt_api.traktRequest("sync/collection/shows?extended=full") or [] for show in shows: try: - tvdb_id = int(show['show']['ids']['tvdb']) - tvrage_id = int(show['show']['ids']['tvrage'] or 0) - if not helpers.findCertainShow(sickbeard.showList, [tvdb_id, tvrage_id]): + if not helpers.findCertainShow(sickbeard.showList, [int(show['show']['ids']['tvdb'])]): if show['show']['ids']['tvdb'] not in (lshow['show']['ids']['tvdb'] for lshow in library_shows): if not_liked_show: if show['show']['ids']['tvdb'] not in (show['show']['ids']['tvdb'] for show in not_liked_show if show['type'] == 'show'):