Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d7c16372c |
+32
-2
@@ -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,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
HSRename 1.0.15
|
||||
- Fix nxnn preview crash (undefined title in rewrite_episode_stem)
|
||||
- Improve matching for shortened episode titles (prefix/token overlap scoring)
|
||||
+2
-1
@@ -76,7 +76,8 @@ API="${GITEA_HOST}/api/v1/repos/${GITEA_OWNER}/${GITEA_REPO}/releases"
|
||||
NOTES="$(cat <<EOF
|
||||
## HSRename ${TAG}
|
||||
|
||||
- Fix botched v1.0.4 AppImage (restores TheTVDB episode match + search fix)
|
||||
- Fix nxnn preview crash (\`name 'title' is not defined\`)
|
||||
- Improve TheTVDB matching for shortened episode titles (prefix and token overlap)
|
||||
- Always verify/update via Gear Lever Forgejo: \`https://git.hisora.dev/Dawnsorrow/HS-Rename\`
|
||||
|
||||
Download:
|
||||
|
||||
Reference in New Issue
Block a user