diff --git a/CHANGES.md b/CHANGES.md index dd7629f..3fbd091 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -51,6 +51,16 @@ * Update urllib3 release 1.25.6 (4a6c288) to 1.25.7 (37ba61a) +### 0.21.25 (2020-04-10 01:50:00 UTC) + +* Fix Kodi uniqueid tag not validated during import +* Change slightly improve performance iterating metadata providers +* Fix AttributeError in anime manager while editing show +* Remove DigitalHive torrent provider +* Fix failure time reset of service URLs +* Change improve clarity of show update/refresh API failure message + + ### 0.21.24 (2020-04-04 00:30:00 UTC) * Fix use release group for Propers check from history if status is snatched diff --git a/gui/slick/images/providers/digitalhive.png b/gui/slick/images/providers/digitalhive.png deleted file mode 100644 index 3a87398..0000000 Binary files a/gui/slick/images/providers/digitalhive.png and /dev/null differ diff --git a/sickbeard/anime.py b/sickbeard/anime.py index 99bd856..59b057f 100644 --- a/sickbeard/anime.py +++ b/sickbeard/anime.py @@ -174,7 +174,7 @@ def short_group_names(groups): pass if isinstance(adba_result, LoginFirstResponse): break - if None is adba_result or not adba_result.hasattr('datalines'): + if None is adba_result or not adba_result.hasattr('datalines', None): continue for line in adba_result.datalines: if line['shortname']: diff --git a/sickbeard/metadata/generic.py b/sickbeard/metadata/generic.py index 7684d42..19206af 100644 --- a/sickbeard/metadata/generic.py +++ b/sickbeard/metadata/generic.py @@ -1027,9 +1027,10 @@ class GenericMetadata(object): showXML = etree.ElementTree(file=xmlFileObj) if None is showXML.findtext('title') \ - or (None is showXML.findtext('tvdbid') - and None is showXML.findtext('id')) \ - and None is showXML.findtext('indexer'): + or (None is showXML.find('//uniqueid[@type="tvdb"]') + and (None is showXML.findtext('tvdbid') + and None is showXML.findtext('id')) + and None is showXML.findtext('indexer')): logger.log(u"Invalid info in tvshow.nfo (missing name or id):" + str(showXML.findtext('title')) + ' ' + str(showXML.findtext('indexer')) + ' ' @@ -1044,7 +1045,11 @@ class GenericMetadata(object): except (BaseException, Exception): tvid = None - if None is not showXML.findtext('tvdbid'): + prodid = showXML.find('//uniqueid[@type="tvdb"]') + if None is not prodid: + prodid = int(prodid.text) + tvid = TVINFO_TVDB + elif None is not showXML.findtext('tvdbid'): prodid = int(showXML.findtext('tvdbid')) tvid = TVINFO_TVDB elif None is not showXML.findtext('id'): diff --git a/sickbeard/providers/__init__.py b/sickbeard/providers/__init__.py index bd65025..0731763 100755 --- a/sickbeard/providers/__init__.py +++ b/sickbeard/providers/__init__.py @@ -32,7 +32,7 @@ __all__ = [ 'omgwtfnzbs', # torrent 'alpharatio', 'bb', 'bithdtv', 'blutopia', 'btn', - 'custom01', 'custom11', 'dh', 'ettv', 'eztv', 'fano', 'filelist', 'funfile', 'grabtheinfo', + 'custom01', 'custom11', 'ettv', 'eztv', 'fano', 'filelist', 'funfile', 'grabtheinfo', 'hdbits', 'hdme', 'hdspace', 'hdtorrents', 'horriblesubs', 'immortalseed', 'iptorrents', 'limetorrents', 'magnetdl', 'milkie', 'morethan', 'nebulance', 'ncore', 'nyaa', 'pisexy', 'pretome', 'privatehd', 'ptf', diff --git a/sickbeard/providers/dh.py b/sickbeard/providers/dh.py deleted file mode 100644 index f07b4ac..0000000 --- a/sickbeard/providers/dh.py +++ /dev/null @@ -1,119 +0,0 @@ -# coding=utf-8 -# -# This file is part of SickGear. -# -# SickGear is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# SickGear is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with SickGear. If not, see . - -import re -import traceback - -from . import generic -from .. import logger -from ..helpers import try_int -from bs4_parser import BS4Parser - -from _23 import unidecode -from six import iteritems - - -class DHProvider(generic.TorrentProvider): - - def __init__(self): - generic.TorrentProvider.__init__(self, 'DigitalHive') - - self.url_base = 'https://www.digitalhive.org/' - self.urls = {'config_provider_home_uri': self.url_base, - 'login': self.url_base + 'getrss.php', - 'search': self.url_base + 'browse.php?search=%s&%s&titleonly=1&incldead=%s'} - - self.categories = {'Season': [34], 'Episode': [7, 32, 55, 57], 'anime': [2]} - self.categories['Cache'] = self.categories['Season'] + self.categories['Episode'] - - self.url = self.urls['config_provider_home_uri'] - - self.digest, self.freeleech, self.minseed, self.minleech = 4 * [None] - - def _authorised(self, **kwargs): - - return super(DHProvider, self)._authorised( - logged_in=(lambda y=None: (None is y or re.search(r'(?i)rss\slink', y)) and self.has_all_cookies() and - self.session.cookies['uid'] in self.digest and self.session.cookies['pass'] in self.digest), - failed_msg=(lambda y=None: u'Invalid cookie details for %s. Check settings')) - - def _search_provider(self, search_params, **kwargs): - - results = [] - if not self._authorised(): - return results - - items = {'Cache': [], 'Season': [], 'Episode': [], 'Propers': []} - - rc = dict([(k, re.compile('(?i)' + v)) for (k, v) in iteritems({'info': 'details', 'get': 'download'})]) - for mode in search_params: - rc['cats'] = re.compile('(?i)cat=(?:%s)' % self._categories_string(mode, template='', delimiter='|')) - for search_string in search_params[mode]: - search_string = unidecode(search_string) - - html = self.get_url(self.urls['search'] % ( - '+'.join(search_string.split()), self._categories_string(mode), ('3', '0')[not self.freeleech])) - if self.should_skip(): - return results - - cnt = len(items[mode]) - try: - if not html or self._has_no_results(html): - raise generic.HaltParseException - - with BS4Parser(html, parse_only=dict(table={'cellpadding': 0})) as tbl: - tbl_rows = [] if not tbl else tbl.find_all('tr') - - if 2 > len(tbl_rows): - raise generic.HaltParseException - - head = None - for tr in tbl_rows[1:]: - cells = tr.find_all('td') - if 6 > len(cells): - continue - try: - head = head if None is not head else self._header_row(tr) - seeders, leechers, size = [try_int(n, n) for n in [ - cells[head[x]].get_text().strip() for x in ('seed', 'leech', 'size')]] - if not tr.find('a', href=rc['cats']) or self._reject_item(seeders, leechers): - continue - - title = tr.find('a', href=rc['info']).get_text().strip() - download_url = self._link(tr.find('a', href=rc['get'])['href']) - except (AttributeError, TypeError, ValueError, IndexError): - continue - - if title and download_url: - items[mode].append((title, download_url, seeders, self._bytesizer(size))) - - except generic.HaltParseException: - pass - except (BaseException, Exception): - logger.log(u'Failed to parse. Traceback: %s' % traceback.format_exc(), logger.ERROR) - - self._log_search(mode, len(items[mode]) - cnt, self.session.response.get('url')) - - results = self._sort_seeding(mode, results + items[mode]) - - return results - - def ui_string(self, key): - return ('%s_digest' % self.get_id()) == key and 'use... \'uid=xx; pass=yy\'' or '' - - -provider = DHProvider() diff --git a/sickbeard/providers/generic.py b/sickbeard/providers/generic.py index 4921d3f..eecbe6e 100644 --- a/sickbeard/providers/generic.py +++ b/sickbeard/providers/generic.py @@ -335,8 +335,12 @@ class GenericProvider(object): changed_val = self._failure_time != value self._failure_time = value if changed_val: - # noinspection PyCallByClass,PyTypeChecker - self._save_fail_value('failure_time', (SGDatetime.totimestamp(value), value)[None is value]) + if isinstance(value, datetime.datetime): + # noinspection PyCallByClass,PyTypeChecker + save_value = SGDatetime.totimestamp(value) + else: + save_value = value + self._save_fail_value('failure_time', save_value) @property def tmr_limit_count(self): diff --git a/sickbeard/webapi.py b/sickbeard/webapi.py index 03ce903..5f88d69 100644 --- a/sickbeard/webapi.py +++ b/sickbeard/webapi.py @@ -3991,10 +3991,10 @@ class CMD_SickGearShowRefresh(ApiCall): try: sickbeard.showQueueScheduler.action.refreshShow(show_obj) - return _responds(RESULT_SUCCESS, msg=str(show_obj.name) + " has queued to be refreshed") - except exceptions_helper.CantRefreshException: + return _responds(RESULT_SUCCESS, msg="%s has queued to be refreshed" % show_obj.name) + except exceptions_helper.CantRefreshException as e: # TODO: log the exception - return _responds(RESULT_FAILURE, msg="Unable to refresh " + str(show_obj.name)) + return _responds(RESULT_FAILURE, msg="Unable to refresh %s. %s" % (show_obj.name, ex(e))) class CMD_ShowRefresh(CMD_SickGearShowRefresh): @@ -4412,10 +4412,10 @@ class CMD_SickGearShowUpdate(ApiCall): try: sickbeard.showQueueScheduler.action.updateShow(show_obj, True) - return _responds(RESULT_SUCCESS, msg=str(show_obj.name) + " has queued to be updated") + return _responds(RESULT_SUCCESS, msg="%s has queued to be updated" % show_obj.name) except exceptions_helper.CantUpdateException as e: self.log(u"Unable to update %s. %s" % (show_obj.name, ex(e)), logger.ERROR) - return _responds(RESULT_FAILURE, msg="Unable to update " + str(show_obj.name)) + return _responds(RESULT_FAILURE, msg="Unable to update %s. %s" % (show_obj.name, ex(e))) class CMD_ShowUpdate(CMD_SickGearShowUpdate): diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py index c38ec99..ac76f10 100644 --- a/sickbeard/webserve.py +++ b/sickbeard/webserve.py @@ -3659,7 +3659,7 @@ class AddShows(Home): prodid = show_name = tvid = None for cur_provider in itervalues(sickbeard.metadata_provider_dict): if prodid and show_name: - continue + break (tvid, prodid, show_name) = cur_provider.retrieveShowMetadata(cur_path)