Commit 9fb3962b authored by echel0n's avatar echel0n
Browse files

Refactored how TheTVDB api handles exceptions and how those are passed on and...

Refactored how TheTVDB api handles exceptions and how those are passed on and handled inside SR core
parent 54b25045
......@@ -65,17 +65,19 @@ def indexerImage(id=None, which=None):
if media_format == "thumb":
image_path = os.path.join(ImageCache()._thumbnails_dir(), image_name)
if not os.path.exists(image_path):
image_url = t.images(int(id), key_type=image_type)[0]['thumbnail']
WebSession().download(image_url, image_path)
image_data = t.images(int(id), key_type=image_type)
if image_data:
image_url = image_data[0]['thumbnail']
WebSession().download(image_url, image_path)
else:
image_path = os.path.join(ImageCache()._cache_dir(), image_name)
if not os.path.exists(image_path):
image_url = t.images(int(id), key_type=image_type)[0]['filename']
WebSession().download(image_url, image_path)
image_data = t.images(int(id), key_type=image_type)
if image_data:
image_url = image_data[0]['filename']
WebSession().download(image_url, image_path)
except (KeyError, IndexError):
pass
except (indexer_error, IOError) as e:
sickrage.app.log.warning("{}: Unable to look up show on ".format(id) + IndexerApi(INDEXER_TVDB).name + ", not downloading images: {}".format(e))
if image_type == 'banner':
return Banner(int(id), media_format)
......
......@@ -257,25 +257,23 @@ class NameParser(object):
episode_numbers = []
if not season_number or not episode_numbers:
try:
lINDEXER_API_PARMS = IndexerApi(show_obj.indexer).api_params.copy()
lINDEXER_API_PARMS['language'] = show_obj.lang or sickrage.app.config.indexer_default_language
t = IndexerApi(show_obj.indexer).indexer(**lINDEXER_API_PARMS)
epObj = t[show_obj.indexer_id].airedOn(best_result.air_date)[0]
season_number = int(epObj["airedseason"])
episode_numbers = [int(epObj["airedepisodenumber"])]
except indexer_episodenotfound:
if best_result.in_showlist:
sickrage.app.log.warning("Unable to find episode with date {air_date} for show {show}, "
"skipping".format(air_date=best_result.air_date, show=show_obj.name))
episode_numbers = []
except indexer_error as e:
sickrage.app.log.warning("Unable to contact " + IndexerApi(show_obj.indexer).name + ": {}".format(e))
episode_numbers = []
lINDEXER_API_PARMS = IndexerApi(show_obj.indexer).api_params.copy()
lINDEXER_API_PARMS['language'] = show_obj.lang or sickrage.app.config.indexer_default_language
t = IndexerApi(show_obj.indexer).indexer(**lINDEXER_API_PARMS)
indexer_show = t[show_obj.indexer_id]
if indexer_show:
epObj = indexer_show.airedOn(best_result.air_date)
if not epObj:
if best_result.in_showlist:
sickrage.app.log.warning("Unable to find episode with date {air_date} for show {show}, "
"skipping".format(air_date=best_result.air_date, show=show_obj.name))
episode_numbers = []
else:
season_number = int(epObj[0]["airedseason"])
episode_numbers = [int(epObj[0]["airedepisodenumber"])]
for epNo in episode_numbers:
s = season_number
......
......@@ -266,46 +266,16 @@ class QueueItemAdd(ShowQueueItem):
index_name = IndexerApi(self.indexer).name
# make sure the Indexer IDs are valid
try:
lINDEXER_API_PARMS = IndexerApi(self.indexer).api_params.copy()
lINDEXER_API_PARMS['cache'] = False
lINDEXER_API_PARMS['language'] = self.lang or sickrage.app.config.indexer_default_language
lINDEXER_API_PARMS = IndexerApi(self.indexer).api_params.copy()
lINDEXER_API_PARMS['cache'] = False
lINDEXER_API_PARMS['language'] = self.lang or sickrage.app.config.indexer_default_language
sickrage.app.log.info("{}: {}".format(index_name, repr(lINDEXER_API_PARMS)))
sickrage.app.log.info("{}: {}".format(index_name, repr(lINDEXER_API_PARMS)))
t = IndexerApi(self.indexer).indexer(**lINDEXER_API_PARMS)
try:
s = t[self.indexer_id]
except indexer_error:
s = None
if not s:
return self._finish_early()
# this usually only happens if they have an NFO in their show dir which gave us a Indexer ID that has no
# proper english version of the show
try:
s.seriesname
except AttributeError:
sickrage.app.log.warning("Show in {} has no name on {}, probably the wrong language used to search with".format(self.showDir, index_name))
sickrage.app.alerts.error(_("Unable to add show"),
_("Show in {} has no name on {}, probably the wrong language. Delete .nfo "
"and add manually in the correct language").format(self.showDir, index_name))
return self._finish_early()
# if the show has no episodes/seasons
if not len(s):
sickrage.app.log.warning(
"Show " + str(s['seriesname']) + " is on " + str(IndexerApi(self.indexer).name) + " but contains no season/episode data.")
sickrage.app.alerts.error(_("Unable to add show"),
_("Show ") + str(s['seriesname']) + _(" is on ") + str(IndexerApi(self.indexer).name) + _(
" but contains no season/episode data."))
return self._finish_early()
except Exception as e:
sickrage.app.log.error("{}: Error while loading information from indexer {}. Error: {}".format(self.indexer_id, index_name, e))
t = IndexerApi(self.indexer).indexer(**lINDEXER_API_PARMS)
s = t[self.indexer_id]
if not s:
sickrage.app.alerts.error(
_("Unable to add show"),
_("Unable to look up the show in {} on {} using ID {}, not using the NFO. Delete .nfo and try adding "
......@@ -328,6 +298,26 @@ class QueueItemAdd(ShowQueueItem):
return self._finish_early()
# this usually only happens if they have an NFO in their show dir which gave us a Indexer ID that has no
# proper english version of the show
try:
s.seriesname
except AttributeError:
sickrage.app.log.warning("Show in {} has no name on {}, probably the wrong language used to search with".format(self.showDir, index_name))
sickrage.app.alerts.error(_("Unable to add show"),
_("Show in {} has no name on {}, probably the wrong language. Delete .nfo "
"and add manually in the correct language").format(self.showDir, index_name))
return self._finish_early()
# if the show has no episodes/seasons
if not len(s):
sickrage.app.log.warning("Show " + str(s['seriesname']) + " is on " + str(IndexerApi(self.indexer).name) + "but contains no season/episode "
"data.")
sickrage.app.alerts.error(_("Unable to add show"),
_("Show ") + str(s['seriesname']) + _(" is on ") + str(IndexerApi(self.indexer).name) + _(
" but contains no season/episode data."))
return self._finish_early()
try:
# add show to database
show_obj = TVShow(self.indexer_id, self.indexer, lang=self.lang, location=self.showDir)
......
......@@ -421,7 +421,12 @@ class TVEpisode(object):
lINDEXER_API_PARMS['dvdorder'] = True
t = IndexerApi(self.indexer).indexer(**lINDEXER_API_PARMS)
myEp = t[self.show.indexer_id][season][episode]
indexer_data = t[self.show.indexer_id]
if not indexer_data:
return False
myEp = indexer_data[season][episode]
else:
myEp = cachedSeason[episode]
except (indexer_error, IOError) as e:
......
......@@ -1552,13 +1552,11 @@ class CMD_SiCKRAGESearchIndexers(ApiCall):
t = IndexerApi(_indexer).indexer(**lINDEXER_API_PARMS)
try:
apiData = t[self.name]
except (indexer_shownotfound, indexer_showincomplete, indexer_error):
sickrage.app.log.warning("Unable to find show with id " + str(self.indexerid))
indexer_data = t[self.name]
if not indexer_data:
continue
for curSeries in apiData:
for curSeries in indexer_data:
results.append({indexer_ids[_indexer]: int(curSeries['id']),
"name": curSeries['seriesname'],
"first_aired": curSeries['firstaired'],
......@@ -1574,16 +1572,12 @@ class CMD_SiCKRAGESearchIndexers(ApiCall):
t = IndexerApi(_indexer).indexer(**lINDEXER_API_PARMS)
try:
myShow = t[int(self.indexerid)]
except (indexer_shownotfound, indexer_showincomplete, indexer_error):
sickrage.app.log.warning("Unable to find show with id " + str(self.indexerid))
return await _responds(RESULT_SUCCESS, {"results": [], "langid": lang_id})
myShow = t[int(self.indexerid)]
if not myShow:
continue
if not myShow.data['seriesname']:
sickrage.app.log.debug(
"Found show with indexer_id: " + str(
self.indexerid) + ", however it contained no show name")
sickrage.app.log.debug("Found show with indexer_id: " + str(self.indexerid) + ", however it contained no show name")
return await _responds(RESULT_FAILURE, msg="Show contains no name, invalid result")
# found show
......@@ -1591,6 +1585,8 @@ class CMD_SiCKRAGESearchIndexers(ApiCall):
"name": myShow.data['seriesname'],
"first_aired": myShow.data['firstaired'],
"indexer": int(_indexer)}]
# break from loop, result found!
break
return await _responds(RESULT_SUCCESS, {"results": results, "langid": lang_id})
......
......@@ -99,16 +99,16 @@ class SearchIndexersForShowNameHandler(BaseHandler, ABC):
sickrage.app.log.debug("Searching for Show with term: %s on Indexer: %s" % (search_term, IndexerApi(indexer).name))
try:
# search via series name
result = t[search_term]
if isinstance(result, dict):
result = [result]
results.setdefault(indexer, []).extend(result)
except Exception:
# search via series name
result = t[search_term]
if not result:
continue
if isinstance(result, dict):
result = [result]
results.setdefault(indexer, []).extend(result)
for i, shows in results.items():
final_results.extend([
[IndexerApi(i).name, i, IndexerApi(i).config["show_url"],
......
......@@ -77,12 +77,12 @@ class IndexerApi(object):
# Query Indexers for each search term and build the list of results
lINDEXER_API_PARMS = self.api_params.copy()
lINDEXER_API_PARMS['custom_ui'] = custom_ui or ShowListUI
t = self.indexer(**lINDEXER_API_PARMS)
sickrage.app.log.debug("Trying to find show ID for show {} on indexer {}".format(show_name, self.name))
try:
search = t[show_name]
return search['id']
except Exception:
pass
t = self.indexer(**lINDEXER_API_PARMS)
indexer_data = t[show_name]
if not indexer_data:
return
return indexer_data['id']
......@@ -49,13 +49,10 @@ def map_indexers(indexer, indexer_id, name):
indexer_api_parms = IndexerApi(mindexer).api_params.copy()
indexer_api_parms['custom_ui'] = ShowListUI
t = IndexerApi(mindexer).indexer(**indexer_api_parms)
try:
mapped_show = t[name]
except Exception:
sickrage.app.log.debug(
"Unable to map " + IndexerApi(indexer).name + "->" + IndexerApi(mindexer).name + " for show: " + name + ", skipping it")
t = IndexerApi(mindexer).indexer(**indexer_api_parms)
mapped_show = t[name]
if not mapped_show:
continue
if mapped_show and len(mapped_show) == 1:
......
......@@ -149,7 +149,8 @@ class Show(dict):
def airedOn(self, date):
ret = self.search(str(date), 'firstaired')
if len(ret) == 0:
raise tvdb_episodenotfound("Could not find any episodes that aired on {}".format(date))
sickrage.app.log.debug("Could not find any episodes on TheTVDB that aired on {}".format(date))
return None
return ret
def search(self, term=None, key=None):
......@@ -379,20 +380,23 @@ class Tvdb:
self.jwt_token = None
def _refresh(self):
self.jwt_token = self._request('get', self.config['api']['refresh'])['token']
resp = self._request('get', self.config['api']['refresh'])
if resp and 'token' in resp:
self.jwt_token = resp['token']
def _login(self):
self.jwt_token = self._request('post', self.config['api']['login'], json={'apikey': self.config['apikey']})['token']
resp = self._request('post', self.config['api']['login'], json={'apikey': self.config['apikey']})
if resp and 'token' in resp:
self.jwt_token = resp['token']
def authenticate(self):
for i in range(0, 3):
try:
if not self.jwt_token or self.jwt_is_expired:
return self._login()
elif self.jwt_time_remaining < 7200:
return self._refresh()
except Exception as e:
self.logout()
try:
if not self.jwt_token or self.jwt_is_expired:
return self._login()
elif self.jwt_time_remaining < 7200:
return self._refresh()
except Exception as e:
self.logout()
def jwt_decode(self, data):
# make sure data is binary
......@@ -447,21 +451,27 @@ class Tvdb:
try:
data = resp.json()
except ValueError:
raise tvdb_error("Unable to parse data from TheTVDB")
sickrage.app.log.debug("Unable to parse data from TheTVDB")
return None
return to_lowercase(data)
if resp is not None:
if resp.status_code == 401:
if i > 3:
sickrage.app.log.debug("Unable to authenticate to TheTVDB")
return None
raise tvdb_unauthorized(resp.text)
elif resp.status_code == 504:
raise tvdb_error("Unable to connect to TheTVDB")
sickrage.app.log.debug("Unable to connect to TheTVDB")
return None
if 'application/json' in resp.headers.get('content-type', '') and i > 3:
raise tvdb_error(resp.json().get('Error', resp.text))
sickrage.app.log.debug(resp.json().get('Error', resp.text))
return None
if i > 3:
raise tvdb_error("Unable to connect to TheTVDB")
return None
def _setItem(self, sid, seas, ep, attrib, value):
"""Creates a new episode, creating Show(), Season() and
......@@ -514,10 +524,14 @@ class Tvdb:
if not re.search(r'tt\d+', series):
sickrage.app.log.debug("Searching for show by name: {}".format(series))
return self._request('get', self.config['api']['getSeries'].format(name=series))['data']
resp = self._request('get', self.config['api']['getSeries'].format(name=series))
if resp and 'data' in resp:
return resp['data']
else:
sickrage.app.log.debug("Searching for show by imdbId: {}".format(series))
return self._request('get', self.config['api']['getSeriesIMDB'].format(id=series))['data']
resp = self._request('get', self.config['api']['getSeriesIMDB'].format(id=series))
if resp and 'data' in resp:
return resp['data']
# elif zap2itid:
# sickrage.app.log.debug("Searching for show by zap2itId: {}".format(zap2itid))
# return self._request('get', self.config['api']['getSeriesZap2It'].format(id=zap2itid))['data']
......@@ -530,8 +544,8 @@ class Tvdb:
"""
allSeries = self.search(series)
if not allSeries:
sickrage.app.log.debug('Series result returned zero')
raise tvdb_shownotfound("Show search returned zero results (cannot find show on theTVDB)")
sickrage.app.log.debug('Show search returned zero results (cannot find show on TheTVDB')
return None
ui = BaseUI(config=self.config)
if self.config['custom_ui'] is not None:
......@@ -547,20 +561,21 @@ class Tvdb:
"""
# Parse show information
sickrage.app.log.debug('Getting all series data for {}'.format(sid))
sickrage.app.log.debug('[{}]: Getting all series data from TheTVDB'.format(sid))
try:
# get series info in english
series_info = self._request('get', self.config['api']['series'].format(id=sid), lang=self.config['api']['lang'])['data']
# get series info in english
resp = self._request('get', self.config['api']['series'].format(id=sid), lang=self.config['api']['lang'])
if not resp or 'data' not in resp:
sickrage.app.log.debug("[{}]: Unable to locate show on TheTVDB".format(sid))
return None
# translate if required to provided language
if not self.config['language'] == self.config['api']['lang']:
series_info.update((k, v) for k, v in self._request('get', self.config['api']['series'].format(id=sid))['data'].items() if v)
except tvdb_unauthorized:
raise tvdb_unauthorized
except Exception as e:
sickrage.app.log.debug("[{}]: Series result returned zero, ERROR: {}".format(sid, e))
raise tvdb_error("[{}]: Series result returned zero, ERROR: {}".format(sid, e))
series_info = resp['data']
# translate if required to provided language
if not self.config['language'] == self.config['api']['lang']:
resp = self._request('get', self.config['api']['series'].format(id=sid))
if resp and 'data' in resp:
series_info.update((k, v) for k, v in resp['data'].items() if v)
# get series data
for k, v in series_info.items():
......@@ -575,7 +590,7 @@ class Tvdb:
self._setShowData(sid, k, v)
# Parse episode data
sickrage.app.log.debug('Getting all episode data for {}'.format(sid))
sickrage.app.log.debug('[{}]: Getting episode data from TheTVDB'.format(sid))
episodes = []
page = pages = 1
......@@ -585,42 +600,42 @@ class Tvdb:
break
episode_info = self._request('get', self.config['api']['episodes'].format(id=sid), lang=self.config['api']['lang'], params={'page': page})
if not episode_info or 'links' not in episode_info or 'data' not in episode_info:
break
pages = episode_info['links']['last']
try:
# translate if required to provided language
if not self.config['language'] == self.config['api']['lang']:
intl_episode_info = self._request('get', self.config['api']['episodes'].format(id=sid), params={'page': page})
for d1, d2 in zip(episode_info['data'], intl_episode_info['data']):
d1.update((k, v) for k, v in d2.items() if v)
episodes.append(d1)
else:
episodes += episode_info['data']
# translate if required to provided language
if not self.config['language'] == self.config['api']['lang']:
intl_episode_info = self._request('get', self.config['api']['episodes'].format(id=sid), params={'page': page})
if not intl_episode_info or 'data' not in intl_episode_info:
break
page += 1
except tvdb_error:
break
for d1, d2 in zip(episode_info['data'], intl_episode_info['data']):
d1.update((k, v) for k, v in d2.items() if v)
episodes.append(d1)
else:
episodes += episode_info['data']
page += 1
if not len(episodes):
sickrage.app.log.debug('Series results incomplete')
raise tvdb_attributenotfound("[{}]: Series results incomplete".format(sid))
sickrage.app.log.debug('Series {} results incomplete on TheTVDB'.format(sid))
return None
episode_incomplete = False
for cur_ep in episodes:
try:
use_dvd = False
if self.config['dvdorder']:
sickrage.app.log.debug('Using DVD ordering.')
use_dvd = all([cur_ep.get('dvdseason'), cur_ep.get('dvdepisodenumber')])
seasnum, epno = cur_ep.get('airedseason'), cur_ep.get('airedepisodenumber')
if use_dvd:
seasnum, epno = cur_ep.get('dvdseason'), cur_ep.get('dvdepisodenumber')
if seasnum is None or epno is None:
raise Exception
except Exception as e:
use_dvd = False
if self.config['dvdorder']:
sickrage.app.log.debug('Using DVD ordering.')
use_dvd = all([cur_ep.get('dvdseason'), cur_ep.get('dvdepisodenumber')])
seasnum, epno = cur_ep.get('airedseason'), cur_ep.get('airedepisodenumber')
if use_dvd:
seasnum, epno = cur_ep.get('dvdseason'), cur_ep.get('dvdepisodenumber')
if seasnum is None or epno is None:
episode_incomplete = True
continue
......@@ -653,12 +668,11 @@ class Tvdb:
def image_key_types(self, sid, season=None, language='en'):
key_types = {}
try:
data = self._request('get', self.config['api']['images']['params'].format(id=sid), language)['data']
except tvdb_error:
resp = self._request('get', self.config['api']['images']['params'].format(id=sid), language)
if not resp or 'data' not in resp:
return key_types
for item in data:
for item in resp['data']:
key_type = item['keytype']
resolution = item['resolution']
subkey = item['subkey']
......@@ -683,21 +697,21 @@ class Tvdb:
sickrage.app.log.debug('Getting {} images for {}'.format(key_type, sid))
images = []
for language in [self.config['api']['lang'], self.config['language']]:
try:
key_types = self.image_key_types(sid, season, language)
if not key_types or key_type not in key_types:
continue
if not season:
images = self._request('get', self.config['api']['images'][key_type].format(id=sid), language)['data']
else:
images = self._request('get', self.config['api']['images'][key_type].format(id=sid, season=season), language)['data']
except tvdb_unauthorized:
raise tvdb_unauthorized
except tvdb_error:
for language in [self.config['api']['lang'], self.config['language']]:
key_types = self.image_key_types(sid, season, language)
if not key_types or key_type not in key_types:
continue
if not season:
resp = self._request('get', self.config['api']['images'][key_type].format(id=sid), language)
if resp and 'data' in resp:
images = resp['data']
else:
resp = self._request('get', self.config['api']['images'][key_type].format(id=sid, season=season), language)
if resp and 'data' in resp:
images = resp['data']
# unable to retrieve images in languages wanted
if not images:
return []
......@@ -720,25 +734,28 @@ class Tvdb:
cur_actors = Actors()
try:
for cur_actor in self._request('get', self.config['api']['actors'].format(id=sid))['data']:
curActor = Actor()
for k, v in cur_actor.items():
if not all([k, v]): continue
v = (v, self.config['api']['images']['prefix'].format(value=v))[k == 'image']
curActor[k] = v
cur_actors.append(curActor)
except tvdb_unauthorized:
raise tvdb_unauthorized
except Exception:
resp = self._request('get', self.config['api']['actors'].format(id=sid))
if not resp or 'data' not in resp:
sickrage.app.log.debug('Actors result returned zero')
return cur_actors
for cur_actor in resp['data']:
cur_actor = Actor()
for k, v in cur_actor.items():
if not all([k, v]):
continue
v = (v, self.config['api']['images']['prefix'].format(value=v))[k == 'image']
cur_actor[k] = v
cur_actors.append(cur_actor)
return cur_actors
@login_required
def updated(self, fromTime):
return self._request('get', self.config['api']['updated'].format(time=fromTime))['data']
resp = self._request('get', self.config['api']['updated'].format(time=fromTime))
if resp and 'data' in resp:
return resp['data']
@property
def languages(self):
......
......@@ -382,7 +382,6 @@ class GenericMetadata(object):
"""
data = self._ep_data(ep_obj)