feat(media): plan a TV relayout from the numbering Jellyfin already has #99

Merged
dank merged 4 commits from feat/media-tv-relayout into main 2026-10-30 23:38:36 -07:00
2 changed files with 16 additions and 1 deletions
Showing only changes of commit c0c77590b1 - Show all commits

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"} SUB_EXT = {".srt", ".ass", ".ssa", ".sub", ".vtt"}
IMG_EXT = {".jpg", ".jpeg", ".png", ".webp", ".bmp", ".gif", ".tbn"} IMG_EXT = {".jpg", ".jpeg", ".png", ".webp", ".bmp", ".gif", ".tbn"}
NFO_EXT = {".nfo", ".xml"} 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. # 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$") 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 # 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) base = os.path.basename(src)
for prefix in (os.path.splitext(base)[0], base): for prefix in (os.path.splitext(base)[0], base):
if stem == prefix or stem.startswith(prefix + "."): 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)) best = (src, dst, len(prefix))
if best: if best:
return best[0], best[1] return best[0], best[1]
@@ -568,6 +571,11 @@ def sidecar_name(r, src, dst):
carry — hung on the video file's new base.""" carry — hung on the video file's new base."""
stem = os.path.splitext(os.path.basename(src))[0] stem = os.path.splitext(os.path.basename(src))[0]
tail = os.path.splitext(r["base"])[0][len(stem):] 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: if r["ext"] in NFO_EXT:
tail = os.path.splitext(os.path.basename(src))[1] + tail tail = os.path.splitext(os.path.basename(src))[1] + tail
return clean(os.path.splitext(os.path.basename(dst))[0] + tail + r["ext"]) return clean(os.path.splitext(os.path.basename(dst))[0] + tail + r["ext"])
+7
View File
@@ -54,6 +54,7 @@ setup() {
# trailer: four things that have to end up in four different places. # trailer: four things that have to end up in four different places.
at "$SEASON/The.Examples.S01E01.Pilot.1080p.x265.mkv" 9000 at "$SEASON/The.Examples.S01E01.Pilot.1080p.x265.mkv" 9000
at "$SEASON/The.Examples.S01E01.Pilot.1080p.x265.en.srt" 200 at "$SEASON/The.Examples.S01E01.Pilot.1080p.x265.en.srt" 200
at "$SEASON/The.Examples.S01E01.Pilot.1080p.x265.mkv.forced.srt" 250
at "$SEASON/folder.jpg" 300 at "$SEASON/folder.jpg" 300
at "$SEASON/Trailers/teaser.mkv" 1000 at "$SEASON/Trailers/teaser.mkv" 1000
at "$SEASON/tvshow.nfo" 400 at "$SEASON/tvshow.nfo" 400
@@ -143,6 +144,12 @@ PY
= "$LIB/The Examples (2010)/Season 01/The Examples S01E01.en.srt" ] = "$LIB/The Examples (2010)/Season 01/The Examples S01E01.en.srt" ]
} }
@test "a subtitle that carries the container's word in its own name still follows the episode" {
plan
[ "$(dst "$SEASON/The.Examples.S01E01.Pilot.1080p.x265.mkv.forced.srt")" \
= "$LIB/The Examples (2010)/Season 01/The Examples S01E01.forced.srt" ]
}
@test "a season image keeps its own name; a series nfo keeps the series folder" { @test "a season image keeps its own name; a series nfo keeps the series folder" {
plan plan
[ "$(dst "$SEASON/folder.jpg")" = "$LIB/The Examples (2010)/Season 01/folder.jpg" ] [ "$(dst "$SEASON/folder.jpg")" = "$LIB/The Examples (2010)/Season 01/folder.jpg" ]