diff --git a/CHANGES.md b/CHANGES.md index a39645e4..db060806 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -57,6 +57,7 @@ * Add persistent hide/unhide cards to Add show/Trakt and Add show/IMDb Cards * Change simplify dropdowns at all Add show/Cards * Change cosmetic title on shutdown +* Change use TVDb API v2 [develop changelog] diff --git a/lib/tvdb_api/tvdb_api.py b/lib/tvdb_api/tvdb_api.py index b4c65286..95feccce 100644 --- a/lib/tvdb_api/tvdb_api.py +++ b/lib/tvdb_api/tvdb_api.py @@ -5,40 +5,36 @@ # repository:http://github.com/dbr/tvdb_api # license:unlicense (http://unlicense.org/) -import traceback from functools import wraps __author__ = 'dbr/Ben' -__version__ = '1.9' +__version__ = '2.0' +__api_version__ = '2.1.2' import os import time import getpass -import StringIO import tempfile import warnings import logging -import zipfile import requests import requests.exceptions - -try: - import gzip -except ImportError: - gzip = None +import datetime +from sickbeard.helpers import getURL from lib.dateutil.parser import parse from lib.cachecontrol import CacheControl, caches -from lib.etreetodict import ConvertXmlToDict from tvdb_ui import BaseUI, ConsoleUI from tvdb_exceptions import (tvdb_error, tvdb_shownotfound, tvdb_seasonnotfound, tvdb_episodenotfound, tvdb_attributenotfound) -from sickbeard import logger + +def log(): + return logging.getLogger('tvdb_api') -def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logr=None): +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/ @@ -54,8 +50,8 @@ def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logr=None): :param backoff: backoff multiplier e.g. value of 2 will double the delay each retry :type backoff: int - :param logr: logger to use. If None, print - :type logr: logging.Logger instance + :param logger: logger to use. If None, print + :type logger: logging.Logger instance """ def deco_retry(f): @@ -67,9 +63,9 @@ def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logr=None): try: return f(*args, **kwargs) except ExceptionToCheck, e: - msg = 'TVDB_API :: %s, Retrying in %d seconds...' % (str(e), mdelay) - if logr: - logger.log(msg, logger.WARNING) + msg = '%s, Retrying in %d seconds...' % (str(e), mdelay) + if logger: + logger.warning(msg) else: print msg time.sleep(mdelay) @@ -86,7 +82,8 @@ class ShowContainer(dict): """Simple dict that holds a series of Show instances """ - def __init__(self): + def __init__(self, **kwargs): + super(ShowContainer, self).__init__(**kwargs) self._stack = [] self._lastgc = time.time() @@ -145,7 +142,7 @@ class Show(dict): # doesn't exist, so attribute error. raise tvdb_attributenotfound('Cannot find attribute %s' % (repr(key))) - def airedOn(self, date): + def aired_on(self, date): ret = self.search(str(date), 'firstaired') if 0 == len(ret): raise tvdb_episodenotfound('Could not find any episodes that aired on %s' % date) @@ -166,9 +163,9 @@ class Show(dict): Search terms are converted to lower case (unicode) strings. # Examples - + These examples assume t is an instance of Tvdb(): - + >> t = Tvdb() >> @@ -212,9 +209,10 @@ class Show(dict): class Season(dict): - def __init__(self, show=None): + def __init__(self, show=None, **kwargs): """The show attribute points to the parent show """ + super(Season, self).__init__(**kwargs) self.show = show def __repr__(self): @@ -251,9 +249,10 @@ class Season(dict): class Episode(dict): - def __init__(self, season=None): + def __init__(self, season=None, **kwargs): """The season attribute points to the parent season """ + super(Episode, self).__init__(**kwargs) self.season = season def __repr__(self): @@ -301,7 +300,7 @@ class Episode(dict): raise TypeError('must supply string to search for (contents)') term = unicode(term).lower() - for cur_key, cur_value in self.items(): + for cur_key, cur_value in self.iteritems(): cur_key, cur_value = unicode(cur_key).lower(), unicode(cur_value).lower() if None is not key and cur_key != key: # Do not search this key @@ -343,13 +342,12 @@ class Tvdb: debug=False, cache=True, banners=False, + fanart=False, actors=False, custom_ui=None, language=None, search_all_languages=False, apikey=None, - forceConnect=False, - useZip=False, dvdorder=False, proxy=None): @@ -413,16 +411,6 @@ class Tvdb: tvdb_api in a larger application) See http://thetvdb.com/?tab=apiregister to get your own key - forceConnect (bool): - If true it will always try to connect to theTVDB.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. - - useZip (bool): - Download the zip archive where possibale, instead of the xml. - This is only used when all episodes are pulled. - And only the main language xml is used, the actor and banner xml are lost. """ self.shows = ShowContainer() # Holds all Show classes @@ -435,6 +423,8 @@ class Tvdb: else: self.config['apikey'] = '0629B785CE550C8D' # tvdb_api's API key + self.token = {'token': None, 'datetime': datetime.datetime.fromordinal(1)} + self.config['debug_enabled'] = debug # show debugging messages self.config['custom_ui'] = custom_ui @@ -445,8 +435,6 @@ class Tvdb: self.config['search_all_languages'] = search_all_languages - self.config['useZip'] = useZip - self.config['dvdorder'] = dvdorder self.config['proxy'] = proxy @@ -463,6 +451,7 @@ class Tvdb: raise ValueError('Invalid value for Cache %r (type was %s)' % (cache, type(cache))) self.config['banners_enabled'] = banners + self.config['fanart_enabled'] = fanart self.config['actors_enabled'] = actors if self.config['debug_enabled']: @@ -498,26 +487,37 @@ class Tvdb: # The following url_ configs are based of the # http://thetvdb.com/wiki/index.php/Programmers_API - self.config['base_url'] = 'http://thetvdb.com' + self.config['base_url'] = 'https://api.thetvdb.com/' - if self.config['search_all_languages']: - self.config['url_get_series'] = u'%(base_url)s/api/GetSeries.php' % self.config - self.config['params_get_series'] = {'seriesname': '', 'language': 'all'} - else: - self.config['url_get_series'] = u'%(base_url)s/api/GetSeries.php' % self.config - self.config['params_get_series'] = {'seriesname': '', 'language': self.config['language']} + self.config['url_get_series'] = '%(base_url)s/search/series' % self.config + self.config['params_get_series'] = {'name': ''} - self.config['url_epInfo'] = u'%(base_url)s/api/%(apikey)s/series/%%s/all/%%s.xml' % self.config - self.config['url_epInfo_zip'] = u'%(base_url)s/api/%(apikey)s/series/%%s/all/%%s.zip' % self.config + self.config['url_epInfo'] = '%(base_url)sseries/%%s/episodes?page=%%s' % self.config - self.config['url_seriesInfo'] = u'%(base_url)s/api/%(apikey)s/series/%%s/%%s.xml' % self.config - self.config['url_actorsInfo'] = u'%(base_url)s/api/%(apikey)s/series/%%s/actors.xml' % self.config + self.config['url_seriesInfo'] = '%(base_url)sseries/%%s' % self.config + self.config['url_actorsInfo'] = '%(base_url)sseries/%%s/actors' % self.config - self.config['url_seriesBanner'] = u'%(base_url)s/api/%(apikey)s/series/%%s/banners.xml' % self.config - self.config['url_artworkPrefix'] = u'%(base_url)s/banners/%%s' % self.config + self.config['url_seriesBanner'] = '%(base_url)sseries/%%s/images/query?keyType=%%s' % self.config + self.config['url_artworkPrefix'] = 'https://thetvdb.com/banners/%s' - def log(self, msg, log_level=logger.DEBUG): - logger.log('TVDB_API :: %s' % (msg.replace(self.config['apikey'], '')), log_level=log_level) + def get_new_token(self): + token = None + url = '%s%s' % (self.config['base_url'], 'login') + params = {'apikey': self.config['apikey']} + resp = getURL(url.strip(), post_json=params, json=True) + if resp: + if 'token' in resp: + token = resp['token'] + + return {'token': token, 'datetime': datetime.datetime.now()} + + def get_token(self): + if self.token.get('token') is None or datetime.datetime.now() - self.token.get( + 'datetime', datetime.datetime.fromordinal(1)) > datetime.timedelta(hours=23): + self.token = self.get_new_token() + if not self.token.get('token'): + raise tvdb_error('Could not get Authentification Token') + return self.token.get('token') @staticmethod def _get_temp_dir(): @@ -537,7 +537,7 @@ class Tvdb: @retry(tvdb_error) def _load_url(self, url, params=None, language=None): - self.log('Retrieving URL %s' % url) + log().debug('Retrieving URL %s' % url) session = requests.session() @@ -545,56 +545,60 @@ class Tvdb: session = CacheControl(session, cache=caches.FileCache(self.config['cache_location'])) if self.config['proxy']: - self.log('Using proxy for URL: %s' % url) + log().debug('Using proxy for URL: %s' % url) session.proxies = {'http': self.config['proxy'], 'https': self.config['proxy']} - session.headers.update({'Accept-Encoding': 'gzip,deflate'}) + session.headers.update({'Accept-Encoding': 'gzip,deflate', 'Authorization': 'Bearer %s' % self.get_token(), + 'Accept': 'application/vnd.thetvdb.v%s' % __api_version__}) - try: - resp = session.get(url.strip(), params=params) - except requests.exceptions.HTTPError, e: - raise tvdb_error('HTTP error %s while loading URL %s' % (e.errno, url)) - except requests.exceptions.ConnectionError, e: - raise tvdb_error('Connection error %s while loading URL %s' % (e.message, url)) - except requests.exceptions.Timeout, e: - raise tvdb_error('Connection timed out %s while loading URL %s' % (e.message, url)) - except Exception: - raise tvdb_error('Unknown exception while loading URL %s: %s' % (url, traceback.format_exc())) + if None is not language and language in self.config['valid_languages']: + session.headers.update({'Accept-Language': language}) - def process_data(data): - te = ConvertXmlToDict(data) - if isinstance(te, dict) and 'Data' in te and isinstance(te['Data'], dict) \ - and 'Series' in te['Data'] and isinstance(te['Data']['Series'], dict) \ - and 'FirstAired' in te['Data']['Series']: - try: - value = parse(te['Data']['Series']['FirstAired'], fuzzy=True).strftime('%Y-%m-%d') - except (StandardError, Exception): - value = None - te['Data']['Series']['firstaired'] = value - return te + resp = getURL(url.strip(), params=params, session=session, json=True) - if resp.ok: - if 'application/zip' in resp.headers.get('Content-Type', ''): - try: - # TODO: The zip contains actors.xml and banners.xml, which are currently ignored [GH-20] - self.log('We received a zip file unpacking now ...') - zipdata = StringIO.StringIO() - zipdata.write(resp.content) - myzipfile = zipfile.ZipFile(zipdata) - return process_data(myzipfile.read('%s.xml' % language)) - except zipfile.BadZipfile: - raise tvdb_error('Bad zip file received from thetvdb.com, could not read it') - else: - try: - return process_data(resp.content.strip()) - except (StandardError, Exception): - return dict([(u'data', None)]) + map_show = {'airstime': 'airs_time', 'airsdayofweek': 'airs_dayofweek', 'imdbid': 'imdb_id'} + + def map_show_keys(data): + for k, v in data.iteritems(): + k_org = k + k = k.lower() + if None is not v: + if k in ['banner', 'fanart', 'poster']: + v = self.config['url_artworkPrefix'] % v + elif 'genre' == k: + v = '|%s|' % '|'.join([self._clean_data(c) for c in v if isinstance(c, basestring)]) + elif 'firstaired' == k: + if v: + try: + v = parse(v, fuzzy=True).strftime('%Y-%m-%d') + except (StandardError, Exception): + v = None + else: + v = None + else: + v = self._clean_data(v) + if k in map_show: + k = map_show[k] + if k_org is not k: + del(data[k_org]) + data[k] = v + return data + + if resp: + if isinstance(resp['data'], dict): + resp['data'] = map_show_keys(resp['data']) + elif isinstance(resp['data'], list): + for idx, row in enumerate(resp['data']): + if isinstance(row, dict): + resp['data'][idx] = map_show_keys(row) + return resp + return dict([(u'data', None)]) def _getetsrc(self, url, params=None, language=None): - """Loads a URL using caching, returns an ElementTree of the source + """Loads a URL using caching """ try: - src = self._load_url(url, params=params, language=language).values()[0] + src = self._load_url(url, params=params, language=language) return src except (StandardError, Exception): return [] @@ -622,12 +626,15 @@ class Tvdb: self.shows[sid][seas][ep] = Episode(season=self.shows[sid][seas]) self.shows[sid][seas][ep][attrib] = value - def _set_show_data(self, sid, key, value): + def _set_show_data(self, sid, key, value, add=False): """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 + if add and isinstance(self.shows[sid].data, dict) and key in self.shows[sid].data: + self.shows[sid].data[key].update(value) + else: + self.shows[sid].data[key] = value @staticmethod def _clean_data(data): @@ -639,23 +646,18 @@ class Tvdb: """ return data if not isinstance(data, basestring) else data.strip().replace(u'&', u'&') - def _get_url_artwork(self, image): - return image and (self.config['url_artworkPrefix'] % image) or image - def search(self, series): """This searches TheTVDB.com for the series name and returns the result list """ series = series.encode('utf-8') - self.log('Searching for show %s' % series) - self.config['params_get_series']['seriesname'] = series + self.config['params_get_series']['name'] = series + log().debug('Searching for show %s' % series) try: - series_found = self._getetsrc(self.config['url_get_series'], self.config['params_get_series']) + series_found = self._getetsrc(self.config['url_get_series'], params=self.config['params_get_series'], + language=self.config['language']) if series_found: - if not isinstance(series_found['Series'], list): - series_found['Series'] = [series_found['Series']] - series_found['Series'] = [{k.lower(): v for k, v in s.iteritems()} for s in series_found['Series']] return series_found.values()[0] except (StandardError, Exception): pass @@ -673,50 +675,31 @@ class Tvdb: all_series = [all_series] if 0 == len(all_series): - self.log('Series result returned zero') + log().debug('Series result returned zero') raise tvdb_shownotfound('Show-name search returned zero results (cannot find show on TVDB)') if None is not self.config['custom_ui']: - self.log('Using custom UI %s' % (repr(self.config['custom_ui']))) + log().debug('Using custom UI %s' % (repr(self.config['custom_ui']))) custom_ui = self.config['custom_ui'] ui = custom_ui(config=self.config) else: if not self.config['interactive']: - self.log('Auto-selecting first search result using BaseUI') + log().debug('Auto-selecting first search result using BaseUI') ui = BaseUI(config=self.config) else: - self.log('Interactively selecting show using ConsoleUI') + log().debug('Interactively selecting show using ConsoleUI') ui = ConsoleUI(config=self.config) return ui.selectSeries(all_series) - def _parse_banners(self, sid): - """Parses banners XML, from - http://thetvdb.com/api/[APIKEY]/series/[SERIES ID]/banners.xml - - Banners are retrieved using t['show name]['_banners'], for example: - - >> t = Tvdb(banners = True) - >> t['scrubs']['_banners'].keys() - ['fanart', 'poster', 'series', 'season'] - >> t['scrubs']['_banners']['poster']['680x1000']['35308']['_bannerpath'] - u'http://thetvdb.com/banners/posters/76156-2.jpg' - >> - - Any key starting with an underscore has been processed (not the raw - data from the XML) - - This interface will be improved in future versions. - """ - self.log('Getting season banners for %s' % sid) - banners_et = self._getetsrc(self.config['url_seriesBanner'] % sid) + def _parse_banners(self, sid, img_list): banners = {} try: - for cur_banner in banners_et['banner']: + for cur_banner in img_list: bid = cur_banner['id'] - btype = cur_banner['bannertype'] - btype2 = cur_banner['bannertype2'] + btype = cur_banner['keytype'] + btype2 = cur_banner['resolution'] if None is btype or None is btype2: continue if btype not in banners: @@ -726,60 +709,37 @@ class Tvdb: if bid not in banners[btype][btype2]: banners[btype][btype2][bid] = {} - for k, v in cur_banner.items(): + for k, v in cur_banner.iteritems(): if None is k or None is v: continue - k, v = k.lower(), v.lower() + k, v = k.lower(), v.lower() if isinstance(v, (str, unicode)) else v + if k == 'filename': + k = 'bannerpath' + banners[btype][btype2][bid]['_bannerpath'] = self.config['url_artworkPrefix'] % v + elif k == 'thumbnail': + k = 'thumbnailpath' + banners[btype][btype2][bid]['_thumbnailpath'] = self.config['url_artworkPrefix'] % v + elif k == 'keytype': + k = 'bannertype' banners[btype][btype2][bid][k] = v - for k, v in banners[btype][btype2][bid].items(): - if k.endswith('path'): - new_key = '_%s' % k - self.log('Transforming %s to %s' % (k, new_key)) - new_url = self._get_url_artwork(v) - banners[btype][btype2][bid][new_key] = new_url except (StandardError, Exception): pass - self._set_show_data(sid, '_banners', banners) + self._set_show_data(sid, '_banners', banners, add=True) - def _parse_actors(self, sid): - """Parsers actors XML, from - http://thetvdb.com/api/[APIKEY]/series/[SERIES ID]/actors.xml - - Actors are retrieved using t['show name]['_actors'], for example: - - >> t = Tvdb(actors = True) - >> actors = t['scrubs']['_actors'] - >> type(actors) - - >> type(actors[0]) - - >> actors[0] - - >> sorted(actors[0].keys()) - ['id', 'image', 'name', 'role', 'sortorder'] - >> actors[0]['name'] - u'Zach Braff' - >> actors[0]['image'] - u'http://thetvdb.com/banners/actors/43640.jpg' - - Any key starting with an underscore has been processed (not the raw - data from the XML) - """ - self.log('Getting actors for %s' % sid) - actors_et = self._getetsrc(self.config['url_actorsInfo'] % sid) + def _parse_actors(self, sid, actor_list): cur_actors = Actors() try: - for curActorItem in actors_et['actor']: + for curActorItem in actor_list: cur_actor = Actor() - for k, v in curActorItem.items(): + for k, v in curActorItem.iteritems(): k = k.lower() if None is not v: if 'image' == k: - v = self._get_url_artwork(v) + v = self.config['url_artworkPrefix'] % v else: v = self._clean_data(v) cur_actor[k] = v @@ -795,96 +755,94 @@ class Tvdb: shows[series_id][season_number][episode_number] """ - if None is self.config['language']: - self.log('Config language is none, using show language') - if None is language: - raise tvdb_error('config[\'language\'] was None, this should not happen') - get_show_in_language = language - else: - self.log('Configured language %s override show language of %s' % (self.config['language'], language)) - get_show_in_language = self.config['language'] - # Parse show information - self.log('Getting all series data for %s' % sid) - url = (self.config['url_seriesInfo'] % (sid, language), self.config['url_epInfo%s' % ('', '_zip')[self.config['useZip']]] % (sid, language))[get_ep_info] - show_data = self._getetsrc(url, language=get_show_in_language) + log().debug('Getting all series data for %s' % sid) + url = self.config['url_seriesInfo'] % sid + show_data = self._getetsrc(url, language=language) # check and make sure we have data to process and that it contains a series name - if not len(show_data) or (isinstance(show_data, dict) and 'SeriesName' not in show_data['Series']): + if not isinstance(show_data, dict) or 'seriesname' not in show_data['data']: return False - for k, v in show_data['Series'].iteritems(): - if None is not v: - if k in ['banner', 'fanart', 'poster']: - v = self._get_url_artwork(v) - else: - v = self._clean_data(v) + for k, v in show_data['data'].iteritems(): + self._set_show_data(sid, k, v) - self._set_show_data(sid, k.lower(), v) + if self.config['banners_enabled']: + poster_data = self._getetsrc(self.config['url_seriesBanner'] % (sid, 'poster'), language=language) + self._set_show_data(sid, u'poster', + ('', self.config['url_artworkPrefix'] % poster_data['data'][0]['filename'])[ + poster_data and 'data' in poster_data and len(poster_data['data']) > 0]) + if poster_data and 'data' in poster_data and len(poster_data['data']) > 1: + self._parse_banners(sid, poster_data['data']) + + if self.config['fanart_enabled']: + fanart_data = self._getetsrc(self.config['url_seriesBanner'] % (sid, 'fanart'), language=language) + self._set_show_data(sid, u'fanart', + ('', self.config['url_artworkPrefix'] % fanart_data['data'][0]['filename'])[ + fanart_data and 'data' in fanart_data and len(fanart_data['data']) > 0]) + if fanart_data and 'data' in fanart_data and len(fanart_data['data']) > 1: + self._parse_banners(sid, fanart_data['data']) + + if self.config['actors_enabled']: + actor_data = self._getetsrc(self.config['url_actorsInfo'] % sid, language=language) + self._set_show_data(sid, u'actors', + ('||', '|%s|' % '|'.join([n.get('name', '') for n in sorted( + actor_data['data'], key=lambda x: x['sortorder'])]))[ + actor_data and 'data' in actor_data and len(actor_data['data']) > 0]) + if actor_data and 'data' in actor_data and len(actor_data['data']) > 0: + self._parse_actors(sid, actor_data['data']) if get_ep_info: - # Parse banners - if self.config['banners_enabled']: - self._parse_banners(sid) - - # Parse actors - if self.config['actors_enabled']: - self._parse_actors(sid) - # Parse episode data - self.log('Getting all episodes of %s' % sid) + log().debug('Getting all episodes of %s' % sid) - if 'Episode' not in show_data: - return False + page = 1 + episodes = [] + while page is not None: + episode_data = self._getetsrc(self.config['url_epInfo'] % (sid, page), language=language) + if isinstance(episode_data, dict) and episode_data['data'] is not None: + episodes.extend(episode_data['data']) + page = episode_data['links']['next'] if isinstance(episode_data, dict) \ + and 'links' in episode_data and 'next' in episode_data['links'] else None - episodes = show_data['Episode'] - if not isinstance(episodes, list): - episodes = [episodes] + ep_map_keys = {'absolutenumber': u'absolute_number', 'airedepisodenumber': u'episodenumber', + 'airedseason': u'seasonnumber', 'airedseasonid': u'seasonid', + 'dvdepisodenumber': u'dvd_episodenumber', 'dvdseason': u'dvd_season'} - dvd_order = {'dvd': [], 'network': []} for cur_ep in episodes: if self.config['dvdorder']: - use_dvd = cur_ep['DVD_season'] not in (None, '') and cur_ep['DVD_episodenumber'] not in (None, '') + log().debug('Using DVD ordering.') + use_dvd = None is not cur_ep.get('dvdseason') and None is not cur_ep.get('dvdepisodenumber') else: use_dvd = False if use_dvd: - elem_seasnum, elem_epno = cur_ep['DVD_season'], cur_ep['DVD_episodenumber'] + elem_seasnum, elem_epno = cur_ep.get('dvdseason'), cur_ep.get('dvdepisodenumber') else: - elem_seasnum, elem_epno = cur_ep['SeasonNumber'], cur_ep['EpisodeNumber'] + elem_seasnum, elem_epno = cur_ep.get('airedseason'), cur_ep.get('airedepisodenumber') if None is elem_seasnum or None is elem_epno: - self.log('An episode has incomplete season/episode number (season: %r, episode: %r)' % ( - elem_seasnum, elem_epno), logger.WARNING) + log().warning('An episode has incomplete season/episode number (season: %r, episode: %r)' % ( + elem_seasnum, elem_epno)) continue # Skip to next episode # float() is because https://github.com/dbr/tvnamer/issues/95 - should probably be fixed in TVDB data seas_no = int(float(elem_seasnum)) ep_no = int(float(elem_epno)) - if self.config['dvdorder']: - dvd_order[('network', 'dvd')[use_dvd]] += ['S%02dE%02d' % (seas_no, ep_no)] - - for k, v in cur_ep.items(): + for k, v in cur_ep.iteritems(): k = k.lower() if None is not v: if 'filename' == k: - v = self._get_url_artwork(v) + v = self.config['url_artworkPrefix'] % v else: v = self._clean_data(v) + if k in ep_map_keys: + k = ep_map_keys[k] self._set_item(sid, seas_no, ep_no, k, v) - if self.config['dvdorder']: - num_dvd, num_network = [len(dvd_order[x]) for x in 'dvd', 'network'] - num_all = num_dvd + num_network - if num_all: - self.log('Of %s episodes, %s use the DVD order, and %s use the network aired order' % ( - num_all, num_dvd, num_network)) - for ep_numbers in [', '.join(dvd_order['dvd'][i:i + 5]) for i in xrange(0, num_dvd, 5)]: - self.log('Using DVD order: %s' % ep_numbers) - return True def _name_to_sid(self, name): @@ -893,10 +851,10 @@ class Tvdb: the correct SID. """ if name in self.corrections: - self.log('Correcting %s to %s' % (name, self.corrections[name])) + log().debug('Correcting %s to %s' % (name, self.corrections[name])) return self.corrections[name] else: - self.log('Getting show %s' % name) + log().debug('Getting show %s' % name) selected_series = self._get_series(name) if isinstance(selected_series, dict): selected_series = [selected_series] @@ -926,7 +884,7 @@ class Tvdb: selected_series = self._get_series(key) if isinstance(selected_series, dict): selected_series = [selected_series] - [[self._set_show_data(show['id'], k, v) for k, v in show.items()] for show in selected_series] + [[self._set_show_data(show['id'], k, v) for k, v in show.iteritems()] for show in selected_series] return selected_series def __repr__(self): diff --git a/lib/tvrage_api/tvrage_api.py b/lib/tvrage_api/tvrage_api.py index 23a70292..fffa531c 100644 --- a/lib/tvrage_api/tvrage_api.py +++ b/lib/tvrage_api/tvrage_api.py @@ -151,7 +151,7 @@ class Show(dict): # doesn't exist, so attribute error. raise tvrage_attributenotfound("Cannot find attribute %s" % (repr(key))) - def airedOn(self, date): + def aired_on(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) diff --git a/sickbeard/indexers/indexer_config.py b/sickbeard/indexers/indexer_config.py index b3b105ca..badc50f9 100644 --- a/sickbeard/indexers/indexer_config.py +++ b/sickbeard/indexers/indexer_config.py @@ -23,7 +23,7 @@ indexerConfig = { id=INDEXER_TVDB, name='TheTVDB', module=Tvdb, - api_params=dict(apikey='F9C450E78D99172E', language='en', useZip=True), + api_params=dict(apikey='F9C450E78D99172E', language='en'), active=True, dupekey='', mapped_only=False, diff --git a/sickbeard/metadata/generic.py b/sickbeard/metadata/generic.py index e61bdcec..1c6833d4 100644 --- a/sickbeard/metadata/generic.py +++ b/sickbeard/metadata/generic.py @@ -761,7 +761,10 @@ class GenericMetadata(): # There's gotta be a better way of doing this but we don't wanna # change the language value elsewhere lINDEXER_API_PARMS = sickbeard.indexerApi(show_obj.indexer).api_params.copy() - lINDEXER_API_PARMS['banners'] = True + if image_type.startswith('fanart'): + lINDEXER_API_PARMS['fanart'] = True + else: + lINDEXER_API_PARMS['banners'] = True lINDEXER_API_PARMS['dvdorder'] = 0 != show_obj.dvdorder if indexer_lang and not 'en' == indexer_lang: diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py index d4e2e202..241288e8 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -272,7 +272,7 @@ class NameParser(object): t = sickbeard.indexerApi(show.indexer).indexer(**lindexer_api_parms) - ep_obj = t[show.indexerid].airedOn(best_result.air_date)[0] + ep_obj = t[show.indexerid].aired_on(best_result.air_date)[0] season_number = int(ep_obj['seasonnumber']) episode_numbers = [int(ep_obj['episodenumber'])]