From 6ec3938e9a00bcde77384852c1f868a766fd7360 Mon Sep 17 00:00:00 2001 From: JackDandy Date: Thu, 10 Sep 2020 13:30:54 +0100 Subject: [PATCH] Fix thesubdb under py3. Change autoProcessTV.py to remove bytestring identifiers that are printed under py3. The actual media process has no issue, however, the aesthetic output caused confusion. Fix saving nzb data to blackhole under py3. Fix deprecated use of elementtree obj without len or explicit None test. Change init provider options _after_ loading settings not before. Change handle search task attributes that do not exist. --- CHANGES.md | 9 ++++- autoProcessTV/autoProcessTV.py | 61 +++++++++++++--------------------- lib/subliminal/services/addic7ed.py | 10 +++--- lib/subliminal/services/thesubdb.py | 23 +++++++------ lib/subliminal/services/tvsubtitles.py | 6 ++-- sickbeard/__init__.py | 20 +++++++++-- sickbeard/nzbget.py | 1 - sickbeard/providers/__init__.py | 11 ++---- sickbeard/providers/newznab.py | 12 ++++--- sickbeard/providers/omgwtfnzbs.py | 39 ++++++++++++++++++---- sickbeard/search.py | 15 ++++----- sickbeard/search_backlog.py | 10 +++--- sickbeard/tv.py | 9 ++--- sickbeard/webserve.py | 9 ++--- 14 files changed, 134 insertions(+), 101 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 7ba2b58..3771a34 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,4 +1,11 @@ -### 0.21.43 (2020-09-09 19:20:00 UTC) +### 0.21.44 (2020-09-11 10:10:00 UTC) + +* Fix thesubdb subtitle service under py3 +* Change autoProcessTV.py to remove bytestring identifiers that are printed under py3 +* Fix saving nzb data to blackhole under py3 + + +### 0.21.43 (2020-09-09 19:20:00 UTC) * Add missing parameter 'failed' to sg.postprocess * Fix legacy command help for episode.search diff --git a/autoProcessTV/autoProcessTV.py b/autoProcessTV/autoProcessTV.py index 066a4d0..8e2ede1 100755 --- a/autoProcessTV/autoProcessTV.py +++ b/autoProcessTV/autoProcessTV.py @@ -35,7 +35,7 @@ warnings.filterwarnings('ignore', module=r'.*ssl_.*', message='.*SSLContext obje try: import requests except ImportError: - print ('You need to install python requests library') + print('You need to install python requests library') sys.exit(1) try: # Try importing Python 3 modules @@ -44,10 +44,12 @@ try: # Try importing Python 3 modules import urllib.request as urllib2 # noinspection PyUnresolvedReferences,PyCompatibility from urllib.parse import urlencode -except ImportError: # On error import Python 2 modules using new names - # noinspection PyPep8Naming +except ImportError: # On error, import Python 2 modules + # noinspection PyPep8Naming,PyUnresolvedReferences import ConfigParser as configparser + # noinspection PyUnresolvedReferences import urllib2 + # noinspection PyUnresolvedReferences from urllib import urlencode @@ -56,32 +58,25 @@ def process_files(dir_to_process, org_nzb_name=None, status=None): # Default values host = 'localhost' port = '8081' - username = '' - password = '' - ssl = 0 + default_url = 'http://%s:%s/' % (host, port) + ssl = username = password = '' web_root = '/' - default_url = host + ':' + port + web_root - if ssl: - default_url = 'https://' + default_url - else: - default_url = 'http://' + default_url - # Get values from config_file config = configparser.RawConfigParser() config_filename = os.path.join(os.path.dirname(sys.argv[0]), 'autoProcessTV.cfg') if not os.path.isfile(config_filename): - print ('ERROR: ' + config_filename + " doesn't exist") - print ('copy /rename ' + config_filename + '.sample and edit\n') - print ('Trying default url: ' + default_url + '\n') + print('ERROR: %s doesn\'t exist' % config_filename) + print('copy /rename %s.sample and edit\n' % config_filename) + print('Trying default url: %s\n' % default_url) else: try: - print ('Loading config from ' + config_filename + '\n') + print('Loading config from %s\n' % config_filename) with open(config_filename, 'r') as fp: - config.readfp(fp) + config.read_file(fp) # Replace default values with config_file values host = config.get('SickBeard', 'host') @@ -90,25 +85,21 @@ def process_files(dir_to_process, org_nzb_name=None, status=None): password = config.get('SickBeard', 'password') try: - ssl = int(config.get('SickBeard', 'ssl')) + ssl = int(config.get('SickBeard', 'ssl')) and 's' or '' except (configparser.NoOptionError, ValueError): pass try: web_root = config.get('SickBeard', 'web_root') - if not web_root.startswith('/'): - web_root = '/' + web_root - - if not web_root.endswith('/'): - web_root = web_root + '/' + web_root = ('/%s/' % web_root.strip('/')).replace('//', '/') except configparser.NoOptionError: pass except EnvironmentError: e = sys.exc_info()[1] - print ('Could not read configuration file: ' + str(e)) + print('Could not read configuration file: ' + str(e)) # There was a config_file, don't use default values but exit sys.exit(1) @@ -120,15 +111,11 @@ def process_files(dir_to_process, org_nzb_name=None, status=None): if None is not status: params['failed'] = status - if ssl: - protocol = 'https://' - else: - protocol = 'http://' - - url = protocol + host + ':' + port + web_root + 'home/process-media/files' - login_url = protocol + host + ':' + port + web_root + 'login' + url = 'http%s://%s:%s%s' % (ssl, host, port, web_root) + login_url = url + 'login' + url = url + 'home/process-media/files' - print ('Opening URL: ' + url) + print('Opening URL: ' + url) try: sess = requests.Session() @@ -142,17 +129,17 @@ def process_files(dir_to_process, org_nzb_name=None, status=None): if 401 == result.status_code: print('Verify and use correct username and password in autoProcessTV.cfg') else: - for line in result.iter_lines(): + for line in result.iter_lines(decode_unicode=True): if line: - print (line.strip()) + print(line.strip()) except IOError: e = sys.exc_info()[1] - print ('Unable to open URL: ' + str(e)) + print('Unable to open URL: ' + str(e)) sys.exit(1) if '__main__' == __name__: - print ('This module is supposed to be used as import in other scripts and not run standalone.') - print ('Use sabToSickBeard instead.') + print('This module is supposed to be used as import in other scripts and not run standalone.') + print('Use sabToSickBeard instead.') sys.exit(1) diff --git a/lib/subliminal/services/addic7ed.py b/lib/subliminal/services/addic7ed.py index b91aacf..54b09b9 100644 --- a/lib/subliminal/services/addic7ed.py +++ b/lib/subliminal/services/addic7ed.py @@ -36,7 +36,7 @@ class Addic7ed(ServiceBase): server_url = 'http://www.addic7ed.com' site_url = 'http://www.addic7ed.com' api_based = False - #TODO: Complete this + # TODO: Complete this languages = language_set(['ar', 'ca', 'de', 'el', 'en', 'es', 'eu', 'fr', 'ga', 'gl', 'he', 'hr', 'hu', 'it', 'pl', 'pt', 'ro', 'ru', 'se', 'pb']) language_map = {'Portuguese (Brazilian)': Language('pob'), 'Greek': Language('gre'), @@ -50,7 +50,7 @@ class Addic7ed(ServiceBase): def get_series_id(self, name): """Get the show page and cache every show found in it""" r = self.session.get('%s/shows.php' % self.server_url) - soup = BeautifulSoup(r.content, self.required_features[0]) + soup = BeautifulSoup(r.text, self.required_features[0]) for html_series in soup.select('h3 > a'): series_name = html_series.text.lower() match = re.search('show/([0-9]+)', html_series['href']) @@ -73,7 +73,7 @@ class Addic7ed(ServiceBase): logger.debug(u'Could not find series id for %s' % series) return [] r = self.session.get('%s/show/%d&season=%d' % (self.server_url, series_id, season)) - soup = BeautifulSoup(r.content, self.required_features[0]) + soup = BeautifulSoup(r.text, self.required_features[0]) subtitles = [] for row in soup('tr', {'class': 'epeven completed'}): cells = row('td') @@ -91,7 +91,7 @@ class Addic7ed(ServiceBase): logger.debug(u'Language %r not in wanted languages %r' % (sub_language, languages)) continue sub_keywords = split_keyword(cells[4].text.strip().lower()) - #TODO: Maybe allow empty keywords here? (same in Subtitulos) + # TODO: Maybe allow empty keywords here? (same in Subtitulos) if keywords and not keywords & sub_keywords: logger.debug(u'None of subtitle keywords %r in %r' % (sub_keywords, keywords)) continue @@ -105,7 +105,7 @@ class Addic7ed(ServiceBase): logger.info(u'Downloading %s in %s' % (subtitle.link, subtitle.path)) try: r = self.session.get(subtitle.link, headers={'Referer': subtitle.link, 'User-Agent': self.user_agent}) - soup = BeautifulSoup(r.content, self.required_features[0]) + soup = BeautifulSoup(r.text, self.required_features[0]) if soup.title is not None and u'Addic7ed.com' in soup.title.text.strip(): raise DownloadFailedError('Download limit exceeded') with open(subtitle.path, 'wb') as f: diff --git a/lib/subliminal/services/thesubdb.py b/lib/subliminal/services/thesubdb.py index 93787ad..7f8e13c 100644 --- a/lib/subliminal/services/thesubdb.py +++ b/lib/subliminal/services/thesubdb.py @@ -40,27 +40,30 @@ class TheSubDB(ServiceBase): def list_checked(self, video, languages): return self.query(video.path, video.hashes['TheSubDB'], languages) - def query(self, filepath, moviehash, languages): - r = self.session.get(self.server_url, params={'action': 'search', 'hash': moviehash}) - if r.status_code == 404: - logger.debug(u'Could not find subtitles for hash %s' % moviehash) + def query(self, filepath, filehash, languages): + r = self.session.get(self.server_url, params={'action': 'search', 'hash': filehash}) + if 404 == r.status_code or (200 == r.status_code and not r.text): + logger.debug(u'Could not find subtitles for hash %s' % filehash) return [] - if r.status_code != 200: + if 200 != r.status_code: logger.error(u'Request %s returned status code %d' % (r.url, r.status_code)) return [] - available_languages = language_set(r.content.split(',')) - #this is needed becase for theSubDB pt languages is Portoguese Brazil and not Portoguese# - #So we are deleting pt language and adding pb language + available_languages = language_set(r.text.split(',')) + # this is needed because for theSubDB pt languages is Portuguese Brazil and not Portuguese # + # So we are deleting pt language and adding pb language if Language('pt') in available_languages: available_languages = available_languages - language_set(['pt']) | language_set(['pb']) languages &= available_languages if not languages: - logger.debug(u'Could not find subtitles for hash %s with languages %r (only %r available)' % (moviehash, languages, available_languages)) + logger.debug(u'Could not find subtitles for hash %s with languages %r (only %r available)' % ( + filehash, languages, available_languages)) return [] subtitles = [] for language in languages: path = get_subtitle_path(filepath, language, self.config.multi) - subtitle = ResultSubtitle(path, language, self.__class__.__name__.lower(), '%s?action=download&hash=%s&language=%s' % (self.server_url, moviehash, language.alpha2)) + subtitle = ResultSubtitle( + path, language, self.__class__.__name__.lower(), + '%s?action=download&hash=%s&language=%s' % (self.server_url, filehash, language.alpha2)) subtitles.append(subtitle) return subtitles diff --git a/lib/subliminal/services/tvsubtitles.py b/lib/subliminal/services/tvsubtitles.py index ce97452..5efccc3 100644 --- a/lib/subliminal/services/tvsubtitles.py +++ b/lib/subliminal/services/tvsubtitles.py @@ -54,7 +54,7 @@ class TvSubtitles(ServiceBase): @cachedmethod def get_likely_series_id(self, name): r = self.session.post('%s/search.php' % self.server_url, data={'q': name}) - soup = BeautifulSoup(r.content, self.required_features[0]) + soup = BeautifulSoup(r.text, self.required_features[0]) maindiv = soup.find('div', 'left') results = [] for elem in maindiv.find_all('li'): @@ -74,7 +74,7 @@ class TvSubtitles(ServiceBase): # download the page of the season, contains ids for all episodes episode_id = None r = self.session.get('%s/tvshow-%d-%d.html' % (self.server_url, series_id, season)) - soup = BeautifulSoup(r.content, self.required_features[0]) + soup = BeautifulSoup(r.text, self.required_features[0]) table = soup.find('table', id='table5') for row in table.find_all('tr'): cells = row.find_all('td') @@ -97,7 +97,7 @@ class TvSubtitles(ServiceBase): def get_sub_ids(self, episode_id): subids = [] r = self.session.get('%s/episode-%d.html' % (self.server_url, episode_id)) - epsoup = BeautifulSoup(r.content, self.required_features[0]) + epsoup = BeautifulSoup(r.text, self.required_features[0]) for subdiv in epsoup.find_all('a'): if 'href' not in subdiv.attrs or not subdiv['href'].startswith('/subtitle'): continue diff --git a/sickbeard/__init__.py b/sickbeard/__init__.py index 52da0c8..53e373a 100755 --- a/sickbeard/__init__.py +++ b/sickbeard/__init__.py @@ -35,6 +35,7 @@ import os.path import sys import threading import uuid +import zlib # noinspection PyPep8Naming import encodingKludge as ek @@ -54,10 +55,11 @@ from .tv import TVidProdid from .watchedstate import EmbyWatchedStateUpdater, PlexWatchedStateUpdater from adba.aniDBerrors import AniDBError +from browser_ua import get_ua from configobj import ConfigObj from libtrakt import TraktAPI -from _23 import b64encodestring, filter_iter, list_items, map_list +from _23 import b64encodestring, decode_bytes, filter_iter, list_items, map_list from six import iteritems, PY2, string_types import sg_helpers @@ -1326,6 +1328,18 @@ def init_stage_1(console_logging): setattr(nzb_prov, attr, check_setting_str(CFG, prov_id_uc, attr_check, default)) elif isinstance(default, int): setattr(nzb_prov, attr, check_setting_int(CFG, prov_id_uc, attr_check, default)) + for cur_provider in filter_iter(lambda p: abs(zlib.crc32(decode_bytes(p.name))) + 40000400 in ( + 1449593765, 1597250020, 1524942228, 160758496 + ) or (p.url and abs(zlib.crc32(decode_bytes(re.sub(r'[./]', '', p.url[-10:])))) + 40000400 in ( + 2417143804,)), providers.sortedProviderList()): + header = {'User-Agent': get_ua()} + if hasattr(cur_provider, 'nn'): + cur_provider.nn = False + cur_provider.ui_string() + # noinspection PyProtectedMember + header = callable(getattr(cur_provider, '_init_api', False)) and False is cur_provider._init_api() \ + and header or {} + cur_provider.headers.update(header) if not os.path.isfile(CONFIG_FILE): logger.log(u'Unable to find \'%s\', all settings will be default!' % CONFIG_FILE, logger.DEBUG) @@ -1452,7 +1466,7 @@ def init_stage_2(): init_search_delay = int(os.environ.get('INIT_SEARCH_DELAY', 0)) - # enter 4490 (was 4489) for experimental internal provider frequencies + # enter 4499 (was 4489) for experimental internal provider frequencies update_interval = datetime.timedelta(minutes=(RECENTSEARCH_FREQUENCY, 1)[4499 == RECENTSEARCH_FREQUENCY]) recentSearchScheduler = scheduler.Scheduler( search_recent.RecentSearcher(), @@ -1462,7 +1476,7 @@ def init_stage_2(): prevent_cycle_run=searchQueueScheduler.action.is_recentsearch_in_progress) if [x for x in providers.sortedProviderList() if x.is_active() and - x.enable_backlog and x.providerType == GenericProvider.NZB]: + getattr(x, 'enable_backlog', None) and GenericProvider.NZB == x.providerType]: nextbacklogpossible = datetime.datetime.fromtimestamp( search_backlog.BacklogSearcher().last_runtime) + datetime.timedelta(hours=23) now = datetime.datetime.now() diff --git a/sickbeard/nzbget.py b/sickbeard/nzbget.py index bc3a741..d203e17 100644 --- a/sickbeard/nzbget.py +++ b/sickbeard/nzbget.py @@ -14,7 +14,6 @@ # You should have received a copy of the GNU General Public License # along with SickGear. If not, see . -import datetime import re import sickbeard diff --git a/sickbeard/providers/__init__.py b/sickbeard/providers/__init__.py index 4fbbb10..fa049fc 100755 --- a/sickbeard/providers/__init__.py +++ b/sickbeard/providers/__init__.py @@ -24,7 +24,7 @@ from .newznab import NewznabConstants from .. import logger import sickbeard -from _23 import decode_bytes, filter_list, filter_iter +from _23 import filter_list, filter_iter from six import iteritems, itervalues __all__ = [ @@ -80,14 +80,7 @@ def sortedProviderList(): def makeProviderList(): - providers = [x.provider for x in [getProviderModule(y) for y in __all__] if x] - import browser_ua - import zlib - headers = [1449593765, 1597250020, 1524942228] - for p in providers: - if abs(zlib.crc32(decode_bytes(p.name))) + 40000400 in headers: - p.headers.update({'User-Agent': browser_ua.get_ua()}) - return providers + return [x.provider for x in [getProviderModule(y) for y in __all__] if x] def getNewznabProviderList(data): diff --git a/sickbeard/providers/newznab.py b/sickbeard/providers/newznab.py index 91fc52e..604b9fc 100755 --- a/sickbeard/providers/newznab.py +++ b/sickbeard/providers/newznab.py @@ -248,7 +248,7 @@ class NewznabProvider(generic.NZBProvider): data = self.get_url('%s/api?t=caps&apikey=%s' % (self.url, api_key)) if data: xml_caps = helpers.parse_xml(data) - if xml_caps and hasattr(xml_caps, 'tag') and 'caps' == xml_caps.tag: + if None is not xml_caps and 'caps' == getattr(xml_caps, 'tag', ''): self._caps_need_apikey = {'need': True, 'date': datetime.date.today()} return xml_caps @@ -421,8 +421,9 @@ class NewznabProvider(generic.NZBProvider): # type: (...) -> AnyStr return '%s|%s|%s|%s|%i|%s|%i|%i|%i|%i|%i' \ % (self.name or '', self.url or '', self.maybe_apikey() or '', self.cat_ids or '', self.enabled, - self.search_mode or '', self.search_fallback, self.enable_recentsearch, self.enable_backlog, - self.enable_scheduled_backlog, self.server_type) + self.search_mode or '', self.search_fallback, getattr(self, 'enable_recentsearch', False), + getattr(self, 'enable_backlog', False), getattr(self, 'enable_scheduled_backlog', False), + self.server_type) def _season_strings(self, ep_obj # type: TVEpisode @@ -1116,8 +1117,9 @@ class NewznabProvider(generic.NZBProvider): (self.name, ('disabled', 'enabled')[self.enabled in (True, 1)], NewznabConstants.server_types.get(self.server_type, 'unknown'), ','.join(en[1] for en in - ((self.enable_recentsearch, 'recent'), (self.enable_scheduled_backlog, 'backlog'), - (self.enable_scheduled_backlog, 'scheduled')) if en[0]) or 'None') + ((getattr(self, 'enable_recentsearch', False), 'recent'), + (getattr(self, 'enable_backlog', False), 'backlog'), + (getattr(self, 'enable_scheduled_backlog', False), 'scheduled')) if en[0]) or 'None') def __repr__(self): return self.__str__() diff --git a/sickbeard/providers/omgwtfnzbs.py b/sickbeard/providers/omgwtfnzbs.py index 40198c8..69285e7 100644 --- a/sickbeard/providers/omgwtfnzbs.py +++ b/sickbeard/providers/omgwtfnzbs.py @@ -20,6 +20,7 @@ from datetime import datetime import re import time import traceback +from random import randint import sickbeard from . import generic @@ -253,7 +254,7 @@ class OmgwtfnzbsProvider(generic.NZBProvider): :return: :rtype: List """ - api_key = self._init_api() + api_key = self._init_api() or search_mode in ['Propers'] and None if False is api_key: return self.search_html(search, search_mode, needed=needed, **kwargs) results = [] @@ -388,13 +389,14 @@ class OmgwtfnzbsProvider(generic.NZBProvider): return None try: + s = re.compile(r'(?i)([\s\']+|cookee\s*:)') api_key = self._check_auth() - if not api_key.startswith('cookie:'): + if not s.match(api_key): return api_key except (BaseException, Exception): return None - self.cookies = re.sub(r'(?i)([\s\']+|cookie\s*:)', '', api_key) + self.cookies = s.sub('', api_key) success, msg = self._check_cookie() if success and self.nn: success, msg = None, 'pm dev in irc about this feature' @@ -404,8 +406,7 @@ class OmgwtfnzbsProvider(generic.NZBProvider): return None return False - @staticmethod - def ui_string(key): + def ui_string(self, key=None): """ :param key: @@ -413,7 +414,18 @@ class OmgwtfnzbsProvider(generic.NZBProvider): :return: :rtype: AnyStr """ - return 'omgwtfnzbs_api_key' == key and 'Or use... \'cookie: cookname=xx; cookpass=yy\'' or '' + try: + ca = ':' == self._check_auth()[6] + except (BaseException, Exception): + ca = False + if not ca: + if not hasattr(self, 'enable_backlog'): + for cur_attr in ('enable_backlog', 'enable_scheduled_backlog'): + setattr(self, cur_attr, None) + elif hasattr(self, 'enable_backlog'): + for cur_attr in ('enable_backlog', 'enable_scheduled_backlog'): + delattr(self, cur_attr) + return 'omgwtfnzbs_api_key' == key and '' or '' class OmgwtfnzbsCache(tvcache.TVCache): @@ -421,7 +433,20 @@ class OmgwtfnzbsCache(tvcache.TVCache): def __init__(self, this_provider): tvcache.TVCache.__init__(self, this_provider) - self.update_freq = 20 # type: int + @property + def update_freq(self): + try: + ca = ':' == self.provider._check_auth()[6] + except (BaseException, Exception): + ca = False + try: + return (10, 20 + randint(0, min(40, sickbeard.RECENTSEARCH_FREQUENCY * 3)))[ca] + except (BaseException, Exception): + return 20 + + @update_freq.setter + def update_freq(self, v): + return def _cache_data(self, **kwargs): diff --git a/sickbeard/search.py b/sickbeard/search.py index 35a5b9f..8f02f72 100644 --- a/sickbeard/search.py +++ b/sickbeard/search.py @@ -28,6 +28,7 @@ import traceback import encodingKludge as ek import exceptions_helper from exceptions_helper import ex +from sg_helpers import write_file import sickbeard from . import clients, common, db, failed_history, helpers, history, logger, \ @@ -78,12 +79,9 @@ def _download_result(result): if not data: new_result = False else: - with ek.ek(open, file_name, 'wb') as file_out: - file_out.write(data) + write_file(file_name, data, raise_exceptions=True) - helpers.chmod_as_parent(file_name) - - except EnvironmentError as e: + except (EnvironmentError, IOError) as e: logger.log(u'Error trying to save NZB to black hole: %s' % ex(e), logger.ERROR) new_result = False elif 'torrent' == res_provider.providerType: @@ -747,9 +745,10 @@ def search_providers( use_quality_list = (status not in ( common.WANTED, common.FAILED, common.UNAIRED, common.SKIPPED, common.IGNORED, common.UNKNOWN)) - provider_list = [x for x in sickbeard.providers.sortedProviderList() if x.is_active() and x.enable_backlog and - (not torrent_only or x.providerType == GenericProvider.TORRENT) and - (not scheduled or x.enable_scheduled_backlog)] + provider_list = [x for x in sickbeard.providers.sortedProviderList() if x.is_active() and + getattr(x, 'enable_backlog', None) and + (not torrent_only or GenericProvider.TORRENT == x.providerType) and + (not scheduled or getattr(x, 'enable_scheduled_backlog', None))] for cur_provider in provider_list: if cur_provider.anime_only and not show_obj.is_anime: logger.log(u'%s is not an anime, skipping' % show_obj.name, logger.DEBUG) diff --git a/sickbeard/search_backlog.py b/sickbeard/search_backlog.py index d1852a1..87165b3 100644 --- a/sickbeard/search_backlog.py +++ b/sickbeard/search_backlog.py @@ -59,7 +59,7 @@ class BacklogSearchScheduler(scheduler.Scheduler): def next_backlog_timeleft(self): now = datetime.datetime.now() torrent_enabled = 0 < len([x for x in sickbeard.providers.sortedProviderList() if x.is_active() and - x.enable_backlog and x.providerType == GenericProvider.TORRENT]) + getattr(x, 'enable_backlog', None) and GenericProvider.TORRENT == x.providerType]) if now > self.action.nextBacklog or self.action.nextCyleTime != self.cycleTime: nextruntime = now + self.timeLeft() if not torrent_enabled: @@ -172,9 +172,10 @@ class BacklogSearcher(object): :param scheduled: scheduled backlog search (can be from webif or scheduler) :return: any provider is active for given backlog """ - return 0 < len([x for x in sickbeard.providers.sortedProviderList() if x.is_active() and x.enable_backlog and + return 0 < len([x for x in sickbeard.providers.sortedProviderList() if x.is_active() and + getattr(x, 'enable_backlog', None) and (not torrent_only or GenericProvider.TORRENT == x.providerType) and - (not scheduled or x.enable_scheduled_backlog)]) + (not scheduled or getattr(x, 'enable_scheduled_backlog', None))]) def search_backlog(self, which_shows=None, # type: Optional[List[TVShow]] @@ -206,7 +207,8 @@ class BacklogSearcher(object): if not force and standard_backlog and (datetime.datetime.now() - datetime.datetime.fromtimestamp( self._get_last_runtime())) < datetime.timedelta(hours=23): any_torrent_enabled = any(map_iter( - lambda x: x.is_active() and x.enable_backlog and x.providerType == GenericProvider.TORRENT, + lambda x: x.is_active() and getattr(x, 'enable_backlog', None) + and GenericProvider.TORRENT == x.providerType, sickbeard.providers.sortedProviderList())) if not any_torrent_enabled: logger.log('Last scheduled backlog run was within the last day, skipping this run.', logger.DEBUG) diff --git a/sickbeard/tv.py b/sickbeard/tv.py index 5817885..248d333 100644 --- a/sickbeard/tv.py +++ b/sickbeard/tv.py @@ -1987,7 +1987,7 @@ class TVEpisode(TVEpisodeBase): def __init__(self, show_obj, season, episode, path='', show_sql=None): super(TVEpisode, self).__init__(season, episode, int(show_obj.tvid)) - + self._show_obj = show_obj # type: TVShow self.scene_season = 0 # type: int @@ -2280,7 +2280,7 @@ class TVEpisode(TVEpisodeBase): else: self._file_size = 0 - # todo: change to _tvid , _epid after removing indexer, indexerid + # todo: change to _tvid , _epid after removing indexer, indexerid self.tvid = int(sql_result[0]['indexer']) self.epid = int(sql_result[0]['indexerid']) @@ -2304,7 +2304,7 @@ class TVEpisode(TVEpisodeBase): if 0 == self.scene_absolute_number: self.scene_absolute_number = sickbeard.scene_numbering.get_scene_absolute_numbering( self.show_obj.tvid, self.show_obj.prodid, - absolute_number=self.absolute_number, + absolute_number=self.absolute_number, season=self.season, episode=episode) if 0 == self.scene_season or 0 == self.scene_episode: @@ -2767,7 +2767,8 @@ class TVEpisode(TVEpisodeBase): self.season, self.episode, self.epid, self.tvid, self.name, self.description, - ','.join([sub for sub in self.subtitles]), self.subtitles_searchcount, self.subtitles_lastsearch, + ','.join([isinstance(sub, string_types) and sub or sub.alpha2 for sub in self.subtitles]), + self.subtitles_searchcount, self.subtitles_lastsearch, self.airdate.toordinal(), self.hasnfo, self.hastbn, self.status, self.location, self.file_size, self.release_name, self.is_proper, self.show_obj.prodid, self.season, self.episode, self.absolute_number, diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index 642eb9d..775902a 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -7013,9 +7013,10 @@ class ConfigProviders(Config): [k for k in nzb_src.may_filter if config.checkbox_to_value(kwargs.get('%s_filter_%s' % (cur_id, k)))]) - for attr in ['search_fallback', 'enable_recentsearch', 'enable_backlog', 'enable_scheduled_backlog', - 'scene_only', 'scene_loose', 'scene_loose_active', - 'scene_rej_nuked', 'scene_nuked_active']: + for attr in filter_iter(lambda a: hasattr(nzb_src, a), [ + 'search_fallback', 'enable_recentsearch', 'enable_backlog', 'enable_scheduled_backlog', + 'scene_only', 'scene_loose', 'scene_loose_active', 'scene_rej_nuked', 'scene_nuked_active' + ]): setattr(nzb_src, attr, config.checkbox_to_value(kwargs.get(cur_id + '_' + attr))) for attr in ['scene_or_contain', 'search_mode']: @@ -7175,7 +7176,7 @@ class ConfigProviders(Config): setattr(nzb_src, attr, config.checkbox_to_value(kwargs.get(src_id_prefix + attr)) or not getattr(nzb_src, 'supports_backlog', True)) - for attr in filter_iter(lambda _x: hasattr(nzb_src, _x), + for attr in filter_iter(lambda a: hasattr(nzb_src, a), ['search_fallback', 'enable_backlog', 'enable_scheduled_backlog', 'scene_only', 'scene_loose', 'scene_loose_active', 'scene_rej_nuked', 'scene_nuked_active']):