Release v1.0.15: fix nxnn preview crash and improve truncated title matching.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Bulk Renamer
2026-07-03 22:34:29 -05:00
co-authored by Cursor
parent 87282b0259
commit 0d7c16372c
4 changed files with 38 additions and 4 deletions
+32 -2
View File
@@ -170,6 +170,7 @@ def rewrite_episode_stem(
span = target.episode_end - target.episode + 1
else:
span = parsed["span"]
title = parsed.get("title") or ""
if parsed["format"] == "nxnn":
s_pad = max(parsed["season_pad"], len(str(new_season)))
@@ -218,6 +219,33 @@ def _similarity(a: str, b: str) -> float:
return SequenceMatcher(None, a, b).ratio()
def _title_match_score(fnorm: str, enorm: str) -> float:
"""Fuzzy title match; handles filenames that use a shortened episode title."""
if not fnorm or not enorm:
return 0.0
if fnorm == enorm:
return 1.0
score = _similarity(fnorm, enorm)
if len(fnorm) >= 4 and (fnorm in enorm or enorm.startswith(fnorm)):
score = max(score, 0.78)
ftokens = [t for t in fnorm.split() if len(t) > 2]
if ftokens:
etokens = set(enorm.split())
overlap = sum(1 for t in ftokens if t in etokens) / len(ftokens)
if overlap >= 0.75:
score = max(score, 0.66 + overlap * 0.3)
return score
def _episode_number_boost(parsed: dict, season: int, ep_num: int, title_score: float) -> float:
"""Nudge score up when NxNN/SxxExx in the filename agrees with this episode."""
if title_score < 0.45:
return 0.0
if parsed.get("season") == season and parsed.get("old_first") == ep_num:
return 0.12
return 0.0
def _coerce_target(
value: EpisodeTarget | tuple[int, ...] | int,
parsed: dict,
@@ -278,7 +306,7 @@ def _combined_title_variants(name: str) -> list[str]:
def _combined_match_score(fnorm: str, combined_name: str, file_title: str = "") -> float:
variants = _combined_title_variants(combined_name)
best = max((_similarity(fnorm, v) for v in variants), default=0.0)
best = max((_title_match_score(fnorm, v) for v in variants), default=0.0)
if file_title and _dual_title_matches_combined(file_title, combined_name):
best = max(best, 0.96)
return best
@@ -417,8 +445,10 @@ def match_filenames_to_episodes(
for season, ep_num, enorm, ep_name in season_eps:
if not fnorm:
continue
title_score = _title_match_score(fnorm, enorm)
score = title_score + _episode_number_boost(parsed, season, ep_num, title_score)
score = _apply_season_hint(
_similarity(fnorm, enorm),
score,
EpisodeTarget(season=season, episode=ep_num),
parsed,
)