diff --git a/CHANGES.md b/CHANGES.md index 9e4eb8f..877076a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -106,6 +106,12 @@ * Fix glide cursor left and right key collisions with ctrl + alt/meta with left and right +### 0.24.16 (2021-08-28 16:05:00 UTC) + +* Update Windows recommended modules lxml, pip, regex, setuptools, and add cffi, python-Levenshtein +* Change newznab provider add handler for http response code 401 + + ### 0.24.15 (2021-08-05 11:45:00 UTC) * Change media process move process method for *nix systems that don't support native move diff --git a/recommended.txt b/recommended.txt index 0622006..1a3ba85 100644 --- a/recommended.txt +++ b/recommended.txt @@ -1,25 +1,29 @@ +cffi@https://raw.githubusercontent.com/wiki/SickGear/SickGear/packages/cffi-1.14.6-cp310-cp310-win_amd64.whl ; '3.10' <= python_version and 'Windows' == platform_system and ('AMD64' == platform_machine or 'x86_64' == platform_machine) +cffi@https://raw.githubusercontent.com/wiki/SickGear/SickGear/packages/cffi-1.14.6-cp310-cp310-win32.whl ; '3.10' <= python_version and 'Windows' == platform_system and ('AMD64' != platform_machine and 'x86_64' != platform_machine) cryptography; '3.7' <= python_version cryptography <= 3.2.1; '3.0' > python_version -lxml >= 4.6.1 +lxml >= 4.6.3 lxml@https://raw.githubusercontent.com/wiki/SickGear/SickGear/packages/lxml-4.6.3-cp310-cp310-win_amd64.whl ; '3.10' <= python_version and 'Windows' == platform_system and ('AMD64' == platform_machine or 'x86_64' == platform_machine) lxml@https://raw.githubusercontent.com/wiki/SickGear/SickGear/packages/lxml-4.6.3-cp310-cp310-win32.whl ; '3.10' <= python_version and 'Windows' == platform_system and ('AMD64' != platform_machine and 'x86_64' != platform_machine) -pip >= 20.0.0; '3.7' <= python_version +pip >= 21.2.4; '3.7' <= python_version pip <= 19.3.1; '3.0' > python_version python-Levenshtein >= 0.12.2; '3.7' <= python_version and 'Windows' == platform_system python-Levenshtein >= 0.12.0, != 0.12.1; '3.7' <= python_version and 'Windows' != platform_system +python-Levenshtein@https://raw.githubusercontent.com/wiki/SickGear/SickGear/packages/python_Levenshtein-0.12.2-cp310-cp310-win_amd64.whl ; '3.10' == python_version and 'Windows' == platform_system and ('AMD64' == platform_machine or 'x86_64' == platform_machine) python-Levenshtein@https://raw.githubusercontent.com/wiki/SickGear/SickGear/packages/python_Levenshtein-0.12.2-cp39-cp39-win_amd64.whl ; '3.9' == python_version and 'Windows' == platform_system and ('AMD64' == platform_machine or 'x86_64' == platform_machine) python-Levenshtein@https://raw.githubusercontent.com/wiki/SickGear/SickGear/packages/python_Levenshtein-0.12.2-cp38-cp38-win_amd64.whl ; '3.8' == python_version and 'Windows' == platform_system and ('AMD64' == platform_machine or 'x86_64' == platform_machine) python-Levenshtein@https://raw.githubusercontent.com/wiki/SickGear/SickGear/packages/python_Levenshtein-0.12.2-cp37-cp37m-win_amd64.whl ; '3.7' == python_version and 'Windows' == platform_system and ('AMD64' == platform_machine or 'x86_64' == platform_machine) +python-Levenshtein@https://raw.githubusercontent.com/wiki/SickGear/SickGear/packages/python_Levenshtein-0.12.2-cp310-cp310-win32.whl ; '3.10' == python_version and 'Windows' == platform_system and ('AMD64' != platform_machine and 'x86_64' != platform_machine) python-Levenshtein@https://raw.githubusercontent.com/wiki/SickGear/SickGear/packages/python_Levenshtein-0.12.2-cp39-cp39-win32.whl ; '3.9' == python_version and 'Windows' == platform_system and ('AMD64' != platform_machine and 'x86_64' != platform_machine) python-Levenshtein@https://raw.githubusercontent.com/wiki/SickGear/SickGear/packages/python_Levenshtein-0.12.2-cp38-cp38-win32.whl ; '3.8' == python_version and 'Windows' == platform_system and ('AMD64' != platform_machine and 'x86_64' != platform_machine) python-Levenshtein@https://raw.githubusercontent.com/wiki/SickGear/SickGear/packages/python_Levenshtein-0.12.2-cp37-cp37m-win32.whl ; '3.7' == python_version and 'Windows' == platform_system and ('AMD64' != platform_machine and 'x86_64' != platform_machine) python-Levenshtein == 0.12.0; '3.0' > python_version python-Levenshtein@https://raw.githubusercontent.com/wiki/SickGear/SickGear/packages/python_Levenshtein-0.12.0-cp27-cp27m-win_amd64.whl ; '2.7' == python_version and 'Windows' == platform_system and ('AMD64' == platform_machine or 'x86_64' == platform_machine) python-Levenshtein@https://raw.githubusercontent.com/wiki/SickGear/SickGear/packages/python_Levenshtein-0.12.0-cp27-cp27m-win32.whl ; '2.7' == python_version and 'Windows' == platform_system and ('AMD64' != platform_machine and 'x86_64' != platform_machine) -regex >= 2020.11.1; '3.7' <= python_version +regex >= 2021.8.28; '3.7' <= python_version regex <= 2020.10.28; '3.0' > python_version -regex@https://raw.githubusercontent.com/wiki/SickGear/SickGear/packages/regex-2021.4.4-cp310-cp310-win_amd64.whl ; '3.10' <= python_version and 'Windows' == platform_system and ('AMD64' == platform_machine or 'x86_64' == platform_machine) -regex@https://raw.githubusercontent.com/wiki/SickGear/SickGear/packages/regex-2021.4.4-cp310-cp310-win32.whl ; '3.10' <= python_version and 'Windows' == platform_system and ('AMD64' != platform_machine and 'x86_64' != platform_machine) +regex@https://raw.githubusercontent.com/wiki/SickGear/SickGear/packages/regex-2021.8.28-cp310-cp310-win_amd64.whl ; '3.10' <= python_version and 'Windows' == platform_system and ('AMD64' == platform_machine or 'x86_64' == platform_machine) +regex@https://raw.githubusercontent.com/wiki/SickGear/SickGear/packages/regex-2021.8.28-cp310-cp310-win32.whl ; '3.10' <= python_version and 'Windows' == platform_system and ('AMD64' != platform_machine and 'x86_64' != platform_machine) scandir >= 1.10.0; '3.0' > python_version -setuptools >= 50.0.0; '3.7' <= python_version +setuptools >= 57.4.0; '3.7' <= python_version setuptools <= 44.1.1; '3.0' > python_version diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index 2a1daf9..6c70c12 100755 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -579,7 +579,7 @@ SG_EXTRA_SCRIPTS = [] GIT_PATH = None IGNORE_WORDS = { - '^(?=.*?\bspanish\b)((?!spanish.?princess).)*$', + r'^(?=.*?\bspanish\b)((?!spanish.?princess).)*$', 'core2hd', 'hevc', 'MrLss', 'reenc', 'x265', 'danish', 'deutsch', 'dutch', 'flemish', 'french', 'german', 'italian', 'nordic', 'norwegian', 'portuguese', 'spanish', 'swedish', 'turkish' } @@ -608,7 +608,7 @@ if TRAKT_STAGING: TRAKT_CLIENT_ID = '2aae3052f90b14235d184cc8f709b12b4fd8ae35f339a060a890c70db92be87a' TRAKT_CLIENT_SECRET = '900e03471220503843d4a856bfbef17080cddb630f2b7df6a825e96e3ff3c39e' TRAKT_PIN_URL = 'https://staging.trakt.tv/pin/638' - TRAKT_BASE_URL = 'http://api.staging.trakt.tv/' + TRAKT_BASE_URL = 'http' + '://api.staging.trakt.tv/' else: # production trakt values: TRAKT_CLIENT_ID = 'f1c453c67d81f1307f9118172c408a883eb186b094d5ea33080d59ddedb7fc7c' @@ -1306,9 +1306,10 @@ def init_stage_1(console_logging): GIT_PATH = check_setting_str(CFG, 'General', 'git_path', '') IGNORE_WORDS, IGNORE_WORDS_REGEX = helpers.split_word_str( - check_setting_str(CFG, 'General', 'ignore_words', IGNORE_WORDS)) + check_setting_str(CFG, 'General', 'ignore_words', helpers.generate_word_str(IGNORE_WORDS, IGNORE_WORDS_REGEX))) REQUIRE_WORDS, REQUIRE_WORDS_REGEX = helpers.split_word_str( - check_setting_str(CFG, 'General', 'require_words', REQUIRE_WORDS)) + check_setting_str(CFG, 'General', 'require_words', + helpers.generate_word_str(REQUIRE_WORDS, REQUIRE_WORDS_REGEX))) CALENDAR_UNPROTECTED = bool(check_setting_int(CFG, 'General', 'calendar_unprotected', 0)) diff --git a/sickbeard/providers/newznab.py b/sickbeard/providers/newznab.py index e7d6cae..2744ee1 100755 --- a/sickbeard/providers/newznab.py +++ b/sickbeard/providers/newznab.py @@ -30,7 +30,7 @@ from . import generic from .. import classes, db, helpers, logger, tvcache from ..classes import SearchResult from ..common import NeededQualities, Quality -from ..helpers import remove_non_release_groups, try_int +from ..helpers import remove_non_release_groups from ..indexers.indexer_config import * from ..network_timezones import SG_TIMEZONE from ..sgdatetime import SGDatetime, timestamp_near @@ -40,7 +40,7 @@ from ..scene_exceptions import has_season_exceptions from ..tv import TVEpisode, TVShow from lib.dateutil import parser -from lib.sg_helpers import md5_for_text +from lib.sg_helpers import md5_for_text, try_int from exceptions_helper import AuthException, ex, MultipleShowObjectsException from lxml_etree import etree @@ -308,7 +308,7 @@ class NewznabProvider(generic.NZBProvider): limit = xml_caps.find('.//limits') if None is not limit: - lim = helpers.try_int(limit.get('max'), 100) + lim = try_int(limit.get('max'), 100) self._limits = (100, lim)[100 <= lim] try: @@ -399,40 +399,38 @@ class NewznabProvider(generic.NZBProvider): return False if 'error' == data.tag: - code = data.get('code', '') - description = data.get('description', '') - - if '100' == code: - raise AuthException('Your API key for %s is incorrect, check your config.' % self.name) - elif '101' == code: - raise AuthException('Your account on %s has been suspended, contact the admin.' % self.name) - elif '102' == code: - try: - retry_time, unit = re.findall(r'Try again in (\d+)\W+([a-z]+)', description, flags=re.I)[0] - except IndexError: - retry_time, unit = None, None - if (description and 'limit' in description.lower()) or (retry_time and unit): - self.tmr_limit_update(retry_time, unit, description) - self.log_failure_url(url) - else: - raise AuthException('Your account isn\'t allowed to use the API on %s, contact the admin.%s' % - (self.name, ('', ' Provider message: %s' % description)[ - description not in ('', None)])) - elif code in ['429', '500']: - try: - retry_time, unit = re.findall(r'Retry in (\d+)\W+([a-z]+)', description, flags=re.I)[0] - except IndexError: - retry_time, unit = None, None - self.tmr_limit_update(retry_time, unit, description) - self.log_failure_url(url) - elif '910' == code: - logger.log( - '%s %s, please check with provider.' % - (self.name, ('currently has their API disabled', description)[description not in (None, '')]), - logger.WARNING) + code = try_int(data.get('code')) + description = data.get('description') or '' + msg = ('', ': %s' % description)[bool(description)] + + if code not in (100, 101, 102, 401, 429, 500, 910): + logger.warning('Unknown error given from %s%s' % (self.name, msg)) else: - logger.log('Unknown error given from %s: %s' % (self.name, data.get('description', '')), - logger.WARNING) + if 100 == code: + raise AuthException('API key for %s is incorrect, check your config' % self.name) + elif 101 == code: + raise AuthException('Account suspended on %s, contact the admin' % self.name) + elif 401 == code: + logger.warning('Error code 401 (Unauthorized) from provider%s' % msg) + raise AuthException('Account disabled on %s (code 401), contact the admin%s' % (self.name, msg)) + elif code in (102, 429, 500): + try: + retry_time, unit = re.findall(r'(?i)(?:Try again|Retry) in (\d+)\W+([a-z]+)', description)[0] + except IndexError: + retry_time, unit = None, None + handle_fail = True + if 102 == code: + handle_fail = ('limit' in description.lower()) or (retry_time and unit) + if not handle_fail: + raise AuthException( + 'Your account isn\'t allowed to use the %s API, contact the admin%s' % + (self.name, ('', '. Provider message: %s' % description)[bool(description)])) + if handle_fail: + self.tmr_limit_update(retry_time, unit, description) + self.log_failure_url(url) + elif 910 == code: + logger.warning('%s %s, please check with provider' % + (self.name, ('currently has their API disabled', description)[bool(description)])) return False self.tmr_limit_count = 0 @@ -469,7 +467,7 @@ class NewznabProvider(generic.NZBProvider): base_params['season'] = '%d' % ep_obj.scene_absolute_number else: base_params['season'] = str((ep_obj.season, ep_obj.scene_season)[bool(ep_obj.show_obj.is_scene)]) - ep_detail = 'S%02d' % helpers.try_int(base_params['season'], 1) + ep_detail = 'S%02d' % try_int(base_params['season'], 1) # id search params = base_params.copy() @@ -521,15 +519,13 @@ class NewznabProvider(generic.NZBProvider): base_params['ep'] = '/'.join(airdate[1:]) ep_detail = '+"%s.%s"' % (base_params['season'], '.'.join(airdate[1:])) elif ep_obj.show_obj.is_anime: - base_params['ep'] = '%i' % (helpers.try_int(ep_obj.scene_absolute_number) or - helpers.try_int(ep_obj.scene_episode)) - ep_detail = '%02d' % helpers.try_int(base_params['ep']) + base_params['ep'] = '%i' % (try_int(ep_obj.scene_absolute_number) or try_int(ep_obj.scene_episode)) + ep_detail = '%02d' % try_int(base_params['ep']) else: base_params['season'], base_params['ep'] = ( (ep_obj.season, ep_obj.episode), (ep_obj.scene_season, ep_obj.scene_episode))[ep_obj.show_obj.is_scene] ep_detail = sickbeard.config.naming_ep_type[2] % { - 'seasonnumber': helpers.try_int(base_params['season'], 1), - 'episodenumber': helpers.try_int(base_params['ep'], 1)} + 'seasonnumber': try_int(base_params['season'], 1), 'episodenumber': try_int(base_params['ep'], 1)} # id search params = base_params.copy() @@ -833,7 +829,7 @@ class NewznabProvider(generic.NZBProvider): if ns and 'newznab' in ns: for attr in item.findall('%sattr' % ns['newznab']): if 'size' == attr.get('name', ''): - parsed_size = helpers.try_int(attr.get('value'), -1) + parsed_size = try_int(attr.get('value'), -1) elif 'guid' == attr.get('name', ''): uid = attr.get('value') except (BaseException, Exception): @@ -1013,12 +1009,11 @@ class NewznabProvider(generic.NZBProvider): # get total and offset attributes try: if 0 == total: - total = (helpers.try_int(parsed_xml.find( + total = (try_int(parsed_xml.find( './/%sresponse' % n_spaces['newznab']).get('total', 0)), 1000)['Cache' == mode] hits = (total // self.limits + int(0 < (total % self.limits))) hits += int(0 == hits) - offset = helpers.try_int(parsed_xml.find('.//%sresponse' - % n_spaces['newznab']).get('offset', 0)) + offset = try_int(parsed_xml.find('.//%sresponse' % n_spaces['newznab']).get('offset', 0)) except (AttributeError, KeyError): if not use_rss: break @@ -1246,7 +1241,7 @@ class NewznabCache(tvcache.TVCache): if 'newznab' in ns: for attr in item.findall('%sattr' % ns['newznab']): if attr.get('name', '') in NewznabConstants.providerToIndexerMapping: - v = helpers.try_int(attr.get('value')) + v = try_int(attr.get('value')) if 0 < v: ids[NewznabConstants.providerToIndexerMapping[attr.get('name')]] = v return ids