From 6a8bef76c97a3f9d827a896197f845eb32a00329 Mon Sep 17 00:00:00 2001 From: echel0n Date: Fri, 2 May 2014 01:47:02 -0700 Subject: [PATCH] Re-code of post-processing, insures the Indexer ID is correct so that shows don't get added with the incorrect Indexer info also no more needing to lookup said info from the Indexers making API calls so overall speed has increased as well. Fixed issues with returning a show object when parsing release names into show names from our database. --- sickbeard/name_parser/parser.py | 12 +- sickbeard/postProcessor.py | 216 ++++++++++++++------------------ 2 files changed, 101 insertions(+), 127 deletions(-) diff --git a/sickbeard/name_parser/parser.py b/sickbeard/name_parser/parser.py index 405927cc..357dacae 100644 --- a/sickbeard/name_parser/parser.py +++ b/sickbeard/name_parser/parser.py @@ -106,7 +106,11 @@ class NameParser(object): result.series_name = match.group('series_name') if result.series_name: result.series_name = self.clean_series_name(result.series_name) - self.show = helpers.get_show_by_name(result.series_name) + name_list = sickbeard.show_name_helpers.sceneToNormalShowNames(result.series_name) + for name in name_list: + result.show = helpers.get_show_by_name(name) + if result.show: + break if 'season_num' in named_groups: tmp_season = int(match.group('season_num')) @@ -239,6 +243,8 @@ class NameParser(object): # parse the dirname for extra info if needed dir_name_result = self._parse_string(dir_name) + final_result.show = self._combine_results(file_name_result, dir_name_result, 'show') + # build the ParseResult object final_result.air_date = self._combine_results(file_name_result, dir_name_result, 'air_date') @@ -290,7 +296,6 @@ class ParseResult(object): show=None, ): - self.show = show self.original_name = original_name self.series_name = series_name @@ -310,11 +315,14 @@ class ParseResult(object): self.sports_event_date = sports_event_date self.which_regex = None + self.show = show def __eq__(self, other): if not other: return False + if self.show != other.show: + return False if self.series_name != other.series_name: return False if self.season_number != other.season_number: diff --git a/sickbeard/postProcessor.py b/sickbeard/postProcessor.py index 1d358bd4..b4dd21ca 100644 --- a/sickbeard/postProcessor.py +++ b/sickbeard/postProcessor.py @@ -93,8 +93,6 @@ class PostProcessor(object): self.is_priority = is_priority - self.indexer = None - self.good_results = {self.NZB_NAME: False, self.FOLDER_NAME: False, self.FILE_NAME: False} @@ -394,7 +392,7 @@ class PostProcessor(object): Returns a (indexer_id, season, []) tuple. The first two may be None if none were found. """ - to_return = (None, None, []) + to_return = (None, None, None, [], None) # if we don't have either of these then there's nothing to use to search the history for anyway if not self.nzb_name and not self.folder_name: @@ -414,30 +412,56 @@ class PostProcessor(object): # search the database for a possible match and return immediately if we find one for curName in names: - sql_results = myDB.select("SELECT * FROM history WHERE resource LIKE ?", [re.sub("[\.\-\ ]", "_", curName)]) + search_name = re.sub("[\.\-\ ]", "_", curName) + sql_results = myDB.select("SELECT * FROM history WHERE resource LIKE ?", [search_name]) if len(sql_results) == 0: continue indexer_id = int(sql_results[0]["showid"]) season = int(sql_results[0]["season"]) + quality = int(sql_results[0]["quality"]) + + if quality == common.Quality.UNKNOWN: + quality = None self.in_history = True - to_return = (indexer_id, season, []) + to_return = (indexer_id, None, season, [], quality) self._log("Found result in history: " + str(to_return), logger.DEBUG) - if curName == self.nzb_name: - self.good_results[self.NZB_NAME] = True - elif curName == self.folder_name: - self.good_results[self.FOLDER_NAME] = True - elif curName == self.file_name: - self.good_results[self.FILE_NAME] = True - return to_return self.in_history = False return to_return + def _finalize(self, parse_result): + self.release_group = parse_result.release_group + + # remember whether it's a proper + if parse_result.extra_info: + self.is_proper = re.search('(^|[\. _-])(proper|repack)([\. _-]|$)', parse_result.extra_info, + re.I) != None + + # if the result is complete then remember that for later + if parse_result.series_name and parse_result.season_number != None and parse_result.episode_numbers and parse_result.release_group: + test_name = ek.ek(os.path.basename, parse_result.original_name) + if test_name == self.nzb_name: + self.good_results[self.NZB_NAME] = True + elif test_name == self.folder_name: + self.good_results[self.FOLDER_NAME] = True + elif test_name == self.file_name: + self.good_results[self.FILE_NAME] = True + else: + logger.log(u"Nothing was good, found " + repr(test_name) + " and wanted either " + repr( + self.nzb_name) + ", " + repr(self.folder_name) + ", or " + repr(self.file_name)) + else: + logger.log(u"Parse result not sufficient(all following have to be set). Will not save release name", + logger.DEBUG) + logger.log("Parse result(series_name): " + str(parse_result.series_name), logger.DEBUG) + logger.log("Parse result(season_number): " + str(parse_result.season_number), logger.DEBUG) + logger.log("Parse result(episode_numbers): " + str(parse_result.episode_numbers), logger.DEBUG) + logger.log("Parse result(release_group): " + str(parse_result.release_group), logger.DEBUG) + def _analyze_name(self, name, file=True): """ Takes a name and tries to figure out a show, season, and episode from it. @@ -450,7 +474,10 @@ class PostProcessor(object): logger.log(u"Analyzing name " + repr(name)) - to_return = (None, None, []) + indexer_id = None + indexer = None + + to_return = (indexer_id, indexer, None, [], None) if not name: return to_return @@ -471,50 +498,13 @@ class PostProcessor(object): season = parse_result.season_number episodes = parse_result.episode_numbers - to_return = (None, season, episodes) + if parse_result.show: + indexer_id = parse_result.show.indexerid + indexer = parse_result.show.indexer - # do a scene reverse-lookup to get a list of all possible names - name_list = show_name_helpers.sceneToNormalShowNames(parse_result.series_name) + to_return = (indexer_id, indexer, season, episodes, None) - if not name_list: - return (None, season, episodes) - - def _finalize(parse_result): - self.release_group = parse_result.release_group - - # remember whether it's a proper - if parse_result.extra_info: - self.is_proper = re.search('(^|[\. _-])(proper|repack)([\. _-]|$)', parse_result.extra_info, - re.I) != None - - # if the result is complete then remember that for later - if parse_result.series_name and parse_result.season_number != None and parse_result.episode_numbers and parse_result.release_group: - test_name = os.path.basename(name) - if test_name == self.nzb_name: - self.good_results[self.NZB_NAME] = True - elif test_name == self.folder_name: - self.good_results[self.FOLDER_NAME] = True - elif test_name == self.file_name: - self.good_results[self.FILE_NAME] = True - else: - logger.log(u"Nothing was good, found " + repr(test_name) + " and wanted either " + repr( - self.nzb_name) + ", " + repr(self.folder_name) + ", or " + repr(self.file_name)) - else: - logger.log(u"Parse result not sufficient(all following have to be set). Will not save release name", - logger.DEBUG) - logger.log("Parse result(series_name): " + str(parse_result.series_name), logger.DEBUG) - logger.log("Parse result(season_number): " + str(parse_result.season_number), logger.DEBUG) - logger.log("Parse result(episode_numbers): " + str(parse_result.episode_numbers), logger.DEBUG) - logger.log("Parse result(release_group): " + str(parse_result.release_group), logger.DEBUG) - - # for each possible interpretation of that scene name - for cur_name in name_list: - showObj = helpers.get_show_by_name(cur_name, checkIndexers=True) - if showObj: - _finalize(parse_result) - return (showObj.indexerid, season, episodes) - - _finalize(parse_result) + self._finalize(parse_result) return to_return def _find_info(self): @@ -522,7 +512,7 @@ class PostProcessor(object): For a given file try to find the showid, season, and episode. """ - indexer_id = season = None + indexer_id = indexer = season = quality = None episodes = [] # try to look up the nzb in history @@ -549,89 +539,61 @@ class PostProcessor(object): for cur_attempt in attempt_list: try: - (cur_indexer_id, cur_season, cur_episodes) = cur_attempt() + (cur_indexer_id, cur_indexer, cur_season, cur_episodes, cur_quality) = cur_attempt() except InvalidNameException, e: logger.log(u"Unable to parse, skipping: " + ex(e), logger.DEBUG) continue - # if we already did a successful history lookup then keep that indexer_id value - if cur_indexer_id and not (self.in_history and indexer_id): + # check and confirm first that the indexer_id exists in our shows list before setting it + if cur_indexer_id != indexer_id and cur_indexer: indexer_id = cur_indexer_id + indexer = cur_indexer + + if cur_quality and not (self.in_history and quality): + quality = cur_quality + if cur_season != None: season = cur_season if cur_episodes: episodes = cur_episodes - # for air-by-date shows we need to look up the season/episode from tvdb - if season == -1 and indexer_id and episodes: - self._log( - u"Looks like this is an air-by-date or sports show, attempting to convert the date to season/episode", - logger.DEBUG) + # for air-by-date shows we need to look up the season/episode from database + if season == -1 and indexer_id and indexer and episodes: + self._log(u"Looks like this is an air-by-date or sports show, attempting to convert the date to season/episode", + logger.DEBUG) + airdate = episodes[0].toordinal() + myDB = db.DBConnection() + sql_result = myDB.select("SELECT season, episode FROM tv_episodes WHERE showid = ? and indexer = ? and airdate = ?", + [indexer_id, indexer, airdate]) - # try to get language set for this show - indexer_lang = None - try: - showObj = helpers.findCertainShow(sickbeard.showList, indexer_id) - if showObj: - indexer_lang = showObj.lang - except exceptions.MultipleShowObjectsException: + if sql_result: + season = int(sql_result[0][0]) + episodes = [int(sql_result[0][1])] + else: + self._log(u"Unable to find episode with date " + str(episodes[0]) + u" for show " + str( + indexer_id) + u", skipping", logger.DEBUG) + # we don't want to leave dates in the episode list if we couldn't convert them to real episode numbers + episodes = [] continue - for indexer in sickbeard.indexerApi().indexers: - self.indexer = int(indexer) - self._log( - u"Searching " + sickbeard.indexerApi(self.indexer).name + ", trying to auto-detect Indexer for " - "show") - try: - lINDEXER_API_PARMS = sickbeard.indexerApi(self.indexer).api_params.copy() - if indexer_lang and not indexer_lang == 'en': - lINDEXER_API_PARMS = {'language': indexer_lang} - - t = sickbeard.indexerApi(self.indexer).indexer(**lINDEXER_API_PARMS) - - epObj = t[indexer_id].airedOn(episodes[0])[0] - - season = int(epObj["seasonnumber"]) - episodes = [int(epObj["episodenumber"])] - - self._log(u"Got season " + str(season) + " episodes " + str(episodes), logger.DEBUG) - except (KeyError, sickbeard.indexer_episodenotfound), e: - self._log(u"Unable to find episode with date " + str(episodes[0]) + u" for show " + str( - indexer_id) + u", skipping", logger.DEBUG) - # we don't want to leave dates in the episode list if we couldn't convert them to real episode numbers - continue - except sickbeard.indexer_error, e: - logger.log(u"Unable to contact " + sickbeard.indexerApi(self.indexer).name + ": " + ex(e), - logger.WARNING) - continue - - # try to find the file info - if indexer_id and season and episodes: - break - - episodes = [] - self._log( - u"Can't find thhe show on " + sickbeard.indexerApi( - self.indexer).name + ", trying next ""indexer", logger.WARNING) - # if there's no season then we can hopefully just use 1 automatically - elif season == None and indexer_id: + elif season == None and indexer_id and indexer: myDB = db.DBConnection() numseasonsSQlResult = myDB.select( - "SELECT COUNT(DISTINCT season) as numseasons FROM tv_episodes WHERE showid = ? and season != 0", - [indexer_id]) + "SELECT COUNT(DISTINCT season) as numseasons FROM tv_episodes WHERE showid = ? and indexer = ? and season != 0", + [indexer_id, indexer]) if int(numseasonsSQlResult[0][0]) == 1 and season == None: self._log( u"Don't have a season number, but this show appears to only have 1 season, setting seasonnumber to 1...", logger.DEBUG) season = 1 - if indexer_id and season and episodes: - break + if indexer_id and indexer and season and episodes: + return (indexer_id, indexer, season, episodes, quality) + + return (indexer_id, indexer, season, episodes, quality) - return (indexer_id, season, episodes) - - def _get_ep_obj(self, indexer_id, season, episodes): + def _get_ep_obj(self, indexer_id, indexer, season, episodes): """ Retrieve the TVEpisode object requested. @@ -643,9 +605,7 @@ class PostProcessor(object): be instantiated and returned. If the episode can't be found then None will be returned. """ - show_obj = None - - self._log(u"Loading show object for indexer_id " + str(indexer_id), logger.DEBUG) + self._log(u"Loading show object with Indexer ID:[" + str(indexer_id) + "] for Indexer:[" + str(sickbeard.indexerApi(indexer).name) + "]", logger.DEBUG) # find the show in the showlist try: show_obj = helpers.findCertainShow(sickbeard.showList, indexer_id) @@ -810,25 +770,31 @@ class PostProcessor(object): if ek.ek(os.path.isdir, self.file_path): self._log(u"File " + self.file_path + " seems to be a directory") return False + for ignore_file in self.IGNORED_FILESTRINGS: if ignore_file in self.file_path: self._log(u"File " + self.file_path + " is ignored type, skipping") return False + # reset per-file stuff self.in_history = False # try to find the file info - (indexer_id, season, episodes) = self._find_info() - if not (indexer_id and season and len(episodes)): - self._log(u"Unable to find enough info to post-process this show, skipping", - logger.WARNING) + (indexer_id, indexer, season, episodes, quality) = self._find_info() + if not indexer_id or not indexer or season == None or not episodes: + self._log(u"Not enough information to determine what episode this is", logger.DEBUG) + self._log(u"Quitting post-processing", logger.DEBUG) return False # retrieve/create the corresponding TVEpisode objects - ep_obj = self._get_ep_obj(indexer_id, season, episodes) + ep_obj = self._get_ep_obj(indexer_id, indexer, season, episodes) # get the quality of the episode we're processing - new_ep_quality = self._get_quality(ep_obj) + if quality: + self._log(u"Snatch history had a quality in it, using that: " + common.Quality.qualityStrings[quality], logger.DEBUG) + new_ep_quality = quality + else: + new_ep_quality = self._get_quality(ep_obj) logger.log(u"Quality of the episode we're processing: " + str(new_ep_quality), logger.DEBUG)