commit remaining modified project files
This commit is contained in:
+41
-8
@@ -23,9 +23,11 @@ QUALITY_TAGS = [
|
||||
r'\b10bit\b', r'\b8bit\b',
|
||||
]
|
||||
|
||||
# Release group patterns (in brackets, but NOT years in parentheses)
|
||||
# Release group patterns (in brackets or parentheses at start/end)
|
||||
RELEASE_GROUP_PATTERNS = [
|
||||
r'\[[\w\s\-\.]+\]', # [RARBG], [YTS], etc.
|
||||
r'^\[[\w\s\-\.]+\]', # [Group] at start
|
||||
r'\[[\w\s\-\.]+\]$', # [Group] at end
|
||||
r'\b[\w\s\-\.]+[-_]Subs\b', # Group_Subs
|
||||
]
|
||||
|
||||
|
||||
@@ -56,6 +58,12 @@ def remove_release_groups(text: str) -> str:
|
||||
result = text
|
||||
for pattern in RELEASE_GROUP_PATTERNS:
|
||||
result = re.sub(pattern, '', result)
|
||||
|
||||
# Remove trailing parenthetical groups, but keep years like (2020)
|
||||
match = re.search(r'\s*(\([^)]+\))$', result)
|
||||
if match and not re.fullmatch(r'\(\d{4}\)', match.group(1)):
|
||||
result = result[:match.start()].rstrip()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@@ -77,6 +85,22 @@ def normalize_title(title: str) -> str:
|
||||
return title.strip()
|
||||
|
||||
|
||||
def humanize_parsed_title(title: str) -> str:
|
||||
"""Make parsed titles less likely to contain accidental all-caps tags.
|
||||
|
||||
This keeps short acronyms like "IV" intact while softening long all-caps
|
||||
words that are likely part of the filename rather than intentional styling.
|
||||
"""
|
||||
normalized = normalize_title(title)
|
||||
words = []
|
||||
for word in normalized.split():
|
||||
if word.isalpha() and word.isupper() and len(word) > 3:
|
||||
words.append(word.capitalize())
|
||||
else:
|
||||
words.append(word)
|
||||
return ' '.join(words).strip()
|
||||
|
||||
|
||||
def parse_movie(
|
||||
filename: str,
|
||||
extensions: Optional[list[str]] = None,
|
||||
@@ -127,7 +151,7 @@ def parse_movie(
|
||||
# Now clean the title
|
||||
title = remove_quality_tags(title)
|
||||
title = remove_release_groups(title)
|
||||
title = normalize_title(title)
|
||||
title = humanize_parsed_title(title or match.group(1))
|
||||
|
||||
return MovieIdentity(
|
||||
title=title,
|
||||
@@ -140,7 +164,7 @@ def parse_movie(
|
||||
# No year found - clean and extract title, flag for review
|
||||
cleaned = remove_quality_tags(name_without_ext)
|
||||
cleaned = remove_release_groups(cleaned)
|
||||
title = normalize_title(cleaned)
|
||||
title = humanize_parsed_title(cleaned or name_without_ext)
|
||||
|
||||
return MovieIdentity(
|
||||
title=title,
|
||||
@@ -189,6 +213,8 @@ def parse_series(
|
||||
(r'(?<!\d)(\d{1,2})x(\d{1,2})(?!\d)', 0.9),
|
||||
# Pattern: Season X Episode Y - Medium confidence
|
||||
(r'[Ss]eason\s*(\d{1,2})\s*[Ee]pisode\s*(\d{1,2})', 0.7),
|
||||
# Pattern: Hyphen Episode (Anime style: Name - 01) - Medium confidence, assume Season 1
|
||||
(r'\s+-\s+(\d{1,3})(?!\d)', 0.6),
|
||||
]
|
||||
|
||||
season = None
|
||||
@@ -199,8 +225,14 @@ def parse_series(
|
||||
for pattern, conf in patterns:
|
||||
match = re.search(pattern, name_without_ext, re.IGNORECASE)
|
||||
if match:
|
||||
season = int(match.group(1))
|
||||
episodes = [int(match.group(2))]
|
||||
if len(match.groups()) == 2:
|
||||
season = int(match.group(1))
|
||||
episodes = [int(match.group(2))]
|
||||
else:
|
||||
# Hyphen episode only
|
||||
season = 1
|
||||
episodes = [int(match.group(1))]
|
||||
|
||||
confidence = conf
|
||||
|
||||
# Extract title (everything before the match)
|
||||
@@ -222,12 +254,12 @@ def parse_series(
|
||||
if title_part:
|
||||
title_part = remove_quality_tags(title_part)
|
||||
title_part = remove_release_groups(title_part)
|
||||
title_part = normalize_title(title_part)
|
||||
title_part = humanize_parsed_title(title_part or name_without_ext)
|
||||
else:
|
||||
# If no title part found, use the whole filename cleaned
|
||||
title_part = remove_quality_tags(name_without_ext)
|
||||
title_part = remove_release_groups(title_part)
|
||||
title_part = normalize_title(title_part)
|
||||
title_part = humanize_parsed_title(title_part or name_without_ext)
|
||||
|
||||
# Determine if review is needed
|
||||
needs_review = season is None or len(episodes) == 0
|
||||
@@ -247,6 +279,7 @@ def parse_series(
|
||||
|
||||
|
||||
def group_episodes(episodes: list[SeriesIdentity]) -> dict[tuple[str, int], list[SeriesIdentity]]:
|
||||
|
||||
"""Group parsed episodes by normalized series title and season number.
|
||||
|
||||
Episodes are grouped by (normalized_title, season) tuple. Episodes with
|
||||
|
||||
Reference in New Issue
Block a user