diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-08-24 14:33:38 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-08-24 14:33:38 +0200 |
| commit | 317f09328ed8bf20148b707470c9b0fe82e59575 (patch) | |
| tree | ba8daf5dcf050d44b7b0e766babbfda8fadac59f /packages/meshbay-node/tests/test_title_parse.py | |
| parent | b6e2dcea65124673da047f9b3c92bc5e25980d63 (diff) | |
| parent | 0b0da86f1f9d6f0b1a27b5e1e1658c42de9f356a (diff) | |
| download | meshbay-317f09328ed8bf20148b707470c9b0fe82e59575.tar.gz | |
Merge branch 'docs/mediacenter-videos-app': Videos group app
Poster grid / flat list browsing, TMDB metadata enrichment, thumbnail
generation and caching, season-specific overviews, manual match
correction, and the create-group wizard's app-selection step.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LAmyXtc6dAADsH23ydXQpY
Diffstat (limited to 'packages/meshbay-node/tests/test_title_parse.py')
| -rw-r--r-- | packages/meshbay-node/tests/test_title_parse.py | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/packages/meshbay-node/tests/test_title_parse.py b/packages/meshbay-node/tests/test_title_parse.py new file mode 100644 index 0000000..1a277f2 --- /dev/null +++ b/packages/meshbay-node/tests/test_title_parse.py @@ -0,0 +1,129 @@ +""" +Tests for indexer/title_parse.py — synthetic filenames only, one per +docs/mediacenter.md §3.3/§3.4 rule. The real ~1950-file library validation +is a manual acceptance step (§11), not something this repo's corpus holds. +""" + +from meshbay_node.indexer.title_parse import ( + ParsedName, + naive_title, + parse_episode_filename, + parse_movie_filename, + season_from_folder_name, + sequel_variants, +) + + +# ── §3.3 row: plain, well-formed movie filename ────────────────────────────── + +def test_plain_movie_filename_parses_confidently(): + r = parse_movie_filename("The.Great.Adventure.2015.1080p.BluRay.x264.mkv") + assert r.display_title == "The Great Adventure" + assert r.year == 2015 + assert r.confidence is True + + +# ── §3.3 row 1: real title in alternative_title ────────────────────────────── + +def test_franchise_numeric_code_exposes_alternative_title(): + r = parse_movie_filename("Franchise.007.-.The.Real.Subtitle.1999.720p.mkv") + assert r.year == 1999 + # guessit lands the franchise fragment in title and the real subtitle in + # alternative_title — both must be surfaced so a caller (tmdb.py) can + # try either, per the design doc's "search both fields" fix. + assert r.alt_title is not None + + +# ── §3.3 row 2: hyphenated title split before a parenthesized year ─────────── + +def test_naive_title_normalizes_hyphens_dots_and_underscores(): + nt = naive_title("Hero-Name.(2002).DVDRip.XviD-GROUP.avi") + assert "-" not in nt + assert "." not in nt + assert "_" not in nt + assert "2002" not in nt # the year itself is stripped, not just its parens + assert "Hero" in nt and "Name" in nt + + +# ── §3.3 row 3: French edition vocabulary stuck to the title ───────────────── + +def test_french_edition_phrases_are_stripped(): + r = parse_movie_filename("Some.Movie.Version.Longue.2010.mkv") + assert "version" not in (r.display_title or "").lower() + assert "longue" not in (r.display_title or "").lower() + + r2 = parse_movie_filename("Autre.Film.Remasterise.1998.mkv") + assert "remasteris" not in (r2.display_title or "").lower() + + +# ── §3.3 row 4: trailing sequel digit / Roman numeral ──────────────────────── + +def test_sequel_variants_strips_digit_and_offers_roman_numeral(): + variants = sequel_variants("Some Sequel 2") + assert "Some Sequel" in variants + assert "Some Sequel II" in variants + + +def test_sequel_variants_empty_when_no_trailing_digit(): + assert sequel_variants("Some Movie") == [] + + +# ── §3.3 row 6: no usable title at all ─────────────────────────────────────── + +def test_low_confidence_when_no_title_or_year(): + r = parse_movie_filename("abc123.mkv") + assert r.confidence is False + # the mandated fallback is always available regardless + assert r.naive_title == "abc123" + + +# ── §3.2/§3.4: episode filename with no show name at all ───────────────────── + +def test_episode_only_filename_has_no_title_but_has_season_episode(): + r = parse_episode_filename("S08E02.SUBFRENCH.720p.mkv") + assert r.display_title is None + assert r.season == 8 + assert r.episode == 2 + # confidence is False (no title yet) — the indexer must supply one from + # a representative sibling filename in the same folder, per §3.4. + assert r.confidence is False + + +def test_episode_filename_with_show_name_parses_confidently(): + r = parse_episode_filename("Some.Show.Name.S02E05.720p.WEB.mkv") + assert r.display_title == "Some Show Name" + assert r.season == 2 + assert r.episode == 5 + assert r.confidence is True + + +# ── §3.4: season-like ancestor folders, including non-English vocabulary ──── + +def test_season_folder_english(): + assert season_from_folder_name("Season 2") == 2 + + +def test_season_folder_french_word(): + assert season_from_folder_name("Saison 3") == 3 + + +def test_season_folder_roman_numeral(): + assert season_from_folder_name("Saison IV") == 4 + + +def test_specials_folder_maps_to_season_zero(): + assert season_from_folder_name("Specials") == 0 + assert season_from_folder_name("Bonus") == 0 + assert season_from_folder_name("Extras") == 0 + + +def test_non_season_folder_name_returns_none(): + assert season_from_folder_name("Some Show Name") 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. + p = ParsedName(display_title=None) + assert p.confidence is False + assert p.naive_title == "" |