The schema landed in 8d6ea6d; this fills it. A video library now builds
library -> series -> season -> episode, with episodes keeping kind='video'
and the two parents standing in for directories that have no file of their
own.
Three naming shapes are recognised, in order:
- a full marker, S01E02 or 1x02
- an episode-only marker, E05 / ep5 / Episode 5, which older rips and anime
use. With no season directory the season is 1, which is what those
libraries mean by it.
- a bare leading number, "05 - Title.mkv", trusted only under a season
directory. Without that anchor it is indistinguishable from a film whose
name starts with a number.
Every marker is delimited by non-alphanumeric characters, which is the guard
that stops "Blade.Runner.1999x264.mkv" reading as season 99 episode 264 -
the failure every release-tagged file would otherwise hit. The episode-only
pattern caps at three digits for the same reason: four would let
"Movie.E.1999.mkv" read as episode 1999, and years have four digits while
episode numbers do not.
Idempotency comes from ON CONFLICT (library_id, path) rather than a lookup,
so a duplicate series row is impossible rather than merely unlikely, and a
rescan leaves the tree byte-identical.
Verified red-green: neutering parseEpisode fails the episode tests, and
removing the episode-only branch fails the four patterns it covers.
Known limits, marked in the code: a multi-episode file (S01E02E03) parses
as its first episode only, and library has no separate 'tv' kind, so a video
library mixing films and shows builds both shapes side by side.
A bare-number episode keeps the cleaned file name as its title rather than
the text after the number. TV metadata replaces the title once the series
lookup lands, so it is not worth guessing at now.