diff --git a/sickbeard/failedProcessor.py b/sickbeard/failedProcessor.py
index c728ab0f..7f052ef9 100644
--- a/sickbeard/failedProcessor.py
+++ b/sickbeard/failedProcessor.py
@@ -79,14 +79,9 @@ class FailedProcessor(object):
self._log(u"Could not create show object. Either the show hasn't been added to SickBeard, or it's still loading (if SB was restarted recently)", logger.WARNING)
raise exceptions.FailedProcessingFailed()
- # figure out what segment the episode is in and remember it so we can backlog it
- if self._show_obj.air_by_date:
- segment = str(parsed.air_date)[:7]
- else:
- segment = parsed.season_number
-
- cur_failed_queue_item = search_queue.FailedQueueItem(self._show_obj, segment, parsed.episode_numbers)
- sickbeard.searchQueueScheduler.action.add_item(cur_failed_queue_item)
+ for episode in parsed.episode_numbers:
+ cur_failed_queue_item = search_queue.FailedQueueItem(self._show_obj, {parsed.season_number: episode})
+ sickbeard.searchQueueScheduler.action.add_item(cur_failed_queue_item)
return True
diff --git a/sickbeard/failed_history.py b/sickbeard/failed_history.py
index 2237d143..a6f09fdd 100644
--- a/sickbeard/failed_history.py
+++ b/sickbeard/failed_history.py
@@ -110,7 +110,7 @@ def hasFailed(release, size, provider="%"):
return (len(sql_results) > 0)
-def revertEpisodes(show_obj, season, episodes):
+def revertEpisode(show_obj, season, episode=None):
"""Restore the episodes of a failed download to their original state"""
myDB = db.DBConnection("failed.db")
log_str = u""
@@ -119,24 +119,22 @@ def revertEpisodes(show_obj, season, episodes):
# {episode: result, ...}
history_eps = dict([(res["episode"], res) for res in sql_results])
- if len(episodes) > 0:
- for cur_episode in episodes:
- try:
- ep_obj = show_obj.getEpisode(season, cur_episode)
- except exceptions.EpisodeNotFoundException, e:
- log_str += _log_helper(u"Unable to create episode, please set its status manually: " + exceptions.ex(e), logger.WARNING)
- continue
-
- log_str += _log_helper(u"Reverting episode (%s, %s): %s" % (season, cur_episode, ep_obj.name))
+ if episode:
+ try:
+ ep_obj = show_obj.getEpisode(season, episode)
+ log_str += _log_helper(u"Reverting episode (%s, %s): %s" % (season, episode, ep_obj.name))
with ep_obj.lock:
- if cur_episode in history_eps:
+ if episode in history_eps:
log_str += _log_helper(u"Found in history")
- ep_obj.status = history_eps[cur_episode]['old_status']
+ ep_obj.status = history_eps[episode]['old_status']
else:
log_str += _log_helper(u"WARNING: Episode not found in history. Setting it back to WANTED", logger.WARNING)
ep_obj.status = WANTED
ep_obj.saveToDB()
+
+ except exceptions.EpisodeNotFoundException, e:
+ log_str += _log_helper(u"Unable to create episode, please set its status manually: " + exceptions.ex(e), logger.WARNING)
else:
# Whole season
log_str += _log_helper(u"Setting season to wanted: " + str(season))
@@ -152,21 +150,22 @@ def revertEpisodes(show_obj, season, episodes):
ep_obj.saveToDB()
-def markFailed(show_obj, season, episodes):
+ return log_str
+
+def markFailed(show_obj, season, episode=None):
log_str = u""
- if len(episodes) > 0:
- for cur_episode in episodes:
- try:
- ep_obj = show_obj.getEpisode(season, cur_episode)
- except exceptions.EpisodeNotFoundException, e:
- log_str += _log_helper(u"Unable to get episode, please set its status manually: " + exceptions.ex(e), logger.WARNING)
- continue
+ if episode:
+ try:
+ ep_obj = show_obj.getEpisode(season, episode)
with ep_obj.lock:
quality = Quality.splitCompositeStatus(ep_obj.status)[1]
ep_obj.status = Quality.compositeStatus(FAILED, quality)
ep_obj.saveToDB()
+
+ except exceptions.EpisodeNotFoundException, e:
+ log_str += _log_helper(u"Unable to get episode, please set its status manually: " + exceptions.ex(e), logger.WARNING)
else:
# Whole season
for ep_obj in show_obj.getAllEpisodes(season):
diff --git a/sickbeard/helpers.py b/sickbeard/helpers.py
index b740372f..4e99809d 100644
--- a/sickbeard/helpers.py
+++ b/sickbeard/helpers.py
@@ -953,51 +953,4 @@ def suffix(d):
return 'th' if 11<=d<=13 else {1:'st',2:'nd',3:'rd'}.get(d%10, 'th')
def custom_strftime(format, t):
- return t.strftime(format).replace('{S}', str(t.day) + suffix(t.day))
-
-def retry(ExceptionToCheck, default=None, tries=4, delay=3, backoff=2, logger=None):
- """Retry calling the decorated function using an exponential backoff.
-
- http://www.saltycrane.com/blog/2009/11/trying-out-retry-decorator-python/
- original from: http://wiki.python.org/moin/PythonDecoratorLibrary#Retry
-
- :param ExceptionToCheck: the exception to check. may be a tuple of
- excpetions to check
- :type ExceptionToCheck: Exception or tuple
- :param tries: number of times to try (not retry) before giving up
- :type tries: int
- :param delay: initial delay between retries in seconds
- :type delay: int
- :param backoff: backoff multiplier e.g. value of 2 will double the delay
- each retry
- :type backoff: int
- :param logger: logger to use. If None, print
- :type logger: logging.Logger instance
- """
- def deco_retry(f):
- def f_retry(*args, **kwargs):
- mtries, mdelay = tries, delay
- try_one_last_time = True
- while mtries > 1:
- try:
- print args,kwargs
- return f(*args, **kwargs)
- try_one_last_time = False
- break
- except ExceptionToCheck, e:
- msg = "%s, Retrying in %d seconds..." % (str(e), mdelay)
- if logger:
- logger.warning(msg)
- else:
- print msg
- time.sleep(mdelay)
- mtries -= 1
- mdelay *= backoff
- if try_one_last_time:
- try:
- return f(*args, **kwargs)
- except ExceptionToCheck, e:
- return default
- return
- return f_retry # true decorator
- return deco_retry
\ No newline at end of file
+ return t.strftime(format).replace('{S}', str(t.day) + suffix(t.day))
\ No newline at end of file
diff --git a/sickbeard/search_queue.py b/sickbeard/search_queue.py
index b1e63ab7..1c66fc69 100644
--- a/sickbeard/search_queue.py
+++ b/sickbeard/search_queue.py
@@ -26,6 +26,7 @@ from sickbeard import db, logger, common, exceptions, helpers
from sickbeard import generic_queue
from sickbeard import search, failed_history, history
from sickbeard import ui
+from sickbeard.common import Quality
BACKLOG_SEARCH = 10
RSS_SEARCH = 20
@@ -238,73 +239,42 @@ class BacklogQueueItem(generic_queue.QueueItem):
class FailedQueueItem(generic_queue.QueueItem):
- def __init__(self, show, segment, episodes):
+ def __init__(self, show, segment):
generic_queue.QueueItem.__init__(self, 'Retry', MANUAL_SEARCH)
self.priority = generic_queue.QueuePriorities.HIGH
self.thread_name = 'RETRY-' + str(show.indexerid)
self.show = show
self.segment = segment
- self.episodes = episodes
-
+
self.success = None
def execute(self):
generic_queue.QueueItem.execute(self)
- season = self.segment
- if self.show.air_by_date:
- myDB = db.DBConnection()
+ for season, episode in self.segment.iteritems():
+ epObj = self.show.getEpisode(season, episode)
- season_year, season_month = map(int, season.split('-'))
- min_date = datetime.date(season_year, season_month, 1)
+ (release, provider) = failed_history.findRelease(self.show, season, episode)
+ if release:
+ logger.log(u"Marking release as bad: " + release)
+ failed_history.markFailed(self.show, season, episode)
+ failed_history.logFailed(release)
+ history.logFailed(self.show.indexerid, season, episode, epObj.status, release, provider)
- # it's easier to just hard code this than to worry about rolling the year over or making a month length map
- if season_month == 12:
- max_date = datetime.date(season_year, 12, 31)
+ failed_history.revertEpisode(self.show, season, episode)
+
+ for season, episode in self.segment.iteritems():
+ epObj = self.show.getEpisode(season, episode)
+
+ if self.show.air_by_date:
+ results = search.findSeason(self.show, str(epObj.airdate)[:7])
else:
- max_date = datetime.date(season_year, season_month + 1, 1) - datetime.timedelta(days=1)
+ results = search.findSeason(self.show, season)
- for episode in self.episodes:
- season = myDB.fetch("SELECT season FROM tv_episodes WHERE showid = ? AND airdate >= ? AND airdate <= ? AND episode = ?",
- [self.show.indexerid, min_date.toordinal(), max_date.toordinal(), episode])
- if self.episodes > 1:
- for episode in self.episodes:
- (release, provider) = failed_history.findRelease(self.show, season, episode)
- if release:
- logger.log(u"Marking release as bad: " + release)
- failed_history.markFailed(self.show, season, [episode])
- failed_history.logFailed(release)
- history.logFailed(self.show.indexerid, season, episode, common.Quality.NONE, release, provider)
-
- failed_history.revertEpisodes(self.show, season, [episode])
-
- # Single failed episode search
- epObj = self.show.getEpisode(int(season), int(episode))
- foundEpisode = search.findEpisode(epObj, manualSearch=True)
- if not foundEpisode:
- ui.notifications.message('No downloads were found', "Couldn't find a download for %s" % epObj.prettyName())
- logger.log(u"Unable to find a download for " + epObj.prettyName())
- else:
- # just use the first result for now
- logger.log(u"Downloading episode from " + foundEpisode.url)
- result = search.snatchEpisode(foundEpisode)
- providerModule = foundEpisode.provider
- if not result:
- ui.notifications.error('Error while attempting to snatch ' + foundEpisode.name+', check your logs')
- elif providerModule == None:
- ui.notifications.error('Provider is configured incorrectly, unable to download')
-
- self.success = result
-
- return
-
- # Multiple failed episode search
- results = search.findSeason(self.show, self.segment)
-
- # download whatever we find
- for curResult in results:
- search.snatchEpisode(curResult)
- time.sleep(5)
+ # download whatever we find
+ for curResult in results:
+ self.success = search.snatchEpisode(curResult)
+ time.sleep(5)
self.finish()
diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py
index 62e6d855..0bf54188 100644
--- a/sickbeard/webserve.py
+++ b/sickbeard/webserve.py
@@ -3075,7 +3075,8 @@ class Home:
else:
return _genericMessage("Error", errMsg)
- segment_list = {}
+ wanted_segments = []
+ failed_segments = {}
if eps != None:
@@ -3091,11 +3092,14 @@ class Home:
return _genericMessage("Error", "Episode couldn't be retrieved")
if int(status) in (WANTED, FAILED):
- # figure out what segment the episode is in and remember it so we can backlog it
+ # figure out what episodes are wanted so we can backlog them
if epObj.show.air_by_date:
- segment_list.setdefault(str(epObj.airdate)[:7],[]).append(epObj.episode)
+ wanted_segments.append(str(epObj.airdate)[:7])
else:
- segment_list.setdefault(epObj.season,[]).append(epObj.episode)
+ wanted_segments.append(epObj.season)
+
+ # figure out what episodes failed so we can retry them
+ failed_segments.setdefault(epObj.season,[]).append(epObj.episode)
with epObj.lock:
# don't let them mess up UNAIRED episodes
@@ -3116,26 +3120,26 @@ class Home:
if int(status) == WANTED:
msg = "Backlog was automatically started for the following seasons of " + showObj.name + ":