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
|
||||
|
||||
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 import logger, db, notifiers, clients
|
||||
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 lib.cachecontrol import CacheControl, caches
|
||||
|
@ -1797,3 +1797,34 @@ def clean_data(data):
|
|||
from lib.six.moves.html_parser import HTMLParser
|
||||
return HTMLParser().unescape(data).strip().replace(u'&', u'&')
|
||||
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, \
|
||||
failed_history, history, ui, properFinder
|
||||
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
|
||||
|
||||
|
||||
|
@ -101,7 +101,7 @@ class SearchQueue(generic_queue.GenericQueue):
|
|||
for cur_item in self.queue:
|
||||
if (isinstance(cur_item, (ManualSearchQueueItem, FailedQueueItem)) and
|
||||
(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
|
||||
|
||||
|
@ -115,7 +115,7 @@ class SearchQueue(generic_queue.GenericQueue):
|
|||
with self.lock:
|
||||
if self.currentItem and isinstance(self.currentItem, (ManualSearchQueueItem, FailedQueueItem)) \
|
||||
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):
|
||||
return self._is_in_progress(BacklogQueueItem)
|
||||
|
@ -407,23 +407,60 @@ class ProperSearchQueueItem(generic_queue.QueueItem):
|
|||
self.finish()
|
||||
|
||||
|
||||
class ManualSearchQueueItem(generic_queue.QueueItem):
|
||||
def __init__(self, show, segment):
|
||||
generic_queue.QueueItem.__init__(self, 'Manual Search', MANUAL_SEARCH)
|
||||
self.priority = generic_queue.QueuePriorities.HIGH
|
||||
self.name = 'MANUAL-%s' % show.indexerid
|
||||
self.success = None
|
||||
self.show = show
|
||||
class BaseSearchQueueItem(generic_queue.QueueItem):
|
||||
def __init__(self, show, segment, name, action_id=0):
|
||||
super(BaseSearchQueueItem, self).__init__(name, action_id)
|
||||
self.segment = segment
|
||||
self.started = None
|
||||
self.added_dt = None
|
||||
self.show = show
|
||||
self.success = None
|
||||
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):
|
||||
if not isinstance(deepcopy_obj, list):
|
||||
deepcopy_obj = []
|
||||
deepcopy_obj += ['segment', 'show']
|
||||
return super(ManualSearchQueueItem, self).copy(deepcopy_obj)
|
||||
deepcopy_obj += ['segment']
|
||||
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):
|
||||
generic_queue.QueueItem.run(self)
|
||||
|
@ -465,25 +502,15 @@ class ManualSearchQueueItem(generic_queue.QueueItem):
|
|||
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):
|
||||
generic_queue.QueueItem.__init__(self, 'Backlog', BACKLOG_SEARCH)
|
||||
super(BacklogQueueItem, self).__init__(show, segment, 'Backlog', BACKLOG_SEARCH)
|
||||
self.priority = generic_queue.QueuePriorities.LOW
|
||||
self.name = 'BACKLOG-%s' % show.indexerid
|
||||
self.success = None
|
||||
self.show = show
|
||||
self.segment = segment
|
||||
self.standard_backlog = standard_backlog
|
||||
self.limited_backlog = limited_backlog
|
||||
self.forced = forced
|
||||
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):
|
||||
generic_queue.QueueItem.run(self)
|
||||
|
@ -521,23 +548,13 @@ class BacklogQueueItem(generic_queue.QueueItem):
|
|||
self.finish()
|
||||
|
||||
|
||||
class FailedQueueItem(generic_queue.QueueItem):
|
||||
class FailedQueueItem(BaseSearchQueueItem):
|
||||
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.name = 'RETRY-%s' % show.indexerid
|
||||
self.show = show
|
||||
self.segment = segment
|
||||
self.success = None
|
||||
self.started = 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):
|
||||
generic_queue.QueueItem.run(self)
|
||||
|
|
|
@ -1615,34 +1615,7 @@ class TVShow(object):
|
|||
return False
|
||||
|
||||
def getOverview(self, epStatus):
|
||||
|
||||
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
|
||||
return helpers.getOverview(epStatus, self.quality, self.upgrade_once)
|
||||
|
||||
def __getstate__(self):
|
||||
d = dict(self.__dict__)
|
||||
|
|
|
@ -2808,12 +2808,7 @@ class Home(MainHandler):
|
|||
|
||||
progress = 'queued'
|
||||
for thread in queued_items:
|
||||
if isinstance(thread, sickbeard.search_queue.ManualSearchQueueItem):
|
||||
ep, uniq_sxe = self.prepare_episode(thread.show, thread.segment, progress)
|
||||
episodes.append(ep)
|
||||
seen_eps.add(uniq_sxe)
|
||||
|
||||
elif hasattr(thread, 'segment'):
|
||||
if hasattr(thread, 'segment'):
|
||||
for ep_obj in thread.segment:
|
||||
ep, uniq_sxe = self.prepare_episode(ep_obj.show, ep_obj, progress)
|
||||
episodes.append(ep)
|
||||
|
@ -2824,12 +2819,7 @@ class Home(MainHandler):
|
|||
episode_params = dict(([('searchstate', 'finished'), ('statusoverview', True)],
|
||||
[('searchstate', 'searching'), ('statusoverview', False)])[None is thread.success],
|
||||
retrystate=True)
|
||||
if isinstance(thread, sickbeard.search_queue.ManualSearchQueueItem):
|
||||
ep, uniq_sxe = self.prepare_episode(thread.show, thread.segment, **episode_params)
|
||||
episodes.append(ep)
|
||||
seen_eps.add(uniq_sxe)
|
||||
|
||||
elif hasattr(thread, 'segment'):
|
||||
if hasattr(thread, 'segment'):
|
||||
for ep_obj in thread.segment:
|
||||
ep, uniq_sxe = self.prepare_episode(ep_obj.show, ep_obj, **episode_params)
|
||||
episodes.append(ep)
|
||||
|
@ -2837,7 +2827,7 @@ class Home(MainHandler):
|
|||
|
||||
episode_params = dict(searchstate='finished', retrystate=True, statusoverview=True)
|
||||
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 \
|
||||
(thread.show.indexer, thread.show.indexerid, thread.segment.season, thread.segment.episode) \
|
||||
not in seen_eps:
|
||||
|
@ -2894,7 +2884,8 @@ class Home(MainHandler):
|
|||
retry_statuses = SNATCHED_ANY + [DOWNLOADED, ARCHIVED]
|
||||
ep_data.update(dict(retrystate=sickbeard.USE_FAILED_DOWNLOADS and ep_status in retry_statuses))
|
||||
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)
|
||||
|
||||
|
|
Loading…
Reference in a new issue