diff --git a/sickbeard/search.py b/sickbeard/search.py
index fefecb83..f8e945bc 100644
--- a/sickbeard/search.py
+++ b/sickbeard/search.py
@@ -387,12 +387,8 @@ def searchProviders(queueItem, show, season, episodes, seasonSearch=False, manua
else:
anyWanted = True
- # if we need every ep in the season check if single episode releases should be preferred over season releases (missing single episode releases will be picked individually from season release)
- preferSingleEpisodesOverSeasonReleases = sickbeard.PREFER_EPISODE_RELEASES
- logger.log(u"Prefer single episodes over season releases: " + str(preferSingleEpisodesOverSeasonReleases),
- logger.DEBUG)
# if we need every ep in the season and there's nothing better then just download this and be done with it (unless single episodes are preferred)
- if allWanted and bestSeasonNZB.quality == highest_quality_overall and not preferSingleEpisodesOverSeasonReleases:
+ if allWanted and bestSeasonNZB.quality == highest_quality_overall:
logger.log(
u"Every ep in this season is needed, downloading the whole " + bestSeasonNZB.provider.providerType + " " + bestSeasonNZB.name)
epObjs = []
diff --git a/sickbeard/searchBacklog.py b/sickbeard/searchBacklog.py
index b1c230f1..fbbb1ebe 100644
--- a/sickbeard/searchBacklog.py
+++ b/sickbeard/searchBacklog.py
@@ -27,7 +27,7 @@ from sickbeard import db, scheduler
from sickbeard import search_queue
from sickbeard import logger
from sickbeard import ui
-#from sickbeard.common import *
+from sickbeard import common
class BacklogSearchScheduler(scheduler.Scheduler):
def forceSearch(self):
@@ -90,46 +90,17 @@ class BacklogSearcher:
self.amActive = True
self.amPaused = False
- #myDB = db.DBConnection()
- #numSeasonResults = myDB.select("SELECT DISTINCT(season), showid FROM tv_episodes ep, tv_shows show WHERE season != 0 AND ep.showid = show.indexer_id AND show.paused = 0 AND ep.airdate > ?", [fromDate.toordinal()])
-
- # get separate lists of the season/date shows
- #season_shows = [x for x in show_list if not x.air_by_date]
- air_by_date_shows = [x for x in show_list if x.air_by_date]
-
- # figure out how many segments of air by date shows we're going to do
- air_by_date_segments = []
- for cur_id in [x.indexerid for x in air_by_date_shows]:
- air_by_date_segments += self._get_air_by_date_segments(cur_id, fromDate)
-
- logger.log(u"Air-by-date segments: " + str(air_by_date_segments), logger.DEBUG)
-
- #totalSeasons = float(len(numSeasonResults) + len(air_by_date_segments))
- #numSeasonsDone = 0.0
-
# go through non air-by-date shows and see if they need any episodes
for curShow in show_list:
if curShow.paused:
continue
- if curShow.air_by_date:
- segments = [x[1] for x in self._get_air_by_date_segments(curShow.indexerid, fromDate)]
- else:
- segments = self._get_segments(curShow.indexerid, fromDate)
+ segments = self._get_segments(curShow, fromDate)
- for cur_segment in segments:
-
- self.currentSearchInfo = {'title': curShow.name + " Season " + str(cur_segment)}
-
- backlog_queue_item = search_queue.BacklogQueueItem(curShow, cur_segment)
-
- if backlog_queue_item.wantedEpisodes:
- sickbeard.searchQueueScheduler.action.add_item(backlog_queue_item) #@UndefinedVariable
- else:
- logger.log(
- u"Nothing in season " + str(cur_segment) + " needs to be downloaded, skipping this season",
- logger.DEBUG)
+ if len(segments):
+ backlog_queue_item = search_queue.BacklogQueueItem(curShow, segments)
+ sickbeard.searchQueueScheduler.action.add_item(backlog_queue_item) #@UndefinedVariable
# don't consider this an actual backlog search if we only did recent eps
# or if we only did certain shows
@@ -158,34 +129,42 @@ class BacklogSearcher:
self._lastBacklog = lastBacklog
return self._lastBacklog
- def _get_segments(self, indexer_id, fromDate):
+ def _get_segments(self, show, fromDate):
+ anyQualities, bestQualities = common.Quality.splitQuality(show.quality) #@UnusedVariable
+
myDB = db.DBConnection()
- sqlResults = myDB.select(
- "SELECT DISTINCT(season) as season FROM tv_episodes WHERE showid = ? AND season > 0 and airdate > ?",
- [indexer_id, fromDate.toordinal()])
+ if show.air_by_date:
+ sqlResults = myDB.select(
+ "SELECT ep.status, ep.season, ep.episode FROM tv_episodes ep, tv_shows show WHERE season != 0 AND ep.showid = show.indexer_id AND show.paused = 0 ANd ep.airdate > ? AND ep.showid = ? AND show.air_by_date = 1",
+ [fromDate.toordinal(), show.indexerid])
+ else:
+ sqlResults = myDB.select(
+ "SELECT status, season, episode FROM tv_episodes WHERE showid = ? AND season > 0 and airdate > ?",
+ [show.indexerid, fromDate.toordinal()])
- return [int(x["season"]) for x in sqlResults]
+ # check through the list of statuses to see if we want any
+ wanted = {}
+ for result in sqlResults:
+ curCompositeStatus = int(result["status"])
+ curStatus, curQuality = common.Quality.splitCompositeStatus(curCompositeStatus)
- def _get_air_by_date_segments(self, indexer_id, fromDate):
- # query the DB for all dates for this show
- myDB = db.DBConnection()
- num_air_by_date_results = myDB.select(
- "SELECT airdate, showid FROM tv_episodes ep, tv_shows show WHERE season != 0 AND ep.showid = show.indexer_id AND show.paused = 0 ANd ep.airdate > ? AND ep.showid = ? AND show.air_by_date = 1",
- [fromDate.toordinal(), indexer_id])
+ if bestQualities:
+ highestBestQuality = max(bestQualities)
+ else:
+ highestBestQuality = 0
- # break them apart into month/year strings
- air_by_date_segments = []
- for cur_result in num_air_by_date_results:
- cur_date = datetime.date.fromordinal(int(cur_result["airdate"]))
- cur_date_str = str(cur_date)[:7]
- cur_indexer_id = int(cur_result["showid"])
+ # if we need a better one then say yes
+ if (curStatus in (common.DOWNLOADED, common.SNATCHED, common.SNATCHED_PROPER,
+ common.SNATCHED_BEST) and curQuality < highestBestQuality) or curStatus == common.WANTED:
- cur_result_tuple = (cur_indexer_id, cur_date_str)
- if cur_result_tuple not in air_by_date_segments:
- air_by_date_segments.append(cur_result_tuple)
+ epObj = show.getEpisode(int(result["season"]), int(result["episode"]))
- return air_by_date_segments
+ if epObj.season in wanted:
+ wanted[epObj.season].append(epObj)
+ else:
+ wanted[epObj.season] = [epObj]
+ return wanted
def _set_lastBacklog(self, when):
diff --git a/sickbeard/search_queue.py b/sickbeard/search_queue.py
index 725e0cee..d3b65f25 100644
--- a/sickbeard/search_queue.py
+++ b/sickbeard/search_queue.py
@@ -42,16 +42,8 @@ class SearchQueue(generic_queue.GenericQueue):
def is_in_queue(self, show, segment):
queue = [x for x in self.queue.queue] + [self.currentItem]
for cur_item in queue:
- with search_queue_lock:
- if isinstance(cur_item, BacklogQueueItem) and cur_item.show == show and cur_item.segment == segment:
- return True
- return False
-
- def is_ep_in_queue(self, ep_obj):
- queue = [x for x in self.queue.queue] + [self.currentItem]
- for cur_item in queue:
- with search_queue_lock:
- if isinstance(cur_item, ManualSearchQueueItem) and cur_item.ep_obj == ep_obj:
+ if cur_item:
+ if cur_item.show == show and cur_item.segment == segment:
return True
return False
@@ -76,9 +68,9 @@ class SearchQueue(generic_queue.GenericQueue):
if isinstance(item, BacklogQueueItem) and not self.is_in_queue(item.show, item.segment):
generic_queue.GenericQueue.add_item(self, item)
- elif isinstance(item, ManualSearchQueueItem) and not self.is_ep_in_queue(item.ep_obj):
+ elif isinstance(item, ManualSearchQueueItem) and not self.is_in_queue(item.show, item.segment):
generic_queue.GenericQueue.add_item(self, item)
- elif isinstance(item, FailedQueueItem) and not self.is_in_queue(item.show, item.episodes):
+ elif isinstance(item, FailedQueueItem) and not self.is_in_queue(item.show, item.segment):
generic_queue.GenericQueue.add_item(self, item)
else:
logger.log(u"Not adding item, it's already in the queue", logger.DEBUG)
@@ -92,29 +84,29 @@ class SearchQueue(generic_queue.GenericQueue):
generic_queue.QueueItem.finish(item)
class ManualSearchQueueItem(generic_queue.QueueItem):
- def __init__(self, ep_obj):
+ def __init__(self, show, segment):
generic_queue.QueueItem.__init__(self, 'Manual Search', MANUAL_SEARCH)
self.priority = generic_queue.QueuePriorities.HIGH
- self.thread_name = 'MANUAL-' + str(ep_obj.show.indexerid) + '-'
+ self.thread_name = 'MANUAL-' + str(show.indexerid) + '-'
self.success = None
- self.show = ep_obj.show
- self.ep_obj = ep_obj
+ self.show = show
+ self.segment = segment
self.results = []
def execute(self):
generic_queue.QueueItem.execute(self)
try:
- logger.log("Beginning manual search for [" + self.ep_obj.prettyName() + "]")
- searchResult = search.searchProviders(self, self.show, self.ep_obj.season, [self.ep_obj],False,True)
+ logger.log("Beginning manual search for [" + self.segment.prettyName() + "]")
+ searchResult = search.searchProviders(self, self.show, self.segment.season, [self.segment],False,True)
if searchResult:
SearchQueue().snatch_item(searchResult)
else:
ui.notifications.message('No downloads were found',
- "Couldn't find a download for %s" % self.ep_obj.prettyName())
+ "Couldn't find a download for %s" % self.segment.prettyName())
- logger.log(u"Unable to find a download for " + self.ep_obj.prettyName())
+ logger.log(u"Unable to find a download for " + self.segment.prettyName())
except Exception:
logger.log(traceback.format_exc(), logger.DEBUG)
@@ -129,86 +121,41 @@ class BacklogQueueItem(generic_queue.QueueItem):
self.success = None
self.show = show
self.segment = segment
- self.wantedEpisodes = []
self.results = []
- logger.log(u"Seeing if we need any episodes from " + self.show.name + " season " + str(self.segment))
-
- myDB = db.DBConnection()
-
- # see if there is anything in this season worth searching for
- if not self.show.air_by_date:
- statusResults = myDB.select("SELECT status, episode FROM tv_episodes WHERE showid = ? AND season = ?",
- [self.show.indexerid, self.segment])
- else:
- season_year, season_month = map(int, self.segment.split('-'))
- min_date = datetime.date(season_year, season_month, 1)
-
- # 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)
- else:
- max_date = datetime.date(season_year, season_month + 1, 1) - datetime.timedelta(days=1)
-
- statusResults = myDB.select(
- "SELECT status, episode FROM tv_episodes WHERE showid = ? AND airdate >= ? AND airdate <= ?",
- [self.show.indexerid, min_date.toordinal(), max_date.toordinal()])
-
- anyQualities, bestQualities = common.Quality.splitQuality(self.show.quality) #@UnusedVariable
- self.wantedEpisodes = self._need_any_episodes(statusResults, bestQualities)
-
def execute(self):
generic_queue.QueueItem.execute(self)
- # check if we want to search for season packs instead of just season/episode
- seasonSearch = False
- seasonEps = self.show.getAllEpisodes(self.segment)
- if len(seasonEps) == len(self.wantedEpisodes):
- seasonSearch = True
+ for season in self.segment:
+ wantedEps = self.segment[season]
- try:
- logger.log("Beginning backlog search for episodes from [" + self.show.name + "] - Season[" + str(self.segment) + "]")
- searchResult = search.searchProviders(self, self.show, self.segment, self.wantedEpisodes, seasonSearch, False)
+ # check if we want to search for season packs instead of just season/episode
+ seasonSearch = False
+ seasonEps = self.show.getAllEpisodes(season)
+ if len(seasonEps) == len(wantedEps) and not sickbeard.PREFER_EPISODE_RELEASES:
+ seasonSearch = True
- if searchResult:
- SearchQueue().snatch_item(searchResult)
- else:
- logger.log(u"No needed episodes found during backlog search")
+ try:
+ logger.log("Beginning backlog search for episodes from [" + self.show.name + "] - Season[" + str(season) + "]")
+ searchResult = search.searchProviders(self, self.show, season, wantedEps, seasonSearch, False)
- except Exception:
- logger.log(traceback.format_exc(), logger.DEBUG)
+ if searchResult:
+ SearchQueue().snatch_item(searchResult)
+ else:
+ logger.log(u"No needed episodes found during backlog search")
+
+ except Exception:
+ logger.log(traceback.format_exc(), logger.DEBUG)
self.finish()
- def _need_any_episodes(self, statusResults, bestQualities):
- wantedEpisodes = []
-
- # check through the list of statuses to see if we want any
- for curStatusResult in statusResults:
- curCompositeStatus = int(curStatusResult["status"])
- curStatus, curQuality = common.Quality.splitCompositeStatus(curCompositeStatus)
- episode = int(curStatusResult["episode"])
-
- if bestQualities:
- highestBestQuality = max(bestQualities)
- else:
- highestBestQuality = 0
-
- # if we need a better one then say yes
- if (curStatus in (common.DOWNLOADED, common.SNATCHED, common.SNATCHED_PROPER,
- common.SNATCHED_BEST) and curQuality < highestBestQuality) or curStatus == common.WANTED:
- epObj = self.show.getEpisode(self.segment, episode)
- wantedEpisodes.append(epObj)
-
- return wantedEpisodes
-
class FailedQueueItem(generic_queue.QueueItem):
- def __init__(self, show, episodes):
+ def __init__(self, show, segment):
generic_queue.QueueItem.__init__(self, 'Retry', FAILED_SEARCH)
self.priority = generic_queue.QueuePriorities.HIGH
self.thread_name = 'RETRY-' + str(show.indexerid) + '-'
self.show = show
- self.episodes = episodes
+ self.segment = segment
self.success = None
self.results = []
@@ -216,7 +163,9 @@ class FailedQueueItem(generic_queue.QueueItem):
generic_queue.QueueItem.execute(self)
failed_episodes = []
- for i, epObj in enumerate(self.episodes):
+ for season in self.segment:
+ epObj = self.segment[season]
+
(release, provider) = failed_history.findRelease(epObj)
if release:
logger.log(u"Marking release as bad: " + release)
@@ -226,11 +175,11 @@ class FailedQueueItem(generic_queue.QueueItem):
failed_history.revertEpisode(epObj)
failed_episodes.append(epObj)
+ logger.log(
+ "Beginning failed download search for [" + epObj.prettyName() + "]")
+
if len(failed_episodes):
try:
- logger.log(
- "Beginning failed download search for episodes from Season [" + str(self.episodes[0].season) + "]")
-
searchResult = search.searchProviders(self, self.show, failed_episodes[0].season, failed_episodes, False, True)
if searchResult:
diff --git a/sickbeard/tv.py b/sickbeard/tv.py
index b823d46c..7498c6c2 100644
--- a/sickbeard/tv.py
+++ b/sickbeard/tv.py
@@ -140,20 +140,7 @@ class TVShow(object):
sql_selection = sql_selection + " FROM tv_episodes tve WHERE showid = " + str(self.indexerid)
if season is not None:
- if not self.air_by_date:
- sql_selection = sql_selection + " AND season = " + str(season)
- else:
- segment_year, segment_month = map(int, str(season).split('-'))
- min_date = datetime.date(segment_year, segment_month, 1)
-
- # it's easier to just hard code this than to worry about rolling the year over or making a month length map
- if segment_month == 12:
- max_date = datetime.date(segment_year, 12, 31)
- else:
- max_date = datetime.date(segment_year, segment_month + 1, 1) - datetime.timedelta(days=1)
-
- sql_selection = sql_selection + " AND airdate >= " + str(
- min_date.toordinal()) + " AND airdate <= " + str(max_date.toordinal())
+ sql_selection = sql_selection + " AND season = " + str(season)
if has_location:
sql_selection = sql_selection + " AND location != '' "
diff --git a/sickbeard/webserve.py b/sickbeard/webserve.py
index 02d0ab98..68711cd9 100644
--- a/sickbeard/webserve.py
+++ b/sickbeard/webserve.py
@@ -3227,8 +3227,7 @@ class Home:
else:
return _genericMessage("Error", errMsg)
- wanted_segments = []
- failed_segments = {}
+ segments = {}
if eps is not None:
@@ -3244,22 +3243,12 @@ class Home:
if epObj is None:
return _genericMessage("Error", "Episode couldn't be retrieved")
- if int(status) == WANTED:
+ if int(status) in [WANTED, FAILED]:
# figure out what episodes are wanted so we can backlog them
- if epObj.show.air_by_date or epObj.show.sports:
- segment = str(epObj.airdate)[:7]
+ if epObj in segments:
+ segments[epObj.season].append(epObj)
else:
- segment = epObj.season
-
- if segment not in wanted_segments:
- wanted_segments.append(segment)
-
- elif int(status) == FAILED:
- # figure out what episodes failed so we can retry them
- if epObj.season not in failed_segments:
- failed_segments[epObj.season] = []
- if epObj.episode not in failed_segments[epObj.season]:
- failed_segments[epObj.season].append(epObj.episode)
+ segments[epObj.season] = [epObj]
with epObj.lock:
# don't let them mess up UNAIRED episodes
@@ -3294,7 +3283,7 @@ class Home:
if int(status) == WANTED:
msg = "Backlog was automatically started for the following seasons of " + showObj.name + ":
"
- for cur_segment in wanted_segments:
+ for cur_segment in segments:
msg += "