class CountValidator(Rule): """ Validate count property and rename it """ priority = 64 consequence = [ RemoveMatch, RenameMatch('episode_count'), RenameMatch('season_count') ] properties = {'episode_count': [None], 'season_count': [None]} def when(self, matches, context): to_remove = [] episode_count = [] season_count = [] for count in matches.named('count'): previous = matches.previous( count, lambda match: match.name in ['episode', 'season'], 0) if previous: if previous.name == 'episode': episode_count.append(count) elif previous.name == 'season': season_count.append(count) else: to_remove.append(count) if to_remove or episode_count or season_count: return to_remove, episode_count, season_count return False
class RenameToDiscMatch(Rule): """ Rename episodes detected with `d` episodeMarkers to `disc`. """ consequence = [RenameMatch('disc'), RenameMatch('discMarker'), RemoveMatch] def when(self, matches, context): discs = [] markers = [] to_remove = [] disc_disabled = is_disabled(context, 'disc') for marker in matches.named( 'episodeMarker', predicate=lambda m: m.value.lower() == 'd'): if disc_disabled: to_remove.append(marker) to_remove.extend(marker.initiator.children) continue markers.append(marker) discs.extend( sorted(marker.initiator.children.named('episode'), key=lambda m: m.value)) if discs or markers or to_remove: return discs, markers, to_remove return False
class SubtitleExtensionRule(Rule): """ Convert language guess as subtitle_language if next match is a subtitle extension. Since it's a strong match, it also removes any conflicting source with it. """ consequence = [RemoveMatch, RenameMatch('subtitle_language')] properties = {'subtitle_language': [None]} def enabled(self, context): return not is_disabled(context, 'subtitle_language') def when(self, matches, context): # pylint:disable=inconsistent-return-statements subtitle_extension = matches.named( 'container', lambda match: 'extension' in match.tags and 'subtitle' in match.tags, 0) if subtitle_extension: subtitle_lang = matches.previous( subtitle_extension, lambda match: match.name == 'language', 0) if subtitle_lang: for weak in matches.named( 'subtitle_language', predicate=lambda m: 'weak-language' in m.tags): weak.private = True return matches.conflicting( subtitle_lang, lambda m: m.name == 'source'), subtitle_lang
class RenameToAbsoluteEpisode(Rule): """ Rename episode to absolute_episodes. Absolute episodes are only used if two groups of episodes are detected: S02E04-06 25-27 25-27 S02E04-06 2x04-06 25-27 28. Anime Name S02E05 The matches in the group with higher episode values are renamed to absolute_episode. """ consequence = RenameMatch('absolute_episode') def when(self, matches, context): # pylint:disable=inconsistent-return-statements initiators = {match.initiator for match in matches.named('episode') if len(match.initiator.children.named('episode')) > 1} if len(initiators) != 2: ret = [] for filepart in matches.markers.named('path'): if matches.range(filepart.start + 1, filepart.end, predicate=lambda m: m.name == 'episode'): ret.extend( matches.starting(filepart.start, predicate=lambda m: m.initiator.name == 'weak_episode')) return ret initiators = sorted(initiators, key=lambda item: item.end) if not matches.holes(initiators[0].end, initiators[1].start, predicate=lambda m: m.raw.strip(seps)): first_range = matches.named('episode', predicate=lambda m: m.initiator == initiators[0]) second_range = matches.named('episode', predicate=lambda m: m.initiator == initiators[1]) if len(first_range) == len(second_range): if second_range[0].value > first_range[0].value: return second_range if first_range[0].value > second_range[0].value: return first_range
class RenameAnotherToOther(Rule): """ Rename `another` properties to `other` """ priority = 32 consequence = RenameMatch('other') def when(self, matches, context): return matches.named('another')
class SubtitleExtensionRule(Rule): """ Convert language guess as subtitle_language if next match is a subtitle extension """ consequence = RenameMatch('subtitle_language') properties = {'subtitle_language': [None]} def when(self, matches, context): subtitle_extension = matches.named('container', lambda match: 'extension' in match.tags and 'subtitle' in match.tags, 0) if subtitle_extension: subtitle_lang = matches.previous(subtitle_extension, lambda match: match.name == 'language', 0) if subtitle_lang: return subtitle_lang
class SubtitleExtensionRule(Rule): """ Convert language guess as subtitle_language if next match is a subtitle extension. Since it's a strong match, it also removes any conflicting source with it. """ consequence = [RemoveMatch, RenameMatch('subtitle_language')] properties = {'subtitle_language': [None]} def when(self, matches, context): subtitle_extension = matches.named('container', lambda match: 'extension' in match.tags and 'subtitle' in match.tags, 0) if subtitle_extension: subtitle_lang = matches.previous(subtitle_extension, lambda match: match.name == 'language', 0) if subtitle_lang: return matches.conflicting(subtitle_lang, lambda m: m.name == 'source'), subtitle_lang