fix(media): a sidecar named "episode.mkv.srt" anchors, and loses the container word

The first run against the real library died in the anchor lookup: a subtitle
whose own name carries the media extension matches BOTH prefix forms of its
video, and the "keep the longest" comparison read the destination slot of the
tuple instead of the length slot. The fixture only ever matched one prefix, so
the seam was green over a crash.

The tail the sidecar keeps is now stripped of that container word: Jellyfin and
Plex both read "Show S01E01.forced.srt", not "Show S01E01.mkv.forced.srt", and
an nfo still carries the media extension because that one is constructed, not
parsed.
This commit is contained in:
Frank committed 2026-10-30 23:17:55 -07:00
1 parent 441b908937
commit c0c77590b1
2 files changed
+16 -1

No files matched your search

+9 -1
View File
@@ -112,6 +112,9 @@ VIDEO_EXT = {".mkv", ".mp4", ".avi", ".m4v", ".mov", ".ts", ".m2ts", ".mpg",
SUB_EXT = {".srt", ".ass", ".ssa", ".sub", ".vtt"}
IMG_EXT = {".jpg", ".jpeg", ".png", ".webp", ".bmp", ".gif", ".tbn"}
NFO_EXT = {".nfo", ".xml"}
# The container's own word, for a sidecar named "episode.mkv.srt": that component
# is not a language flag, and both matchers read the plain form better.
CONTAINER = {e[1:] for e in VIDEO_EXT}
# Files that are never anybody's business: hidden, forks, resume state, thumbnails.
SKIP_NAME = re.compile(r"^(\.|#|dl_state|@eaDir|Thumbs\.db|desktop\.ini)|\.!q$")
# Show-level metadata keeps its own name at the series root; season-level at the
@@ -556,7 +559,7 @@ def anchor_of(path, stem):
base = os.path.basename(src)
for prefix in (os.path.splitext(base)[0], base):
if stem == prefix or stem.startswith(prefix + "."):
if best is None or len(prefix) > best[1]:
if best is None or len(prefix) > best[2]:
best = (src, dst, len(prefix))
if best:
return best[0], best[1]
@@ -568,6 +571,11 @@ def sidecar_name(r, src, dst):
carry — hung on the video file's new base."""
stem = os.path.splitext(os.path.basename(src))[0]
tail = os.path.splitext(r["base"])[0][len(stem):]
# "Show.S01E01.mkv.srt" carries the container's name, not a flag: Jellyfin and
# Plex both read "Show S01E01.srt", so the container word is dropped here.
parts = tail.split(".")
if len(parts) > 1 and parts[1].lower() in CONTAINER:
tail = "".join("." + p for p in parts[2:])
if r["ext"] in NFO_EXT:
tail = os.path.splitext(os.path.basename(src))[1] + tail
return clean(os.path.splitext(os.path.basename(dst))[0] + tail + r["ext"])