mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-02 17:33:37 +00:00
Change add BaseSearchQueueItem and base_info() for thread-safe checks.
Change to making simple base info of search_queue items instead of full deep copies. Change move TVShow.getOverview logic to helpers.episode_status_overview() and call it with parameter in tv.py and webserve.py
This commit is contained in:
parent
85a5f6ea00
commit
89905fc94d
5 changed files with 107 additions and 81 deletions
|
@ -452,3 +452,17 @@ else:
|
||||||
return v if v is not None else default
|
return v if v is not None else default
|
||||||
|
|
||||||
sickbeard.ENV = LinuxEnv(os.environ)
|
sickbeard.ENV = LinuxEnv(os.environ)
|
||||||
|
|
||||||
|
|
||||||
|
# backport from python 3
|
||||||
|
class SimpleNamespace:
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.__dict__.update(kwargs)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
keys = sorted(self.__dict__)
|
||||||
|
items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys)
|
||||||
|
return "{}({})".format(type(self).__name__, ", ".join(items))
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return self.__dict__ == other.__dict__
|
||||||
|
|
|
@ -59,7 +59,7 @@ except ImportError:
|
||||||
from sickbeard.exceptions import MultipleShowObjectsException, ex
|
from sickbeard.exceptions import MultipleShowObjectsException, ex
|
||||||
from sickbeard import logger, db, notifiers, clients
|
from sickbeard import logger, db, notifiers, clients
|
||||||
from sickbeard.common import USER_AGENT, mediaExtensions, subtitleExtensions, cpu_presets, statusStrings, \
|
from sickbeard.common import USER_AGENT, mediaExtensions, subtitleExtensions, cpu_presets, statusStrings, \
|
||||||
SNATCHED_ANY, DOWNLOADED, ARCHIVED, IGNORED, Quality
|
SNATCHED_ANY, DOWNLOADED, ARCHIVED, IGNORED, WANTED, SKIPPED, UNAIRED, UNKNOWN, SUBTITLED, FAILED, Quality, Overview
|
||||||
from sickbeard import encodingKludge as ek
|
from sickbeard import encodingKludge as ek
|
||||||
|
|
||||||
from lib.cachecontrol import CacheControl, caches
|
from lib.cachecontrol import CacheControl, caches
|
||||||
|
@ -1797,3 +1797,34 @@ def clean_data(data):
|
||||||
from lib.six.moves.html_parser import HTMLParser
|
from lib.six.moves.html_parser import HTMLParser
|
||||||
return HTMLParser().unescape(data).strip().replace(u'&', u'&')
|
return HTMLParser().unescape(data).strip().replace(u'&', u'&')
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def getOverview(epStatus, show_quality, upgrade_once):
|
||||||
|
|
||||||
|
status, quality = Quality.splitCompositeStatus(epStatus)
|
||||||
|
if ARCHIVED == status:
|
||||||
|
return Overview.GOOD
|
||||||
|
if WANTED == status:
|
||||||
|
return Overview.WANTED
|
||||||
|
if status in (SKIPPED, IGNORED):
|
||||||
|
return Overview.SKIPPED
|
||||||
|
if status in (UNAIRED, UNKNOWN):
|
||||||
|
return Overview.UNAIRED
|
||||||
|
if status in [SUBTITLED] + Quality.SNATCHED_ANY + Quality.DOWNLOADED + Quality.FAILED:
|
||||||
|
|
||||||
|
if FAILED == status:
|
||||||
|
return Overview.WANTED
|
||||||
|
if status in SNATCHED_ANY:
|
||||||
|
return Overview.SNATCHED
|
||||||
|
|
||||||
|
void, best_qualities = Quality.splitQuality(show_quality)
|
||||||
|
# if re-downloads aren't wanted then mark it "good" if there is anything
|
||||||
|
if not len(best_qualities):
|
||||||
|
return Overview.GOOD
|
||||||
|
|
||||||
|
min_best, max_best = min(best_qualities), max(best_qualities)
|
||||||
|
if quality >= max_best \
|
||||||
|
or (upgrade_once and
|
||||||
|
(quality in best_qualities or (None is not min_best and quality > min_best))):
|
||||||
|
return Overview.GOOD
|
||||||
|
return Overview.QUAL
|
||||||
|
|
|
@ -27,7 +27,7 @@ import sickbeard
|
||||||
from sickbeard import db, logger, common, exceptions, helpers, network_timezones, generic_queue, search, \
|
from sickbeard import db, logger, common, exceptions, helpers, network_timezones, generic_queue, search, \
|
||||||
failed_history, history, ui, properFinder
|
failed_history, history, ui, properFinder
|
||||||
from sickbeard.search import wanted_episodes, get_aired_in_season, set_wanted_aired
|
from sickbeard.search import wanted_episodes, get_aired_in_season, set_wanted_aired
|
||||||
from sickbeard.classes import Proper
|
from sickbeard.classes import Proper, SimpleNamespace
|
||||||
from sickbeard.indexers.indexer_config import INDEXER_TVDB
|
from sickbeard.indexers.indexer_config import INDEXER_TVDB
|
||||||
|
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ class SearchQueue(generic_queue.GenericQueue):
|
||||||
for cur_item in self.queue:
|
for cur_item in self.queue:
|
||||||
if (isinstance(cur_item, (ManualSearchQueueItem, FailedQueueItem)) and
|
if (isinstance(cur_item, (ManualSearchQueueItem, FailedQueueItem)) and
|
||||||
(not show or show == str(cur_item.show.indexerid))):
|
(not show or show == str(cur_item.show.indexerid))):
|
||||||
ep_obj_list.append(cur_item.copy())
|
ep_obj_list.append(cur_item.base_info())
|
||||||
|
|
||||||
return ep_obj_list
|
return ep_obj_list
|
||||||
|
|
||||||
|
@ -115,7 +115,7 @@ class SearchQueue(generic_queue.GenericQueue):
|
||||||
with self.lock:
|
with self.lock:
|
||||||
if self.currentItem and isinstance(self.currentItem, (ManualSearchQueueItem, FailedQueueItem)) \
|
if self.currentItem and isinstance(self.currentItem, (ManualSearchQueueItem, FailedQueueItem)) \
|
||||||
and (not show or show == str(self.currentItem.show.indexerid)):
|
and (not show or show == str(self.currentItem.show.indexerid)):
|
||||||
return self.currentItem.copy()
|
return self.currentItem.base_info()
|
||||||
|
|
||||||
def is_backlog_in_progress(self):
|
def is_backlog_in_progress(self):
|
||||||
return self._is_in_progress(BacklogQueueItem)
|
return self._is_in_progress(BacklogQueueItem)
|
||||||
|
@ -407,23 +407,60 @@ class ProperSearchQueueItem(generic_queue.QueueItem):
|
||||||
self.finish()
|
self.finish()
|
||||||
|
|
||||||
|
|
||||||
class ManualSearchQueueItem(generic_queue.QueueItem):
|
class BaseSearchQueueItem(generic_queue.QueueItem):
|
||||||
def __init__(self, show, segment):
|
def __init__(self, show, segment, name, action_id=0):
|
||||||
generic_queue.QueueItem.__init__(self, 'Manual Search', MANUAL_SEARCH)
|
super(BaseSearchQueueItem, self).__init__(name, action_id)
|
||||||
self.priority = generic_queue.QueuePriorities.HIGH
|
|
||||||
self.name = 'MANUAL-%s' % show.indexerid
|
|
||||||
self.success = None
|
|
||||||
self.show = show
|
|
||||||
self.segment = segment
|
self.segment = segment
|
||||||
self.started = None
|
self.show = show
|
||||||
self.added_dt = None
|
self.success = None
|
||||||
self.snatched_eps = set([])
|
self.snatched_eps = set([])
|
||||||
|
|
||||||
|
def base_info(self):
|
||||||
|
o = SimpleNamespace()
|
||||||
|
o.success = self.success
|
||||||
|
o.show = SimpleNamespace()
|
||||||
|
o.show.indexer = self.show.indexer
|
||||||
|
o.show.indexerid = self.show.indexerid
|
||||||
|
o.show.quality = self.show.quality
|
||||||
|
o.show.upgrade_once = self.show.upgrade_once
|
||||||
|
sl = []
|
||||||
|
for s in ([self.segment], self.segment)[isinstance(self.segment, list)]:
|
||||||
|
eo = SimpleNamespace()
|
||||||
|
eo.episode = s.episode
|
||||||
|
eo.season = s.season
|
||||||
|
eo.status = s.status
|
||||||
|
eo.show = SimpleNamespace()
|
||||||
|
eo.show.indexer = s.show.indexer
|
||||||
|
eo.show.indexerid = s.show.indexerid
|
||||||
|
eo.show.quality = s.show.quality
|
||||||
|
eo.show.upgrade_once = s.show.upgrade_once
|
||||||
|
sl.append(eo)
|
||||||
|
o.segment = sl
|
||||||
|
|
||||||
|
return o
|
||||||
|
|
||||||
def copy(self, deepcopy_obj=None):
|
def copy(self, deepcopy_obj=None):
|
||||||
if not isinstance(deepcopy_obj, list):
|
if not isinstance(deepcopy_obj, list):
|
||||||
deepcopy_obj = []
|
deepcopy_obj = []
|
||||||
deepcopy_obj += ['segment', 'show']
|
deepcopy_obj += ['segment']
|
||||||
return super(ManualSearchQueueItem, self).copy(deepcopy_obj)
|
same_show = True
|
||||||
|
if (isinstance(self.segment, list) and getattr(self.segment[0], 'show') is not self.show) \
|
||||||
|
or getattr(self.segment, 'show') is not self.show:
|
||||||
|
same_show = False
|
||||||
|
deepcopy_obj += ['show']
|
||||||
|
n_o = super(BaseSearchQueueItem, self).copy(deepcopy_obj)
|
||||||
|
if same_show:
|
||||||
|
n_o.show = (getattr(n_o.segment, 'show'), getattr(n_o.segment[0], 'show'))[isinstance(n_o.segment, list)]
|
||||||
|
return n_o
|
||||||
|
|
||||||
|
|
||||||
|
class ManualSearchQueueItem(BaseSearchQueueItem):
|
||||||
|
def __init__(self, show, segment):
|
||||||
|
super(ManualSearchQueueItem, self).__init__(show, segment, 'Manual Search', MANUAL_SEARCH)
|
||||||
|
self.priority = generic_queue.QueuePriorities.HIGH
|
||||||
|
self.name = 'MANUAL-%s' % show.indexerid
|
||||||
|
self.started = None
|
||||||
|
self.added_dt = None
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
generic_queue.QueueItem.run(self)
|
generic_queue.QueueItem.run(self)
|
||||||
|
@ -465,25 +502,15 @@ class ManualSearchQueueItem(generic_queue.QueueItem):
|
||||||
self.finish()
|
self.finish()
|
||||||
|
|
||||||
|
|
||||||
class BacklogQueueItem(generic_queue.QueueItem):
|
class BacklogQueueItem(BaseSearchQueueItem):
|
||||||
def __init__(self, show, segment, standard_backlog=False, limited_backlog=False, forced=False, torrent_only=False):
|
def __init__(self, show, segment, standard_backlog=False, limited_backlog=False, forced=False, torrent_only=False):
|
||||||
generic_queue.QueueItem.__init__(self, 'Backlog', BACKLOG_SEARCH)
|
super(BacklogQueueItem, self).__init__(show, segment, 'Backlog', BACKLOG_SEARCH)
|
||||||
self.priority = generic_queue.QueuePriorities.LOW
|
self.priority = generic_queue.QueuePriorities.LOW
|
||||||
self.name = 'BACKLOG-%s' % show.indexerid
|
self.name = 'BACKLOG-%s' % show.indexerid
|
||||||
self.success = None
|
|
||||||
self.show = show
|
|
||||||
self.segment = segment
|
|
||||||
self.standard_backlog = standard_backlog
|
self.standard_backlog = standard_backlog
|
||||||
self.limited_backlog = limited_backlog
|
self.limited_backlog = limited_backlog
|
||||||
self.forced = forced
|
self.forced = forced
|
||||||
self.torrent_only = torrent_only
|
self.torrent_only = torrent_only
|
||||||
self.snatched_eps = set([])
|
|
||||||
|
|
||||||
def copy(self, deepcopy_obj=None):
|
|
||||||
if not isinstance(deepcopy_obj, list):
|
|
||||||
deepcopy_obj = []
|
|
||||||
deepcopy_obj += ['segment', 'show']
|
|
||||||
return super(BacklogQueueItem, self).copy(deepcopy_obj)
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
generic_queue.QueueItem.run(self)
|
generic_queue.QueueItem.run(self)
|
||||||
|
@ -521,23 +548,13 @@ class BacklogQueueItem(generic_queue.QueueItem):
|
||||||
self.finish()
|
self.finish()
|
||||||
|
|
||||||
|
|
||||||
class FailedQueueItem(generic_queue.QueueItem):
|
class FailedQueueItem(BaseSearchQueueItem):
|
||||||
def __init__(self, show, segment):
|
def __init__(self, show, segment):
|
||||||
generic_queue.QueueItem.__init__(self, 'Retry', FAILED_SEARCH)
|
super(FailedQueueItem, self).__init__(show, segment, 'Retry', FAILED_SEARCH)
|
||||||
self.priority = generic_queue.QueuePriorities.HIGH
|
self.priority = generic_queue.QueuePriorities.HIGH
|
||||||
self.name = 'RETRY-%s' % show.indexerid
|
self.name = 'RETRY-%s' % show.indexerid
|
||||||
self.show = show
|
|
||||||
self.segment = segment
|
|
||||||
self.success = None
|
|
||||||
self.started = None
|
self.started = None
|
||||||
self.added_dt = None
|
self.added_dt = None
|
||||||
self.snatched_eps = set([])
|
|
||||||
|
|
||||||
def copy(self, deepcopy_obj=None):
|
|
||||||
if not isinstance(deepcopy_obj, list):
|
|
||||||
deepcopy_obj = []
|
|
||||||
deepcopy_obj += ['segment', 'show']
|
|
||||||
return super(FailedQueueItem, self).copy(deepcopy_obj)
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
generic_queue.QueueItem.run(self)
|
generic_queue.QueueItem.run(self)
|
||||||
|
|
|
@ -1615,34 +1615,7 @@ class TVShow(object):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def getOverview(self, epStatus):
|
def getOverview(self, epStatus):
|
||||||
|
return helpers.getOverview(epStatus, self.quality, self.upgrade_once)
|
||||||
status, quality = Quality.splitCompositeStatus(epStatus)
|
|
||||||
if ARCHIVED == status:
|
|
||||||
return Overview.GOOD
|
|
||||||
if WANTED == status:
|
|
||||||
return Overview.WANTED
|
|
||||||
if status in (SKIPPED, IGNORED):
|
|
||||||
return Overview.SKIPPED
|
|
||||||
if status in (UNAIRED, UNKNOWN):
|
|
||||||
return Overview.UNAIRED
|
|
||||||
if status in [SUBTITLED] + Quality.SNATCHED_ANY + Quality.DOWNLOADED + Quality.FAILED:
|
|
||||||
|
|
||||||
if FAILED == status:
|
|
||||||
return Overview.WANTED
|
|
||||||
if status in SNATCHED_ANY:
|
|
||||||
return Overview.SNATCHED
|
|
||||||
|
|
||||||
void, best_qualities = Quality.splitQuality(self.quality)
|
|
||||||
# if re-downloads aren't wanted then mark it "good" if there is anything
|
|
||||||
if not len(best_qualities):
|
|
||||||
return Overview.GOOD
|
|
||||||
|
|
||||||
min_best, max_best = min(best_qualities), max(best_qualities)
|
|
||||||
if quality >= max_best \
|
|
||||||
or (self.upgrade_once and
|
|
||||||
(quality in best_qualities or (None is not min_best and quality > min_best))):
|
|
||||||
return Overview.GOOD
|
|
||||||
return Overview.QUAL
|
|
||||||
|
|
||||||
def __getstate__(self):
|
def __getstate__(self):
|
||||||
d = dict(self.__dict__)
|
d = dict(self.__dict__)
|
||||||
|
|
|
@ -2808,12 +2808,7 @@ class Home(MainHandler):
|
||||||
|
|
||||||
progress = 'queued'
|
progress = 'queued'
|
||||||
for thread in queued_items:
|
for thread in queued_items:
|
||||||
if isinstance(thread, sickbeard.search_queue.ManualSearchQueueItem):
|
if hasattr(thread, 'segment'):
|
||||||
ep, uniq_sxe = self.prepare_episode(thread.show, thread.segment, progress)
|
|
||||||
episodes.append(ep)
|
|
||||||
seen_eps.add(uniq_sxe)
|
|
||||||
|
|
||||||
elif hasattr(thread, 'segment'):
|
|
||||||
for ep_obj in thread.segment:
|
for ep_obj in thread.segment:
|
||||||
ep, uniq_sxe = self.prepare_episode(ep_obj.show, ep_obj, progress)
|
ep, uniq_sxe = self.prepare_episode(ep_obj.show, ep_obj, progress)
|
||||||
episodes.append(ep)
|
episodes.append(ep)
|
||||||
|
@ -2824,12 +2819,7 @@ class Home(MainHandler):
|
||||||
episode_params = dict(([('searchstate', 'finished'), ('statusoverview', True)],
|
episode_params = dict(([('searchstate', 'finished'), ('statusoverview', True)],
|
||||||
[('searchstate', 'searching'), ('statusoverview', False)])[None is thread.success],
|
[('searchstate', 'searching'), ('statusoverview', False)])[None is thread.success],
|
||||||
retrystate=True)
|
retrystate=True)
|
||||||
if isinstance(thread, sickbeard.search_queue.ManualSearchQueueItem):
|
if hasattr(thread, 'segment'):
|
||||||
ep, uniq_sxe = self.prepare_episode(thread.show, thread.segment, **episode_params)
|
|
||||||
episodes.append(ep)
|
|
||||||
seen_eps.add(uniq_sxe)
|
|
||||||
|
|
||||||
elif hasattr(thread, 'segment'):
|
|
||||||
for ep_obj in thread.segment:
|
for ep_obj in thread.segment:
|
||||||
ep, uniq_sxe = self.prepare_episode(ep_obj.show, ep_obj, **episode_params)
|
ep, uniq_sxe = self.prepare_episode(ep_obj.show, ep_obj, **episode_params)
|
||||||
episodes.append(ep)
|
episodes.append(ep)
|
||||||
|
@ -2837,7 +2827,7 @@ class Home(MainHandler):
|
||||||
|
|
||||||
episode_params = dict(searchstate='finished', retrystate=True, statusoverview=True)
|
episode_params = dict(searchstate='finished', retrystate=True, statusoverview=True)
|
||||||
for thread in finished_items:
|
for thread in finished_items:
|
||||||
if isinstance(thread, sickbeard.search_queue.ManualSearchQueueItem):
|
if not isinstance(getattr(thread, 'segment'), list):
|
||||||
if (not show or show == str(thread.show.indexerid)) and \
|
if (not show or show == str(thread.show.indexerid)) and \
|
||||||
(thread.show.indexer, thread.show.indexerid, thread.segment.season, thread.segment.episode) \
|
(thread.show.indexer, thread.show.indexerid, thread.segment.season, thread.segment.episode) \
|
||||||
not in seen_eps:
|
not in seen_eps:
|
||||||
|
@ -2894,7 +2884,8 @@ class Home(MainHandler):
|
||||||
retry_statuses = SNATCHED_ANY + [DOWNLOADED, ARCHIVED]
|
retry_statuses = SNATCHED_ANY + [DOWNLOADED, ARCHIVED]
|
||||||
ep_data.update(dict(retrystate=sickbeard.USE_FAILED_DOWNLOADS and ep_status in retry_statuses))
|
ep_data.update(dict(retrystate=sickbeard.USE_FAILED_DOWNLOADS and ep_status in retry_statuses))
|
||||||
if statusoverview:
|
if statusoverview:
|
||||||
ep_data.update(dict(statusoverview=Overview.overviewStrings[show.getOverview(ep.status)]))
|
ep_data.update(dict(statusoverview=Overview.overviewStrings[
|
||||||
|
helpers.getOverview(ep.status, show.quality, show.upgrade_once)]))
|
||||||
|
|
||||||
return ep_data, (show.indexer, show.indexerid, ep.season, ep.episode)
|
return ep_data, (show.indexer, show.indexerid, ep.season, ep.episode)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue