diff --git a/scanner/scanner/parser/rules.py b/scanner/scanner/parser/rules.py index d730f7a3..b707e28f 100644 --- a/scanner/scanner/parser/rules.py +++ b/scanner/scanner/parser/rules.py @@ -1,6 +1,6 @@ # Read that for examples/rules: https://github.com/pymedusa/Medusa/blob/master/medusa/name_parser/rules/rules.py -from typing import Any, Generator, Iterable, List, Optional, cast +from typing import Any, List, Optional, cast from rebulk import Rule, RemoveMatch, AppendMatch, POST_PROCESS from rebulk.match import Matches, Match from copy import copy @@ -10,7 +10,6 @@ class EpisodeTitlePromotion(Rule): """Promote "episode_title" to "episode" when the title is in fact the episode number Example: '[Erai-raws] Youkoso Jitsuryoku Shijou Shugi no Kyoushitsu e S3 - 05 [1080p][Multiple Subtitle][0DDEAFCD].mkv' - Default: ```json { @@ -18,15 +17,8 @@ class EpisodeTitlePromotion(Rule): "title": "Youkoso Jitsuryoku Shijou Shugi no Kyoushitsu e", "season": 3, "episode_title": "05", - "screen_size": "1080p", - "subtitle_language": "Multiple languages", - "crc32": "0DDEAFCD", - "container": "mkv", - "mimetype": "video/x-matroska", - "type": "episode" } ``` - Expected: ```json { @@ -34,12 +26,6 @@ class EpisodeTitlePromotion(Rule): "title": "Youkoso Jitsuryoku Shijou Shugi no Kyoushitsu e", "season": 3, "episode": 5, - "screen_size": "1080p", - "subtitle_language": "Multiple languages", - "crc32": "0DDEAFCD", - "container": "mkv", - "mimetype": "video/x-matroska", - "type": "episode" } ``` """ @@ -67,7 +53,6 @@ class TitleNumberFixup(Rule): Example: '[Erai-raws] Zom 100 - Zombie ni Naru made ni Shitai 100 no Koto - 01 [1080p][Multiple Subtitle][8AFBB298].mkv' (or '[SubsPlease] Mob Psycho 100 Season 3 - 12 (1080p) [E5058D7B].mkv') - Default: ```json { @@ -78,15 +63,8 @@ class TitleNumberFixup(Rule): 1 ], "episode_title": "Zombie ni Naru made ni Shitai", - "screen_size": "1080p", - "subtitle_language": "Multiple languages", - "crc32": "8AFBB298", - "container": "mkv", - "mimetype": "video/x-matroska", - "type": "episode" } ``` - Expected: ```json { @@ -94,12 +72,6 @@ class TitleNumberFixup(Rule): "title": "Zom 100", "episode": 1, "episode_title": "Zombie ni Naru made ni Shitai 100 no Koto", - "screen_size": "1080p", - "subtitle_language": "Multiple languages", - "crc32": "8AFBB298", - "container": "mkv", - "mimetype": "video/x-matroska", - "type": "episode" } ``` """ @@ -110,14 +82,14 @@ class TitleNumberFixup(Rule): def when(self, matches: Matches, context) -> Any: episodes: List[Match] = matches.named("episode") # type: ignore - if not episodes or len(episodes) < 2: + if len(episodes) < 2: return to_remove = [] to_add = [] for episode in episodes: prevs: List[Match] = matches.previous(episode) # type: ignore - title = prevs[0] if len(prevs) > 0 and prevs[0].tagged("title") else None + title = prevs[0] if prevs and prevs[0].tagged("title") else None if not title: continue @@ -127,9 +99,9 @@ class TitleNumberFixup(Rule): continue to_remove.extend([title, episode]) - newTitle = copy(title) - newTitle.end = episode.end - newTitle.value = f"{title.value} {episode.value}" + new_title = copy(title) + new_title.end = episode.end + new_title.value = f"{title.value} {episode.value}" # If an hole was created to parse the episode at the current pos, merge it back into the title holes = matches.holes(episode.end) @@ -138,10 +110,10 @@ class TitleNumberFixup(Rule): if "-" in val: val, *_ = val.split("-") val = val.rstrip() - newTitle.value = f"{newTitle.value}{val}" - newTitle.end += len(val) + new_title.value = f"{new_title.value}{val}" + new_title.end += len(val) - to_add.append(newTitle) + to_add.append(new_title) return [to_remove, to_add] @@ -149,7 +121,6 @@ class MultipleSeasonRule(Rule): """Understand `abcd Season 2 - 5.mkv` as S2E5 Example: '[Erai-raws] Spy x Family Season 2 - 08 [1080p][Multiple Subtitle][00C44E2F].mkv' - Default: ```json { @@ -163,27 +134,14 @@ class MultipleSeasonRule(Rule): 7, 8 ], - "screen_size": "1080p", - "release_group": "Multiple Subtitle", - "crc32": "00C44E2F", - "container": "mkv", - "mimetype": "video/x-matroska", - "type": "episode" } ``` - Expected: ```json { "title": "Spy x Family", "season": 2, "episode": 8, - "screen_size": "1080p", - "release_group": "Multiple Subtitle", - "crc32": "00C44E2F", - "container": "mkv", - "mimetype": "video/x-matroska", - "type": "episode" } ``` """ @@ -194,7 +152,7 @@ class MultipleSeasonRule(Rule): def when(self, matches: Matches, context) -> Any: seasons: List[Match] = matches.named("season") # type: ignore - if not seasons or len(seasons) < 1: + if not seasons: return # Only apply this rule if all seasons are due to the same match @@ -208,12 +166,12 @@ class MultipleSeasonRule(Rule): if "-" not in value: return - newSeason, *newEpisodes = (x.strip() for x in value.split("-")) - to_remove = [x for x in seasons if cast(Match, x.parent).value != newSeason] + new_season, *new_episodes = (x.strip() for x in value.split("-")) + to_remove = [x for x in seasons if cast(Match, x.parent).value != new_season] to_add = [] try: - episodes = [int(x) for x in newEpisodes] + episodes = [int(x) for x in new_episodes] parents: List[Match] = [match.parent for match in to_remove] # type: ignore for episode in episodes: smatch = next( @@ -231,4 +189,66 @@ class MultipleSeasonRule(Rule): return [to_remove, to_add] -# TODO: xem fixup? like for "Somthing Season 2" was a xem override but we converted that to "Something", season: 2 then convert it back here? +class XemFixup(Rule): + """Fix both alternate names and seasons that are known on the xem but parsed differently by guessit + + Example: "JoJo's Bizarre Adventure - Diamond is Unbreakable - 12.mkv" + Default: + ```json + { + "title": "JoJo's Bizarre Adventure", + "alternative_title": "Diamond is Unbreakable", + "episode": 12, + } + ``` + Expected: + ```json + { + "title": "JoJo's Bizarre Adventure - Diamond is Unbreakable", + "episode": 12, + } + ``` + + Or + Example: 'Owarimonogatari S2 E15.mkv' + Default: + ```json + { + "title": "Owarimonogatari", + "season": 2, + "episode": 15 + } + ``` + Expected: + ```json + { + "title": "Owarimonogatari S2", + "episode": 15 + } + ``` + """ + + priority = POST_PROCESS + consequence = [RemoveMatch, AppendMatch] + + def when(self, matches: Matches, context) -> Any: + titles: List[Match] = matches.named("title", lambda m: m.tagged("title")) # type: ignore + + if not titles: + return + title = titles[0] + + nmatch: List[Match] = matches.next(title) # type: ignore + if not nmatch or not (nmatch[0].tagged("title") or nmatch[0].named("season")): + return + + holes: List[Match] = matches.holes(title.end, nmatch[0].start) # type: ignore + hole = " ".join(f" {h.value}" if h.value != "-" else " - " for h in holes) + + new_title = copy(title) + new_title.end = nmatch[0].end + new_title.value = f"{title.value}{hole}{nmatch[0].value}" + + # TODO: check if new_title exists on thexem, if not early return + + return [[title, nmatch[0]], [new_title]]