mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-02 17:33:37 +00:00
Change increase performance by reducing TVDb API requests with a global token.
Change raise tvdb_error if any of the episodes pages return an error instead of an incomplete episode list. Handle expired token.
This commit is contained in:
parent
8b384e22d7
commit
6d56cfa485
6 changed files with 70 additions and 21 deletions
|
@ -64,6 +64,7 @@
|
||||||
* Change only use newznab Api key if needed
|
* Change only use newznab Api key if needed
|
||||||
* Change editshow saving empty scene exceptions
|
* Change editshow saving empty scene exceptions
|
||||||
* Change improve TVDB data handling
|
* Change improve TVDB data handling
|
||||||
|
* Change increase performance by reducing TVDb API requests with a global token
|
||||||
|
|
||||||
|
|
||||||
[develop changelog]
|
[develop changelog]
|
||||||
|
|
|
@ -21,13 +21,15 @@ import requests
|
||||||
import requests.exceptions
|
import requests.exceptions
|
||||||
import datetime
|
import datetime
|
||||||
from sickbeard.helpers import getURL
|
from sickbeard.helpers import getURL
|
||||||
|
import sickbeard
|
||||||
|
|
||||||
from lib.dateutil.parser import parse
|
from lib.dateutil.parser import parse
|
||||||
from lib.cachecontrol import CacheControl, caches
|
from lib.cachecontrol import CacheControl, caches
|
||||||
|
|
||||||
from tvdb_ui import BaseUI, ConsoleUI
|
from tvdb_ui import BaseUI, ConsoleUI
|
||||||
from tvdb_exceptions import (tvdb_error, tvdb_shownotfound,
|
from tvdb_exceptions import (
|
||||||
tvdb_seasonnotfound, tvdb_episodenotfound, tvdb_attributenotfound)
|
tvdb_error, tvdb_shownotfound, tvdb_seasonnotfound, tvdb_episodenotfound,
|
||||||
|
tvdb_attributenotfound, tvdb_tokenexpired)
|
||||||
|
|
||||||
|
|
||||||
def log():
|
def log():
|
||||||
|
@ -59,6 +61,7 @@ def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None):
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def f_retry(*args, **kwargs):
|
def f_retry(*args, **kwargs):
|
||||||
mtries, mdelay = tries, delay
|
mtries, mdelay = tries, delay
|
||||||
|
auth_error = 0
|
||||||
while mtries > 1:
|
while mtries > 1:
|
||||||
try:
|
try:
|
||||||
return f(*args, **kwargs)
|
return f(*args, **kwargs)
|
||||||
|
@ -69,9 +72,17 @@ def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None):
|
||||||
else:
|
else:
|
||||||
print msg
|
print msg
|
||||||
time.sleep(mdelay)
|
time.sleep(mdelay)
|
||||||
mtries -= 1
|
if isinstance(e, tvdb_tokenexpired) and not auth_error:
|
||||||
mdelay *= backoff
|
auth_error += 1
|
||||||
return f(*args, **kwargs)
|
else:
|
||||||
|
mtries -= 1
|
||||||
|
mdelay *= backoff
|
||||||
|
try:
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
except tvdb_tokenexpired:
|
||||||
|
if not auth_error:
|
||||||
|
return f(*args, **kwargs)
|
||||||
|
raise tvdb_tokenexpired
|
||||||
|
|
||||||
return f_retry # true decorator
|
return f_retry # true decorator
|
||||||
|
|
||||||
|
@ -423,8 +434,6 @@ class Tvdb:
|
||||||
else:
|
else:
|
||||||
self.config['apikey'] = '0629B785CE550C8D' # tvdb_api's API key
|
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['debug_enabled'] = debug # show debugging messages
|
||||||
|
|
||||||
self.config['custom_ui'] = custom_ui
|
self.config['custom_ui'] = custom_ui
|
||||||
|
@ -501,23 +510,25 @@ class Tvdb:
|
||||||
self.config['url_artworkPrefix'] = 'https://thetvdb.com/banners/%s'
|
self.config['url_artworkPrefix'] = 'https://thetvdb.com/banners/%s'
|
||||||
|
|
||||||
def get_new_token(self):
|
def get_new_token(self):
|
||||||
token = None
|
token = sickbeard.THETVDB_V2_API_TOKEN.get('token', None)
|
||||||
|
dt = sickbeard.THETVDB_V2_API_TOKEN.get('datetime', datetime.datetime.fromordinal(1))
|
||||||
url = '%s%s' % (self.config['base_url'], 'login')
|
url = '%s%s' % (self.config['base_url'], 'login')
|
||||||
params = {'apikey': self.config['apikey']}
|
params = {'apikey': self.config['apikey']}
|
||||||
resp = getURL(url.strip(), post_json=params, json=True)
|
resp = getURL(url.strip(), post_json=params, json=True)
|
||||||
if resp:
|
if resp:
|
||||||
if 'token' in resp:
|
if 'token' in resp:
|
||||||
token = resp['token']
|
token = resp['token']
|
||||||
|
dt = datetime.datetime.now()
|
||||||
|
|
||||||
return {'token': token, 'datetime': datetime.datetime.now()}
|
return {'token': token, 'datetime': dt}
|
||||||
|
|
||||||
def get_token(self):
|
def get_token(self):
|
||||||
if self.token.get('token') is None or datetime.datetime.now() - self.token.get(
|
if sickbeard.THETVDB_V2_API_TOKEN.get('token') is None or datetime.datetime.now() - sickbeard.THETVDB_V2_API_TOKEN.get(
|
||||||
'datetime', datetime.datetime.fromordinal(1)) > datetime.timedelta(hours=23):
|
'datetime', datetime.datetime.fromordinal(1)) > datetime.timedelta(hours=23):
|
||||||
self.token = self.get_new_token()
|
sickbeard.THETVDB_V2_API_TOKEN = self.get_new_token()
|
||||||
if not self.token.get('token'):
|
if not sickbeard.THETVDB_V2_API_TOKEN.get('token'):
|
||||||
raise tvdb_error('Could not get Authentification Token')
|
raise tvdb_error('Could not get Authentification Token')
|
||||||
return self.token.get('token')
|
return sickbeard.THETVDB_V2_API_TOKEN.get('token')
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _get_temp_dir():
|
def _get_temp_dir():
|
||||||
|
@ -535,7 +546,7 @@ class Tvdb:
|
||||||
|
|
||||||
return os.path.join(tempfile.gettempdir(), 'tvdb_api-%s' % uid)
|
return os.path.join(tempfile.gettempdir(), 'tvdb_api-%s' % uid)
|
||||||
|
|
||||||
@retry(tvdb_error)
|
@retry((tvdb_error, tvdb_tokenexpired))
|
||||||
def _load_url(self, url, params=None, language=None):
|
def _load_url(self, url, params=None, language=None):
|
||||||
log().debug('Retrieving URL %s' % url)
|
log().debug('Retrieving URL %s' % url)
|
||||||
|
|
||||||
|
@ -554,7 +565,19 @@ class Tvdb:
|
||||||
if None is not language and language in self.config['valid_languages']:
|
if None is not language and language in self.config['valid_languages']:
|
||||||
session.headers.update({'Accept-Language': language})
|
session.headers.update({'Accept-Language': language})
|
||||||
|
|
||||||
resp = getURL(url.strip(), params=params, session=session, json=True)
|
resp = None
|
||||||
|
try:
|
||||||
|
resp = getURL(url.strip(), params=params, session=session, json=True, raise_status_code=True,
|
||||||
|
raise_exceptions=True)
|
||||||
|
except requests.exceptions.HTTPError as e:
|
||||||
|
if 401 == e.response.status_code:
|
||||||
|
# token expired, get new token, raise error to retry
|
||||||
|
sickbeard.THETVDB_V2_API_TOKEN = self.get_new_token()
|
||||||
|
raise tvdb_tokenexpired
|
||||||
|
elif 404 != e.response.status_code:
|
||||||
|
raise tvdb_error
|
||||||
|
except (StandardError, Exception):
|
||||||
|
raise tvdb_error
|
||||||
|
|
||||||
map_show = {'airstime': 'airs_time', 'airsdayofweek': 'airs_dayofweek', 'imdbid': 'imdb_id'}
|
map_show = {'airstime': 'airs_time', 'airsdayofweek': 'airs_dayofweek', 'imdbid': 'imdb_id'}
|
||||||
|
|
||||||
|
@ -803,6 +826,8 @@ class Tvdb:
|
||||||
episodes = []
|
episodes = []
|
||||||
while page is not None:
|
while page is not None:
|
||||||
episode_data = self._getetsrc(self.config['url_epInfo'] % (sid, page), language=language)
|
episode_data = self._getetsrc(self.config['url_epInfo'] % (sid, page), language=language)
|
||||||
|
if [] is episode_data:
|
||||||
|
raise tvdb_error('Exception retrieving episodes for show')
|
||||||
if isinstance(episode_data, dict) and episode_data['data'] is not None:
|
if isinstance(episode_data, dict) and episode_data['data'] is not None:
|
||||||
episodes.extend(episode_data['data'])
|
episodes.extend(episode_data['data'])
|
||||||
page = episode_data['links']['next'] if isinstance(episode_data, dict) \
|
page = episode_data['links']['next'] if isinstance(episode_data, dict) \
|
||||||
|
|
|
@ -50,3 +50,8 @@ class tvdb_attributenotfound(tvdb_exception):
|
||||||
attribute (such as a episode name)
|
attribute (such as a episode name)
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class tvdb_tokenexpired(tvdb_exception):
|
||||||
|
"""token expired or missing thetvdb.com
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
|
@ -506,6 +506,8 @@ else:
|
||||||
TRAKT_PIN_URL = 'https://trakt.tv/pin/6314'
|
TRAKT_PIN_URL = 'https://trakt.tv/pin/6314'
|
||||||
TRAKT_BASE_URL = 'https://api.trakt.tv/'
|
TRAKT_BASE_URL = 'https://api.trakt.tv/'
|
||||||
|
|
||||||
|
THETVDB_V2_API_TOKEN = {'token': None, 'datetime': datetime.datetime.fromordinal(1)}
|
||||||
|
|
||||||
COOKIE_SECRET = base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes)
|
COOKIE_SECRET = base64.b64encode(uuid.uuid4().bytes + uuid.uuid4().bytes)
|
||||||
|
|
||||||
CACHE_IMAGE_URL_LIST = classes.ImageUrlList()
|
CACHE_IMAGE_URL_LIST = classes.ImageUrlList()
|
||||||
|
|
|
@ -1100,7 +1100,8 @@ def proxy_setting(proxy_setting, request_url, force=False):
|
||||||
return (False, proxy_address)[request_url_match], True
|
return (False, proxy_address)[request_url_match], True
|
||||||
|
|
||||||
|
|
||||||
def getURL(url, post_data=None, params=None, headers=None, timeout=30, session=None, json=False, raise_status_code=False, **kwargs):
|
def getURL(url, post_data=None, params=None, headers=None, timeout=30, session=None, json=False,
|
||||||
|
raise_status_code=False, raise_exceptions=False, **kwargs):
|
||||||
"""
|
"""
|
||||||
Returns a byte-string retrieved from the url provider.
|
Returns a byte-string retrieved from the url provider.
|
||||||
"""
|
"""
|
||||||
|
@ -1197,16 +1198,22 @@ def getURL(url, post_data=None, params=None, headers=None, timeout=30, session=N
|
||||||
if 'mute_connect_err' not in mute:
|
if 'mute_connect_err' not in mute:
|
||||||
logger.log(u'Connection error msg:%s while loading URL%s' % (
|
logger.log(u'Connection error msg:%s while loading URL%s' % (
|
||||||
e.message, _maybe_request_url(e)), logger.WARNING)
|
e.message, _maybe_request_url(e)), logger.WARNING)
|
||||||
|
if raise_exceptions:
|
||||||
|
raise e
|
||||||
return
|
return
|
||||||
except requests.exceptions.ReadTimeout as e:
|
except requests.exceptions.ReadTimeout as e:
|
||||||
if 'mute_read_timeout' not in mute:
|
if 'mute_read_timeout' not in mute:
|
||||||
logger.log(u'Read timed out msg:%s while loading URL%s' % (
|
logger.log(u'Read timed out msg:%s while loading URL%s' % (
|
||||||
e.message, _maybe_request_url(e)), logger.WARNING)
|
e.message, _maybe_request_url(e)), logger.WARNING)
|
||||||
|
if raise_exceptions:
|
||||||
|
raise e
|
||||||
return
|
return
|
||||||
except (requests.exceptions.Timeout, socket.timeout) as e:
|
except (requests.exceptions.Timeout, socket.timeout) as e:
|
||||||
if 'mute_connect_timeout' not in mute:
|
if 'mute_connect_timeout' not in mute:
|
||||||
logger.log(u'Connection timed out msg:%s while loading URL %s' % (
|
logger.log(u'Connection timed out msg:%s while loading URL %s' % (
|
||||||
e.message, _maybe_request_url(e, url)), logger.WARNING)
|
e.message, _maybe_request_url(e, url)), logger.WARNING)
|
||||||
|
if raise_exceptions:
|
||||||
|
raise e
|
||||||
return
|
return
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if e.message:
|
if e.message:
|
||||||
|
@ -1215,6 +1222,8 @@ def getURL(url, post_data=None, params=None, headers=None, timeout=30, session=N
|
||||||
else:
|
else:
|
||||||
logger.log(u'Unknown exception while loading URL %s\r\nDetail... %s'
|
logger.log(u'Unknown exception while loading URL %s\r\nDetail... %s'
|
||||||
% (url, traceback.format_exc()), logger.WARNING)
|
% (url, traceback.format_exc()), logger.WARNING)
|
||||||
|
if raise_exceptions:
|
||||||
|
raise e
|
||||||
return
|
return
|
||||||
|
|
||||||
if json:
|
if json:
|
||||||
|
@ -1223,6 +1232,8 @@ def getURL(url, post_data=None, params=None, headers=None, timeout=30, session=N
|
||||||
return ({}, data_json)[isinstance(data_json, (dict, list))]
|
return ({}, data_json)[isinstance(data_json, (dict, list))]
|
||||||
except (TypeError, Exception) as e:
|
except (TypeError, Exception) as e:
|
||||||
logger.log(u'JSON data issue from URL %s\r\nDetail... %s' % (url, e.message), logger.WARNING)
|
logger.log(u'JSON data issue from URL %s\r\nDetail... %s' % (url, e.message), logger.WARNING)
|
||||||
|
if raise_exceptions:
|
||||||
|
raise e
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return resp.content
|
return resp.content
|
||||||
|
|
|
@ -7,17 +7,22 @@
|
||||||
|
|
||||||
from lib.tvdb_api.tvdb_exceptions import \
|
from lib.tvdb_api.tvdb_exceptions import \
|
||||||
tvdb_exception, tvdb_attributenotfound, tvdb_episodenotfound, tvdb_error, \
|
tvdb_exception, tvdb_attributenotfound, tvdb_episodenotfound, tvdb_error, \
|
||||||
tvdb_seasonnotfound, tvdb_shownotfound, tvdb_userabort
|
tvdb_seasonnotfound, tvdb_shownotfound, tvdb_userabort, tvdb_tokenexpired
|
||||||
|
|
||||||
indexerExcepts = ["indexer_exception", "indexer_error", "indexer_userabort", "indexer_shownotfound",
|
indexerExcepts = [
|
||||||
"indexer_seasonnotfound", "indexer_episodenotfound", "indexer_attributenotfound"]
|
'indexer_exception', 'indexer_error', 'indexer_userabort',
|
||||||
|
'indexer_shownotfound', 'indexer_seasonnotfound', 'indexer_episodenotfound',
|
||||||
|
'indexer_attributenotfound', 'indexer_authenticationerror']
|
||||||
|
|
||||||
tvdbExcepts = ["tvdb_exception", "tvdb_error", "tvdb_userabort", "tvdb_shownotfound",
|
tvdbExcepts = [
|
||||||
"tvdb_seasonnotfound", "tvdb_episodenotfound", "tvdb_attributenotfound"]
|
'tvdb_exception', 'tvdb_error', 'tvdb_userabort', 'tvdb_shownotfound',
|
||||||
|
'tvdb_seasonnotfound', 'tvdb_episodenotfound', 'tvdb_attributenotfound',
|
||||||
|
'tvdb_tokenexpired']
|
||||||
|
|
||||||
# link API exceptions to our exception handler
|
# link API exceptions to our exception handler
|
||||||
indexer_exception = tvdb_exception
|
indexer_exception = tvdb_exception
|
||||||
indexer_error = tvdb_error
|
indexer_error = tvdb_error
|
||||||
|
indexer_authenticationerror = tvdb_tokenexpired
|
||||||
indexer_userabort = tvdb_userabort
|
indexer_userabort = tvdb_userabort
|
||||||
indexer_attributenotfound = tvdb_attributenotfound
|
indexer_attributenotfound = tvdb_attributenotfound
|
||||||
indexer_episodenotfound = tvdb_episodenotfound
|
indexer_episodenotfound = tvdb_episodenotfound
|
||||||
|
|
Loading…
Reference in a new issue