diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-08-26 17:18:37 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-08-26 17:18:37 +0200 |
| commit | 80cb6c4dc5f22336387f2ac74ef2cb85cf2cf7d4 (patch) | |
| tree | 590e2daf81b2feef674f1bd580b9bf40f83addad /packages/meshbay-node/tests/test_title_parse.py | |
| parent | ca62b4123b854fc9ece258e14c84c895aaa275cd (diff) | |
| parent | 59289b82dc8af08c605fd247c90a5c5ec92c6db3 (diff) | |
| download | meshbay-80cb6c4dc5f22336387f2ac74ef2cb85cf2cf7d4.tar.gz | |
Merge branch 'feat/video-type-filter'
Videos app grouping and TMDB matching fixes, plus a new toolbar filter:
- A season-like ancestor folder (numbered season, or Specials/Bonus/Extras
-> season 0) now names the show from its own root folder, unconditionally
— never a per-file guessit title, which cannot tell a show's real name
from an individual episode's own one-off name when the filename carries
no reliable ShowName/SxxExx structure. Fixes a real show's episodes and
Specials folder alike showing up as dozens of individual "movies", each
matched against TMDB by its own one-off title.
- The ancestor walk continues past every consecutive season-like folder,
not just the first — a per-season Bonus folder is nested two levels
inside the show, and stopping at the first would name the season as the
show.
- A season spanning more than one folder (a per-book Bonus folder nested
inside every numbered season) no longer hands out colliding episode
numbers independently in each one.
- guessit's own episode number is not trusted when it comes from a bare
3-digit leading number ("100" parses as season=1/episode=0, not
episode=100) — read directly via regex instead.
- Recognizes "S1"/"S2"-style abbreviated season folders, not just full
words ("Season"/"Saison"/"Livre") — a real show organized its later
seasons this way and they never got the ancestor-based grouping fix at
all.
- The TMDB match cache is no longer trusted across a movie<->show
reclassification it doesn't know happened.
- New: an All/Movies/Series filter in the Videos toolbar, to the left of
the search field, defaulting to "All"; wraps correctly on mobile.
Verified live against the real libraries these were found on throughout —
not synthetic reproduction alone. 430 hub tests + 667 node tests passing.
Diffstat (limited to 'packages/meshbay-node/tests/test_title_parse.py')
| -rw-r--r-- | packages/meshbay-node/tests/test_title_parse.py | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/packages/meshbay-node/tests/test_title_parse.py b/packages/meshbay-node/tests/test_title_parse.py index 1a277f2..5f0977c 100644 --- a/packages/meshbay-node/tests/test_title_parse.py +++ b/packages/meshbay-node/tests/test_title_parse.py @@ -6,6 +6,7 @@ is a manual acceptance step (§11), not something this repo's corpus holds. from meshbay_node.indexer.title_parse import ( ParsedName, + leading_episode_number, naive_title, parse_episode_filename, parse_movie_filename, @@ -111,6 +112,31 @@ def test_season_folder_roman_numeral(): assert season_from_folder_name("Saison IV") == 4 +def test_season_folder_book_word_roman_numeral(): + # Some shows number their seasons by "book" (Roman numerals) rather + # than "season"/"saison" — real, observed vocabulary (§3.4). + assert season_from_folder_name("Livre I") == 1 + assert season_from_folder_name("Livre VI") == 6 + + +def test_season_folder_bare_s_abbreviation(): + # A common abbreviated convention distinct from SEASON_WORDS' full + # words — found live: a show with "S1"/"S2"/"S3" folders instead of + # "Season 1" etc, exactly the shape that grouped its later seasons as + # loose individual entries rather than under the show. + assert season_from_folder_name("S1") == 1 + assert season_from_folder_name("S2") == 2 + assert season_from_folder_name("S02") == 2 + + +def test_season_folder_bare_s_abbreviation_does_not_match_inside_a_longer_name(): + # Anchored to the whole folder name — a real folder that merely starts + # with "S" followed by digits somewhere in a longer, unrelated name + # must not be read as a season abbreviation. + assert season_from_folder_name("S1 Extended Cut") is None + assert season_from_folder_name("Something2") is None + + def test_specials_folder_maps_to_season_zero(): assert season_from_folder_name("Specials") == 0 assert season_from_folder_name("Bonus") == 0 @@ -121,6 +147,30 @@ def test_non_season_folder_name_returns_none(): assert season_from_folder_name("Some Show Name") is None +# ── §3.4c: a bare leading episode number, guessit's 3-digit blind spot ─────── + +def test_leading_episode_number_reads_the_whole_number(): + assert leading_episode_number("001 Episode's Own Title.mkv") == 1 + assert leading_episode_number("099 Episode's Own Title.mkv") == 99 + + +def test_leading_episode_number_not_split_by_guessit_at_three_digits(): + # The real bug this guards: guessit itself reads a bare "100" as season=1, + # episode=0 (a concatenated SxxE guess), not episode=100 — silently, with + # nothing in its output telling apart a real 2-digit episode from this. + assert leading_episode_number("100 Episode's Own Title.mkv") == 100 + + +def test_leading_episode_number_ignores_a_leading_year(): + # Four digits, not the 1-3 an episode-number prefix can be — this is a + # normal movie filename shape, not an episode number. + assert leading_episode_number("2010 - Some Movie.mkv") is None + + +def test_leading_episode_number_none_without_a_leading_number(): + assert leading_episode_number("Some Show.S01E01.mkv") is None + + def test_parsed_name_is_a_plain_dataclass(): # sanity: constructible with just the one required field, per the # "None => caller must supply from elsewhere" contract. |