def get_indexer_absolute_numbering(series_obj, scene_episode, fallback_to_xem=True, scene_season=None): """ Returns a tuple, (season, episode, absolute_number) with the TVDB absolute numbering for (scene_episode) (this works like the reverse of get_absolute_numbering) """ if scene_season is not None: # Get the real absolute number real_episode = get_absolute_number_from_season_and_episode( series_obj, scene_season, scene_episode) scene_episode = real_episode or scene_episode main_db_con = db.DBConnection() rows = main_db_con.select( 'SELECT absolute_number FROM scene_numbering ' 'WHERE indexer = ? and indexer_id = ? and scene_absolute_number = ?', [series_obj.indexer, series_obj.series_id, scene_episode]) if rows: return int(rows[0]['absolute_number']) if fallback_to_xem: a = get_indexer_absolute_numbering_for_xem(series_obj, scene_episode) return a or scene_episode return scene_episode
def _parse_anime(result): """ Parse anime season episode results. Translate scene episode and season numbering to indexer numbering, using anime scen episode/season translation tables to indexer episode/season. :param result: Guessit parse result object. :return: tuple of found indexer episode numbers and indexer season numbers """ log.debug('Series {name} is anime', {'name': result.series.name}) new_episode_numbers = [] new_season_numbers = [] new_absolute_numbers = [] # Try to translate the scene series name to a scene number. # For example Jojo's bizarre Adventure - Diamond is unbreakable, will use xem, to translate the # "diamond is unbreakable" exception back to season 4 of it's "master" table. This will be used later # to translate it to an absolute number, which in turn can be translated to an indexer SxEx. # For example Diamond is unbreakable - 26 -> Season 4 -> Absolute number 100 -> tvdb S03E26 season_exception = None if result.season_number is None: season_exception = scene_exceptions.get_season_from_name(result.series, result.series_name) if result.ab_episode_numbers: for absolute_episode in result.ab_episode_numbers: a = absolute_episode # Don't assume that scene_exceptions season is the same as indexer season. # E.g.: [HorribleSubs] Cardcaptor Sakura Clear Card - 08 [720p].mkv thetvdb s04, thexem s02 if season_exception is not None or result.series.is_scene: # Get absolute number from custom numbering (1), XEM (2) or indexer (3) a = scene_numbering.get_indexer_absolute_numbering( result.series, a, fallback_to_xem=True, scene_season=season_exception ) new_absolute_numbers.append(a) # Translate the absolute episode number, back to the indexers season and episode. (season, episodes) = helpers.get_all_episodes_from_absolute_number(result.series, [a]) if season and episodes: new_episode_numbers.extend(episodes) new_season_numbers.append(season) if season_exception is not None: log.debug( 'Detected a season scene exception [{series_name} -> {scene_season}] without a ' 'season number in the title, ' 'translating the episode #{abs} to indexer #{indexer_absolute}: {ep}', {'series_name': result.series_name, 'scene_season': season_exception, 'abs': absolute_episode, 'indexer_absolute': a, 'ep': episode_num(season, episodes[0])} ) elif result.series.is_scene: log.debug( 'Scene numbering enabled anime series {name} using indexer numbering #{absolute}: {ep}', {'name': result.series.name, 'season': season, 'absolute': a, 'ep': episode_num(season, episodes[0])} ) else: log.debug( 'Anime series {name} using indexer numbering #{absolute}: {ep}', {'name': result.series.name, 'season': season, 'absolute': a, 'ep': episode_num(season, episodes[0])} ) # It's possible that we map a parsed result to an anime series, # but the result is not detected/parsed as an anime. In that case, we're using the result.episode_numbers. else: for episode_number in result.episode_numbers: season = result.season_number episode = episode_number if result.series.is_scene: (season, episode) = scene_numbering.get_indexer_numbering( result.series, result.season_number, episode_number ) log.debug( 'Scene numbering enabled anime {name} using indexer numbering: {ep}', {'name': result.series.name, 'ep': episode_num(season, episode)} ) a = helpers.get_absolute_number_from_season_and_episode(result.series, season, episode) if a: new_absolute_numbers.append(a) log.debug( 'Anime series {name} using using indexer numbering #{absolute}: {ep}', {'name': result.series.name, 'absolute': a, 'ep': episode_num(season, episode)} ) new_episode_numbers.append(episode) new_season_numbers.append(season) return new_episode_numbers, new_season_numbers, new_absolute_numbers
def _parse_anime(result): """ Parse anime season episode results. Translate scene episode and season numbering to indexer numbering, using anime scen episode/season translation tables to indexer episode/season. :param result: Guessit parse result object. :return: tuple of found indexer episode numbers and indexer season numbers """ log.debug('Scene numbering enabled series {name} is anime', {'name': result.series.name}) new_episode_numbers = [] new_season_numbers = [] new_absolute_numbers = [] # Try to translate the scene series name to a scene number. # For example Jojo's bizarre Adventure - Diamond is unbreakable, will use xem, to translate the # "diamond is unbreakable" exception back to season 4 of it's "master" table. This will be used later # to translate it to an absolute number, which in turn can be translated to an indexer SxEx. # For example Diamond is unbreakable - 26 -> Season 4 -> Absolute number 100 -> tvdb S03E26 scene_season = scene_exceptions.get_scene_exceptions_by_name( result.series_name or result.series.name)[0][1] if result.ab_episode_numbers: for absolute_episode in result.ab_episode_numbers: a = absolute_episode # Apparently we got a scene_season using the season scene exceptions. If we also do not have a season # parsed, guessit made a 'mistake' and it should have set the season with the value. # This is required for titles like: '[HorribleSubs].Kekkai.Sensen.&.Beyond.-.01.[1080p].mkv' # # Don't assume that scene_exceptions season is the same as indexer season. # E.g.: [HorribleSubs] Cardcaptor Sakura Clear Card - 08 [720p].mkv thetvdb s04, thexem s02 if result.series.is_scene or (result.season_number is None and scene_season is not None and scene_season > 0): a = scene_numbering.get_indexer_absolute_numbering( result.series, absolute_episode, True, scene_season) # Translate the absolute episode number, back to the indexers season and episode. (season, episode) = helpers.get_all_episodes_from_absolute_number( result.series, [a]) if result.season_number is None and scene_season is not None and scene_season > 0: log.debug( 'Detected a season scene exception [{series_name} -> {scene_season}] without a ' 'season number in the title, ' 'translating the episode absolute # [{scene_absolute}] to season #[{absolute_season}] and ' 'episode #[{absolute_episode}].', { 'series_name': result.series_name, 'scene_season': scene_season, 'scene_absolute': a, 'absolute_season': season, 'absolute_episode': episode }) else: log.debug( 'Scene numbering enabled series {name} with season {season} using indexer for absolute {absolute}: {ep}', { 'name': result.series.name, 'season': season, 'absolute': a, 'ep': episode_num(season, episode, 'absolute') }) new_absolute_numbers.append(a) new_episode_numbers.extend(episode) new_season_numbers.append(season) # It's possible that we map a parsed result to an anime series, # but the result is not detected/parsed as an anime. In that case, we're using the result.episode_numbers. else: for episode_number in result.episode_numbers: season = result.season_number episode = episode_number a = helpers.get_absolute_number_from_season_and_episode( result.series, season, episode) if a: new_absolute_numbers.append(a) log.debug( 'Scene numbering enabled anime {name} using indexer with absolute {absolute}: {ep}', { 'name': result.series.name, 'absolute': a, 'ep': episode_num(season, episode, 'absolute') }) new_episode_numbers.append(episode) new_season_numbers.append(season) return new_episode_numbers, new_season_numbers, new_absolute_numbers
def _parse_anime(result): """ Parse anime season episode results. Translate scene episode and season numbering to indexer numbering, using anime scen episode/season translation tables to indexer episode/season. :param result: Guessit parse result object. :return: tuple of found indexer episode numbers and indexer season numbers """ log.debug('Scene numbering enabled series {name} is anime', {'name': result.series.name}) new_episode_numbers = [] new_season_numbers = [] new_absolute_numbers = [] # Try to translate the scene series name to a scene number. # For example Jojo's bizarre Adventure - Diamond is unbreakable, will use xem, to translate the # "diamond is unbreakable" exception back to season 4 of it's "master" table. This will be used later # to translate it to an absolute number, which in turn can be translated to an indexer SxEx. # For example Diamond is unbreakable - 26 -> Season 4 -> Absolute number 100 -> tvdb S03E26 scene_season = scene_exceptions.get_scene_exceptions_by_name( result.series_name or result.series.name)[0][1] if result.ab_episode_numbers: for absolute_episode in result.ab_episode_numbers: a = absolute_episode # Apparently we got a scene_season using the season scene exceptions. If we also do not have a season # parsed, guessit made a 'mistake' and it should have set the season with the value. # This is required for titles like: '[HorribleSubs].Kekkai.Sensen.&.Beyond.-.01.[1080p].mkv' # # Don't assume that scene_exceptions season is the same as indexer season. # E.g.: [HorribleSubs] Cardcaptor Sakura Clear Card - 08 [720p].mkv thetvdb s04, thexem s02 if result.series.is_scene or (result.season_number is None and scene_season is not None and scene_season > 0): a = scene_numbering.get_indexer_absolute_numbering( result.series, absolute_episode, True, scene_season ) # Translate the absolute episode number, back to the indexers season and episode. (season, episode) = helpers.get_all_episodes_from_absolute_number(result.series, [a]) if result.season_number is None and scene_season is not None and scene_season > 0: log.debug( 'Detected a season scene exception [{series_name} -> {scene_season}] without a ' 'season number in the title, ' 'translating the episode absolute # [{scene_absolute}] to season #[{absolute_season}] and ' 'episode #[{absolute_episode}].', {'series_name': result.series_name, 'scene_season': scene_season, 'scene_absolute': a, 'absolute_season': season, 'absolute_episode': episode} ) else: log.debug( 'Scene numbering enabled series {name} with season {season} using indexer for absolute {absolute}: {ep}', {'name': result.series.name, 'season': season, 'absolute': a, 'ep': episode_num(season, episode, 'absolute')} ) new_absolute_numbers.append(a) new_episode_numbers.extend(episode) new_season_numbers.append(season) # It's possible that we map a parsed result to an anime series, # but the result is not detected/parsed as an anime. In that case, we're using the result.episode_numbers. else: for episode_number in result.episode_numbers: season = result.season_number episode = episode_number a = helpers.get_absolute_number_from_season_and_episode(result.series, season, episode) if a: new_absolute_numbers.append(a) log.debug( 'Scene numbering enabled anime {name} using indexer with absolute {absolute}: {ep}', {'name': result.series.name, 'absolute': a, 'ep': episode_num(season, episode, 'absolute')} ) new_episode_numbers.append(episode) new_season_numbers.append(season) return new_episode_numbers, new_season_numbers, new_absolute_numbers
def _parse_string(self, name): guess = guessit.guessit(name, dict(show_type=self.show_type)) result = self.to_parse_result(name, guess) search_series = helpers.get_show(result.series_name, self.try_indexers) if not self.naming_pattern else None # confirm passed in show object indexer id matches result show object indexer id series_obj = None if search_series and self.series and search_series.indexerid != self.series.indexerid else search_series result.series = series_obj or self.series # if this is a naming pattern test or result doesn't have a show object then return best result if not result.series or self.naming_pattern: return result new_episode_numbers = [] new_season_numbers = [] new_absolute_numbers = [] # if we have an air-by-date show and the result is air-by-date, # then get the real season/episode numbers if result.series.air_by_date and result.is_air_by_date: log.debug('Series {name} is air by date', {'name': result.series.name}) airdate = result.air_date.toordinal() main_db_con = db.DBConnection() sql_result = main_db_con.select( b'SELECT season, episode FROM tv_episodes WHERE indexer = ? AND showid = ? AND airdate = ?', [result.series.indexer, result.series.series_id, airdate]) season_number = None episode_numbers = [] if sql_result: season_number = int(sql_result[0][0]) episode_numbers = [int(sql_result[0][1])] # Use the next query item if we have multiple results # and the current one is a special episode (season 0) if season_number == 0 and len(sql_result) > 1: season_number = int(sql_result[1][0]) episode_numbers = [int(sql_result[1][1])] log.debug( 'Database info for series {name}: Season: {season} Episode(s): {episodes}', { 'name': result.series.name, 'season': season_number, 'episodes': episode_numbers } ) if season_number is None or not episode_numbers: log.debug('Series {name} has no season or episodes, using indexer', {'name': result.series.name}) try: indexer_api_params = indexerApi(result.series.indexer).api_params.copy() if result.series.lang: indexer_api_params['language'] = result.series.lang indexer_api = indexerApi(result.series.indexer).indexer(**indexer_api_params) tv_episode = indexer_api[result.series.indexerid].aired_on(result.air_date)[0] season_number = int(tv_episode['seasonnumber']) episode_numbers = [int(tv_episode['episodenumber'])] log.debug( 'Indexer info for series {name}: {ep}', { 'name': result.series.name, 'ep': episode_num(season_number, episode_numbers[0]), } ) except IndexerEpisodeNotFound: log.warning( 'Unable to find episode with date {date} for series {name}. Skipping', {'date': result.air_date, 'name': result.series.name} ) episode_numbers = [] except IndexerError as error: log.warning( 'Unable to contact {indexer_api.name}: {error}', {'indexer_api': indexer_api, 'error': error.message} ) episode_numbers = [] except IndexerException as error: log.warning( 'Indexer exception: {indexer_api.name}: {error}', {'indexer_api': indexer_api, 'error': error.message} ) episode_numbers = [] for episode_number in episode_numbers: season = season_number episode = episode_number if result.series.is_scene: (season, episode) = scene_numbering.get_indexer_numbering( result.series, season_number, episode_number, ) log.debug( 'Scene numbering enabled series {name}, using indexer numbering: {ep}', {'name': result.series.name, 'ep': episode_num(season, episode)} ) new_episode_numbers.append(episode) new_season_numbers.append(season) elif result.series.is_anime and result.is_anime: log.debug('Scene numbering enabled series {name} is anime', {'name': result.series.name}) scene_season = scene_exceptions.get_scene_exceptions_by_name(result.series_name)[0][1] for absolute_episode in result.ab_episode_numbers: a = absolute_episode # Apparently we got a scene_season using the season scene exceptions. If we also do not have a season # parsed, guessit made a 'mistake' and it should have set the season with the value. # This is required for titles like: '[HorribleSubs].Kekkai.Sensen.&.Beyond.-.01.[1080p].mkv' if result.season_number is None and scene_season > 0: season = scene_season episode = [a] log.debug( 'Detected a season scene exception [{series_name} -> {scene_season}] without a ' 'season number in the title, ' 'assuming the episode # [{scene_absolute}] is the scene_absolute #.', {'series_name': result.series_name, 'scene_season': scene_season, 'scene_absolute': a} ) else: if result.series.is_scene: a = scene_numbering.get_indexer_absolute_numbering(result.series, absolute_episode, True, scene_season) # Translate the absolute episode number, back to the indexers season and episode. (season, episode) = helpers.get_all_episodes_from_absolute_number(result.series, [a]) log.debug( 'Scene numbering enabled series {name} using indexer for absolute {absolute}: {ep}', {'name': result.series.name, 'absolute': a, 'ep': episode_num(season, episode, 'absolute')} ) new_absolute_numbers.append(a) new_episode_numbers.extend(episode) new_season_numbers.append(season) elif result.season_number and result.episode_numbers: for episode_number in result.episode_numbers: season = result.season_number episode = episode_number if result.series.is_scene: (season, episode) = scene_numbering.get_indexer_numbering( result.series, result.season_number, episode_number ) log.debug( 'Scene numbering enabled series {name} using indexer numbering: {ep}', {'name': result.series.name, 'ep': episode_num(season, episode)} ) if result.series.is_anime: a = helpers.get_absolute_number_from_season_and_episode(result.series, season, episode) if a: new_absolute_numbers.append(a) log.debug( 'Scene numbering enabled anime {name} using indexer with absolute {absolute}: {ep}', {'name': result.series.name, 'absolute': a, 'ep': episode_num(season, episode, 'absolute')} ) new_episode_numbers.append(episode) new_season_numbers.append(season) # need to do a quick sanity check heregex. It's possible that we now have episodes # from more than one season (by tvdb numbering), and this is just too much # for the application, so we'd need to flag it. new_season_numbers = sorted(set(new_season_numbers)) # remove duplicates if len(new_season_numbers) > 1: raise InvalidNameException('Scene numbering results episodes from seasons {seasons}, (i.e. more than one) ' 'and Medusa does not support this. Sorry.'.format(seasons=new_season_numbers)) # If guess it's possible that we'd have duplicate episodes too, # so lets eliminate them new_episode_numbers = sorted(set(new_episode_numbers)) # maybe even duplicate absolute numbers so why not do them as well new_absolute_numbers = sorted(set(new_absolute_numbers)) if new_absolute_numbers: result.ab_episode_numbers = new_absolute_numbers if new_season_numbers and new_episode_numbers: result.episode_numbers = new_episode_numbers result.season_number = new_season_numbers[0] # For anime that we still couldn't get a season, let's assume we should use 1. if result.series.is_anime and result.season_number is None and result.episode_numbers: result.season_number = 1 log.warning( 'Unable to parse season number for anime {name}, ' 'assuming absolute numbered anime with season 1', {'name': result.series.name} ) if result.series.is_scene: log.debug( 'Converted parsed result {original} into {result}', {'original': result.original_name, 'result': result} ) return result