Release v1.0.11: fix multi-episode match for end-numbered and dual titles.
Combined pairs are recognized when the SxxExx tag uses the last episode number or the filename lists both story titles separated by dashes. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
+32
-7
@@ -269,21 +269,46 @@ def _combined_title_variants(name: str) -> list[str]:
|
|||||||
return variants
|
return variants
|
||||||
|
|
||||||
|
|
||||||
def _combined_match_score(fnorm: str, combined_name: str) -> float:
|
def _combined_match_score(fnorm: str, combined_name: str, file_title: str = "") -> float:
|
||||||
variants = _combined_title_variants(combined_name)
|
variants = _combined_title_variants(combined_name)
|
||||||
return max((_similarity(fnorm, v) for v in variants), default=0.0)
|
best = max((_similarity(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
|
||||||
|
|
||||||
|
|
||||||
def _combined_allowed_for_file(parsed: dict, target: EpisodeTarget) -> bool:
|
def _dual_title_matches_combined(file_title: str, combined_name: str) -> bool:
|
||||||
"""Only treat as multi-episode when the file's episode code fits the range start."""
|
"""True when the filename lists both stories in a combined-order pair."""
|
||||||
|
file_parts = [p.strip() for p in re.split(r"\s+-\s+", file_title) if p.strip()]
|
||||||
|
combined_parts = split_combined_title(combined_name)
|
||||||
|
if len(file_parts) < 2 or len(combined_parts) < 2:
|
||||||
|
return False
|
||||||
|
matched = 0
|
||||||
|
for fp in file_parts[: len(combined_parts)]:
|
||||||
|
fn = normalize_title(fp)
|
||||||
|
if max(_similarity(fn, normalize_title(cp)) for cp in combined_parts) >= 0.72:
|
||||||
|
matched += 1
|
||||||
|
return matched >= 2
|
||||||
|
|
||||||
|
|
||||||
|
def _combined_allowed_for_file(
|
||||||
|
parsed: dict,
|
||||||
|
target: EpisodeTarget,
|
||||||
|
combined_name: str = "",
|
||||||
|
) -> bool:
|
||||||
|
"""Treat as multi-episode when the episode tag or dual title fits the aired range."""
|
||||||
if target.span <= 1:
|
if target.span <= 1:
|
||||||
return True
|
return True
|
||||||
if parsed.get("span", 1) > 1:
|
if parsed.get("span", 1) > 1:
|
||||||
return True
|
return True
|
||||||
|
file_title = parsed.get("title") or ""
|
||||||
|
if combined_name and _dual_title_matches_combined(file_title, combined_name):
|
||||||
|
return True
|
||||||
file_ep = parsed.get("old_first")
|
file_ep = parsed.get("old_first")
|
||||||
if file_ep is None:
|
if file_ep is None:
|
||||||
return False
|
return False
|
||||||
return file_ep == target.episode
|
end = target.episode_end if target.episode_end is not None else target.episode
|
||||||
|
return file_ep == target.episode or file_ep == end
|
||||||
|
|
||||||
|
|
||||||
def _range_overlaps(
|
def _range_overlaps(
|
||||||
@@ -390,9 +415,9 @@ def match_filenames_to_episodes(
|
|||||||
for _cep, target, variants in combined_entries:
|
for _cep, target, variants in combined_entries:
|
||||||
if not fnorm:
|
if not fnorm:
|
||||||
continue
|
continue
|
||||||
if not _combined_allowed_for_file(parsed, target):
|
if not _combined_allowed_for_file(parsed, target, _cep.name):
|
||||||
continue
|
continue
|
||||||
best = _combined_match_score(fnorm, _cep.name)
|
best = _combined_match_score(fnorm, _cep.name, raw_title)
|
||||||
best = _apply_season_hint(best, target, parsed)
|
best = _apply_season_hint(best, target, parsed)
|
||||||
pairs.append((best, fname, target, raw_title, _cep.name))
|
pairs.append((best, fname, target, raw_title, _cep.name))
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
HSRename 1.0.11
|
||||||
|
- Fix multi-episode detection when filename uses end episode (S01E06 for E05-E06)
|
||||||
|
- Detect dual titles separated by " - " (Otto 3000 - Night Prowler) as combined pairs
|
||||||
Reference in New Issue
Block a user