diff --git a/sickbeard/dailysearcher.py b/sickbeard/dailysearcher.py index 6e53346d..900d0515 100644 --- a/sickbeard/dailysearcher.py +++ b/sickbeard/dailysearcher.py @@ -87,14 +87,16 @@ class DailySearcher(): def searchForNeededEpisodes(self): - logger.log(u"Searching ESS Cache for any needed new episodes") + logger.log(u"Searching RSS Cache for any new releases we may want to snatch ...") foundResults = {} didSearch = False # ask all providers for any episodes it finds + threadName = threading.currentThread().name for curProvider in [x for x in sickbeard.providers.sortedProviderList() if x.isActive()]: + threading.currentThread().name = threadName + ":[" + curProvider.name + "]" try: curFoundResults = curProvider.searchRSS() diff --git a/sickbeard/providers/generic.py b/sickbeard/providers/generic.py index ec71cd8e..93145947 100644 --- a/sickbeard/providers/generic.py +++ b/sickbeard/providers/generic.py @@ -53,6 +53,8 @@ class GenericProvider: self.show = None self.supportsBacklog = False + self.search_mode = None + self.search_fallback = False self.cache = tvcache.TVCache(self) @@ -234,11 +236,13 @@ class GenericProvider: searched_scene_season = None for epObj in episodes: - scene_season = epObj.scene_season if seasonSearch and searched_scene_season: - if scene_season == searched_scene_season: + if searched_scene_season == epObj.scene_season: continue + # mark season searched for season pack searches so we can skip later on + searched_scene_season = epObj.scene_season + if not epObj.show.air_by_date: if epObj.scene_season == 0 or epObj.scene_episode == 0: logger.log( @@ -265,9 +269,6 @@ class GenericProvider: itemList = [i for n, i in enumerate(itemList) if i not in itemList[n + 1:]] searchItems[epObj] = itemList - # mark season searched so we can skip anymore searches of this season if this is a season pack search - searched_scene_season = scene_season - # if we have cached results return them. if len(results): return results @@ -288,6 +289,12 @@ class GenericProvider: continue if not (self.show.air_by_date or self.show.sports): + if seasonSearch and len(parse_result.episode_numbers): + logger.log( + u"This is supposed to be a season pack search but the result " + title + " is not a valid season pack, skipping it", + logger.DEBUG) + continue + if not len(parse_result.episode_numbers) and ( parse_result.season_number != None and parse_result.season_number != ep_obj.season) or ( parse_result.season_number == None and ep_obj.season != 1): diff --git a/sickbeard/rssupdater.py b/sickbeard/rssupdater.py index 9b807307..d9384f96 100644 --- a/sickbeard/rssupdater.py +++ b/sickbeard/rssupdater.py @@ -32,6 +32,7 @@ class RSSUpdater(): def run(self): self.amActive = True + threadName = threading.currentThread().name # remove names from cache that link back to active shows that we watch sickbeard.name_cache.syncNameCache() @@ -39,7 +40,8 @@ class RSSUpdater(): # update RSS cache providers = [x for x in sickbeard.providers.sortedProviderList() if x.isActive()] for provider in providers: - logger.log(u"Updating RSS cache for provider [" + provider.name + "]") + threading.currentThread().name = threadName + ":[" + provider.name + "]" + logger.log(u"Updating RSS cache ...") provider.cache.updateCache() self.amActive = False \ No newline at end of file diff --git a/sickbeard/search.py b/sickbeard/search.py index 0a2e1608..6a6ea266 100644 --- a/sickbeard/search.py +++ b/sickbeard/search.py @@ -317,10 +317,12 @@ def filterSearchResults(show, results): def searchProviders(queueItem, show, season, episodes, seasonSearch=False, manualSearch=False): + threadName = threading.currentThread().name + if seasonSearch: - logger.log(u"Searching for " + show.name + " season " + str(season) + " pack") + logger.log(u"Searching for " + show.name + " Season " + str(season) + " pack") else: - logger.log(u"Searching for episodes we need from " + show.name + " season " + str(season)) + logger.log(u"Searching for episodes we need from " + show.name + " Season " + str(season)) providers = [x for x in sickbeard.providers.sortedProviderList() if x.isActive()] @@ -329,231 +331,236 @@ def searchProviders(queueItem, show, season, episodes, seasonSearch=False, manua logger.ERROR) return queueItem - foundResults = {} - for providerNum, provider in enumerate(providers): - foundResults.setdefault(provider.name, {}) + def doSearch(): + foundResults = {} + for providerNum, provider in enumerate(providers): + foundResults.setdefault(provider.name, {}) + threading.currentThread().name = threadName + ":[" + provider.name + "]" - try: - curResults = provider.findSearchResults(show, season, episodes, seasonSearch, manualSearch) - except exceptions.AuthException, e: - logger.log(u"Authentication error: " + ex(e), logger.ERROR) - continue - except Exception, e: - logger.log(u"Error while searching " + provider.name + ", skipping: " + ex(e), logger.ERROR) - logger.log(traceback.format_exc(), logger.DEBUG) - continue + try: + curResults = provider.findSearchResults(show, season, episodes, seasonSearch, manualSearch) + except exceptions.AuthException, e: + logger.log(u"Authentication error: " + ex(e), logger.ERROR) + continue + except Exception, e: + logger.log(u"Error while searching " + provider.name + ", skipping: " + ex(e), logger.ERROR) + logger.log(traceback.format_exc(), logger.DEBUG) + continue - if not len(curResults): - continue + if not len(curResults): + continue - foundResults[provider.name] = filterSearchResults(show, curResults) - if not len(foundResults[provider.name]): - continue + foundResults[provider.name] = filterSearchResults(show, curResults) + if not len(foundResults[provider.name]): + continue - anyQualities, bestQualities = Quality.splitQuality(show.quality) + anyQualities, bestQualities = Quality.splitQuality(show.quality) - # pick the best season NZB - bestSeasonNZB = None - if SEASON_RESULT in foundResults[provider.name]: - bestSeasonNZB = pickBestResult(foundResults[provider.name][SEASON_RESULT], show, - anyQualities + bestQualities) + # pick the best season NZB + bestSeasonNZB = None + if SEASON_RESULT in foundResults[provider.name]: + bestSeasonNZB = pickBestResult(foundResults[provider.name][SEASON_RESULT], show, + anyQualities + bestQualities) - highest_quality_overall = 0 - for cur_episode in foundResults[provider.name]: - for cur_result in foundResults[provider.name][cur_episode]: - if cur_result.quality != Quality.UNKNOWN and cur_result.quality > highest_quality_overall: - highest_quality_overall = cur_result.quality - logger.log(u"The highest quality of any match is " + Quality.qualityStrings[highest_quality_overall], - logger.DEBUG) + highest_quality_overall = 0 + for cur_episode in foundResults[provider.name]: + for cur_result in foundResults[provider.name][cur_episode]: + if cur_result.quality != Quality.UNKNOWN and cur_result.quality > highest_quality_overall: + highest_quality_overall = cur_result.quality + logger.log(u"The highest quality of any match is " + Quality.qualityStrings[highest_quality_overall], + logger.DEBUG) - # see if every episode is wanted - if bestSeasonNZB: + # see if every episode is wanted + if bestSeasonNZB: - # get the quality of the season nzb - seasonQual = Quality.sceneQuality(bestSeasonNZB.name) - seasonQual = bestSeasonNZB.quality - logger.log( - u"The quality of the season " + bestSeasonNZB.provider.providerType + " is " + Quality.qualityStrings[ - seasonQual], logger.DEBUG) - - myDB = db.DBConnection() - allEps = [int(x["episode"]) for x in - myDB.select("SELECT episode FROM tv_episodes WHERE showid = ? AND season = ?", - [show.indexerid, season])] - logger.log(u"Episode list: " + str(allEps), logger.DEBUG) - - allWanted = True - anyWanted = False - for curEpNum in allEps: - if not show.wantEpisode(season, curEpNum, seasonQual): - allWanted = False - else: - anyWanted = True - - # 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: + # get the quality of the season nzb + seasonQual = Quality.sceneQuality(bestSeasonNZB.name) + seasonQual = bestSeasonNZB.quality logger.log( - u"Every ep in this season is needed, downloading the whole " + bestSeasonNZB.provider.providerType + " " + bestSeasonNZB.name) - epObjs = [] + u"The quality of the season " + bestSeasonNZB.provider.providerType + " is " + Quality.qualityStrings[ + seasonQual], logger.DEBUG) + + myDB = db.DBConnection() + allEps = [int(x["episode"]) for x in + myDB.select("SELECT episode FROM tv_episodes WHERE showid = ? AND season = ?", + [show.indexerid, season])] + logger.log(u"Episode list: " + str(allEps), logger.DEBUG) + + allWanted = True + anyWanted = False for curEpNum in allEps: - epObjs.append(show.getEpisode(season, curEpNum)) - bestSeasonNZB.episodes = epObjs - queueItem.results = [bestSeasonNZB] - return queueItem + if not show.wantEpisode(season, curEpNum, seasonQual): + allWanted = False + else: + anyWanted = True - elif not anyWanted: - logger.log( - u"No eps from this season are wanted at this quality, ignoring the result of " + bestSeasonNZB.name, - logger.DEBUG) - - else: - - if bestSeasonNZB.provider.providerType == GenericProvider.NZB: - logger.log(u"Breaking apart the NZB and adding the individual ones to our results", logger.DEBUG) - - # if not, break it apart and add them as the lowest priority results - individualResults = nzbSplitter.splitResult(bestSeasonNZB) - - individualResults = filter( - lambda x: show_name_helpers.filterBadReleases(x.name) and show_name_helpers.isGoodResult(x.name, - show), - individualResults) - - for curResult in individualResults: - if len(curResult.episodes) == 1: - epNum = curResult.episodes[0].episode - elif len(curResult.episodes) > 1: - epNum = MULTI_EP_RESULT - - if epNum in foundResults[provider.name]: - foundResults[provider.name][epNum].append(curResult) - else: - foundResults[provider.name][epNum] = [curResult] - - # If this is a torrent all we can do is leech the entire torrent, user will have to select which eps not do download in his torrent client - else: - - # Season result from Torrent Provider must be a full-season torrent, creating multi-ep result for it. + # 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: logger.log( - u"Adding multi-ep result for full-season torrent. Set the episodes you don't want to 'don't download' in your torrent client if desired!") + u"Every ep in this season is needed, downloading the whole " + bestSeasonNZB.provider.providerType + " " + bestSeasonNZB.name) epObjs = [] for curEpNum in allEps: epObjs.append(show.getEpisode(season, curEpNum)) bestSeasonNZB.episodes = epObjs + queueItem.results = [bestSeasonNZB] + return queueItem - epNum = MULTI_EP_RESULT - if epNum in foundResults[provider.name]: - foundResults[provider.name][epNum].append(bestSeasonNZB) - else: - foundResults[provider.name][epNum] = [bestSeasonNZB] - - # go through multi-ep results and see if we really want them or not, get rid of the rest - multiResults = {} - if MULTI_EP_RESULT in foundResults[provider.name]: - for multiResult in foundResults[provider.name][MULTI_EP_RESULT]: - - logger.log(u"Seeing if we want to bother with multi-episode result " + multiResult.name, logger.DEBUG) - - if sickbeard.USE_FAILED_DOWNLOADS and failed_history.hasFailed(multiResult.name, multiResult.size, - multiResult.provider.name): - logger.log(multiResult.name + u" has previously failed, rejecting this multi-ep result") - continue - - # see how many of the eps that this result covers aren't covered by single results - neededEps = [] - notNeededEps = [] - for epObj in multiResult.episodes: - epNum = epObj.episode - # if we have results for the episode - if epNum in foundResults[provider.name] and len(foundResults[provider.name][epNum]) > 0: - # but the multi-ep is worse quality, we don't want it - # TODO: wtf is this False for - #if False and multiResult.quality <= pickBestResult(foundResults[epNum]): - # notNeededEps.append(epNum) - #else: - neededEps.append(epNum) - else: - neededEps.append(epNum) - - logger.log( - u"Single-ep check result is neededEps: " + str(neededEps) + ", notNeededEps: " + str(notNeededEps), - logger.DEBUG) - - if not neededEps: - logger.log(u"All of these episodes were covered by single nzbs, ignoring this multi-ep result", - logger.DEBUG) - continue - - # check if these eps are already covered by another multi-result - multiNeededEps = [] - multiNotNeededEps = [] - for epObj in multiResult.episodes: - epNum = epObj.episode - if epNum in multiResults: - multiNotNeededEps.append(epNum) - else: - multiNeededEps.append(epNum) - - logger.log( - u"Multi-ep check result is multiNeededEps: " + str(multiNeededEps) + ", multiNotNeededEps: " + str( - multiNotNeededEps), logger.DEBUG) - - if not multiNeededEps: + elif not anyWanted: logger.log( - u"All of these episodes were covered by another multi-episode nzbs, ignoring this multi-ep result", + u"No eps from this season are wanted at this quality, ignoring the result of " + bestSeasonNZB.name, logger.DEBUG) + + else: + + if bestSeasonNZB.provider.providerType == GenericProvider.NZB: + logger.log(u"Breaking apart the NZB and adding the individual ones to our results", logger.DEBUG) + + # if not, break it apart and add them as the lowest priority results + individualResults = nzbSplitter.splitResult(bestSeasonNZB) + + individualResults = filter( + lambda x: show_name_helpers.filterBadReleases(x.name) and show_name_helpers.isGoodResult(x.name, + show), + individualResults) + + for curResult in individualResults: + if len(curResult.episodes) == 1: + epNum = curResult.episodes[0].episode + elif len(curResult.episodes) > 1: + epNum = MULTI_EP_RESULT + + if epNum in foundResults[provider.name]: + foundResults[provider.name][epNum].append(curResult) + else: + foundResults[provider.name][epNum] = [curResult] + + # If this is a torrent all we can do is leech the entire torrent, user will have to select which eps not do download in his torrent client + else: + + # Season result from Torrent Provider must be a full-season torrent, creating multi-ep result for it. + logger.log( + u"Adding multi-ep result for full-season torrent. Set the episodes you don't want to 'don't download' in your torrent client if desired!") + epObjs = [] + for curEpNum in allEps: + epObjs.append(show.getEpisode(season, curEpNum)) + bestSeasonNZB.episodes = epObjs + + epNum = MULTI_EP_RESULT + if epNum in foundResults[provider.name]: + foundResults[provider.name][epNum].append(bestSeasonNZB) + else: + foundResults[provider.name][epNum] = [bestSeasonNZB] + + # go through multi-ep results and see if we really want them or not, get rid of the rest + multiResults = {} + if MULTI_EP_RESULT in foundResults[provider.name]: + for multiResult in foundResults[provider.name][MULTI_EP_RESULT]: + + logger.log(u"Seeing if we want to bother with multi-episode result " + multiResult.name, logger.DEBUG) + + if sickbeard.USE_FAILED_DOWNLOADS and failed_history.hasFailed(multiResult.name, multiResult.size, + multiResult.provider.name): + logger.log(multiResult.name + u" has previously failed, rejecting this multi-ep result") + continue + + # see how many of the eps that this result covers aren't covered by single results + neededEps = [] + notNeededEps = [] + for epObj in multiResult.episodes: + epNum = epObj.episode + # if we have results for the episode + if epNum in foundResults[provider.name] and len(foundResults[provider.name][epNum]) > 0: + # but the multi-ep is worse quality, we don't want it + # TODO: wtf is this False for + #if False and multiResult.quality <= pickBestResult(foundResults[epNum]): + # notNeededEps.append(epNum) + #else: + neededEps.append(epNum) + else: + neededEps.append(epNum) + + logger.log( + u"Single-ep check result is neededEps: " + str(neededEps) + ", notNeededEps: " + str(notNeededEps), + logger.DEBUG) + + if not neededEps: + logger.log(u"All of these episodes were covered by single nzbs, ignoring this multi-ep result", + logger.DEBUG) + continue + + # check if these eps are already covered by another multi-result + multiNeededEps = [] + multiNotNeededEps = [] + for epObj in multiResult.episodes: + epNum = epObj.episode + if epNum in multiResults: + multiNotNeededEps.append(epNum) + else: + multiNeededEps.append(epNum) + + logger.log( + u"Multi-ep check result is multiNeededEps: " + str(multiNeededEps) + ", multiNotNeededEps: " + str( + multiNotNeededEps), logger.DEBUG) + + if not multiNeededEps: + logger.log( + u"All of these episodes were covered by another multi-episode nzbs, ignoring this multi-ep result", + logger.DEBUG) + continue + + # if we're keeping this multi-result then remember it + for epObj in multiResult.episodes: + multiResults[epObj.episode] = multiResult + + # don't bother with the single result if we're going to get it with a multi result + for epObj in multiResult.episodes: + epNum = epObj.episode + if epNum in foundResults[provider.name]: + logger.log( + u"A needed multi-episode result overlaps with a single-episode result for ep #" + str( + epNum) + ", removing the single-episode results from the list", logger.DEBUG) + del foundResults[provider.name][epNum] + + # of all the single ep results narrow it down to the best one for each episode + queueItem.results += set(multiResults.values()) + for curEp in foundResults[provider.name]: + if curEp in (MULTI_EP_RESULT, SEASON_RESULT): continue - # if we're keeping this multi-result then remember it - for epObj in multiResult.episodes: - multiResults[epObj.episode] = multiResult + if len(foundResults[provider.name][curEp]) == 0: + continue - # don't bother with the single result if we're going to get it with a multi result - for epObj in multiResult.episodes: - epNum = epObj.episode - if epNum in foundResults[provider.name]: - logger.log( - u"A needed multi-episode result overlaps with a single-episode result for ep #" + str( - epNum) + ", removing the single-episode results from the list", logger.DEBUG) - del foundResults[provider.name][epNum] + bestResult = pickBestResult(foundResults[provider.name][curEp], show) - # of all the single ep results narrow it down to the best one for each episode - queueItem.results += set(multiResults.values()) - for curEp in foundResults[provider.name]: - if curEp in (MULTI_EP_RESULT, SEASON_RESULT): + # if all results were rejected move on to the next episode + if not bestResult: + continue + + # add result if its not a duplicate and + found = False + for i, result in enumerate(queueItem.results): + for bestResultEp in bestResult.episodes: + if bestResultEp in result.episodes: + if result.quality < bestResult.quality: + queueItem.results.pop(i) + else: + found = True + if not found: + queueItem.results += [bestResult] + + + # check that we got all the episodes we wanted first before doing a match and snatch + wantedEpCount = 0 + for wantedEp in episodes: + for result in queueItem.results: + if wantedEp in result.episodes and isFinalResult(result): + wantedEpCount += 1 + + # make sure we search every provider for results unless we found everything we wanted + if providerNum != len(providers) and wantedEpCount != len(episodes): continue - if len(foundResults[provider.name][curEp]) == 0: - continue + return queueItem - bestResult = pickBestResult(foundResults[provider.name][curEp], show) - - # if all results were rejected move on to the next episode - if not bestResult: - continue - - # add result if its not a duplicate and - found = False - for i, result in enumerate(queueItem.results): - for bestResultEp in bestResult.episodes: - if bestResultEp in result.episodes: - if result.quality < bestResult.quality: - queueItem.results.pop(i) - else: - found = True - if not found: - queueItem.results += [bestResult] - - - # check that we got all the episodes we wanted first before doing a match and snatch - wantedEpCount = 0 - for wantedEp in episodes: - for result in queueItem.results: - if wantedEp in result.episodes and isFinalResult(result): - wantedEpCount += 1 - - # make sure we search every provider for results unless we found everything we wanted - if providerNum != len(providers) and wantedEpCount != len(episodes): - continue - - return queueItem + results = doSearch() + return results \ No newline at end of file diff --git a/sickbeard/search_queue.py b/sickbeard/search_queue.py index 3286d7ee..a6a8fa24 100644 --- a/sickbeard/search_queue.py +++ b/sickbeard/search_queue.py @@ -138,7 +138,7 @@ class BacklogQueueItem(generic_queue.QueueItem): seasonSearch = True try: - logger.log("Beginning backlog search for episodes from [" + self.show.name + "] - Season[" + str(season) + "]") + logger.log("Beginning backlog search for [" + self.show.name + "]") searchResult = search.searchProviders(self, self.show, season, wantedEps, seasonSearch, False) if searchResult: