aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/tests/test_enrich.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-node/tests/test_enrich.py')
-rw-r--r--packages/meshbay-node/tests/test_enrich.py113
1 files changed, 69 insertions, 44 deletions
diff --git a/packages/meshbay-node/tests/test_enrich.py b/packages/meshbay-node/tests/test_enrich.py
index 5497812..8c0c6b2 100644
--- a/packages/meshbay-node/tests/test_enrich.py
+++ b/packages/meshbay-node/tests/test_enrich.py
@@ -9,8 +9,8 @@ import pytest
from meshbay_common.protocol import IndexEntry
from meshbay_node.indexer.enrich import (
- Enricher, _season_from_ancestors, _synthetic_episode_number,
- _title_from_show_siblings, _title_from_siblings,
+ Enricher, _season_and_show_from_ancestors, _synthetic_episode_number,
+ _title_from_siblings,
)
from meshbay_node.media_cache import MediaCache
@@ -19,22 +19,48 @@ _HAVE_FFMPEG = shutil.which("ffmpeg") and shutil.which("ffprobe")
# ── pure helpers, no ffmpeg needed ───────────────────────────────────────────
-def test_season_from_ancestors_finds_season_folder(tmp_path):
+def test_season_and_show_from_ancestors_finds_season_folder(tmp_path):
folder = tmp_path / "Some Show" / "Season 2"
folder.mkdir(parents=True)
ep = folder / "01 - Episode Title.mkv"
ep.touch()
- assert _season_from_ancestors(ep) == 2
+ assert _season_and_show_from_ancestors(ep) == (2, "Some Show")
-def test_season_from_ancestors_none_when_no_season_folder(tmp_path):
+def test_season_and_show_from_ancestors_none_when_no_season_folder(tmp_path):
folder = tmp_path / "Movies"
folder.mkdir()
f = folder / "Some Movie 2015.mkv"
f.touch()
- assert _season_from_ancestors(f) is None
+ assert _season_and_show_from_ancestors(f) is None
+
+
+def test_season_and_show_from_ancestors_walks_past_a_per_season_bonus_folder(tmp_path):
+ # The real shape this guards: a Specials/Bonus folder nested *inside*
+ # each numbered season folder (Show/Season N/Bonus/file.ext) rather
+ # than once at the show's top level — both "Bonus" and "Season N" are
+ # season-like on their own, and stopping at the first (innermost)
+ # would hand back "Season N" as the show's name instead of "Show".
+ folder = tmp_path / "Some Show" / "Season 1" / "Bonus"
+ folder.mkdir(parents=True)
+ f = folder / "One-Off Bonus Title.mkv"
+ f.touch()
+
+ assert _season_and_show_from_ancestors(f) == (0, "Some Show")
+
+
+def test_season_and_show_from_ancestors_book_word_season_folder(tmp_path):
+ # Same shape as the real bug this whole fix guards, with the "book"
+ # season vocabulary (§3.4) instead of "season"/"saison": a plain
+ # numbered-episode folder nested under it.
+ folder = tmp_path / "Some Show" / "Livre I" / "Episodes"
+ folder.mkdir(parents=True)
+ f = folder / "001 Episode's Own Title.mkv"
+ f.touch()
+
+ assert _season_and_show_from_ancestors(f) == (1, "Some Show")
def test_title_from_siblings_borrows_from_a_titled_sibling(tmp_path):
@@ -67,44 +93,6 @@ def test_title_from_siblings_ignores_a_titled_sibling_with_no_episode_number(tmp
assert _title_from_siblings(folder / "Bonus Feature Two.mkv") is None
-def test_title_from_show_siblings_borrows_from_a_sibling_season_folder(tmp_path):
- show = tmp_path / "Some Show"
- specials = show / "Specials"
- specials.mkdir(parents=True)
- (specials / "Bonus Feature One.mkv").touch()
- season1 = show / "Season 1"
- season1.mkdir()
- (season1 / "Some Show.S01E01.mkv").touch()
-
- assert _title_from_show_siblings(specials / "Bonus Feature One.mkv") == "Some Show"
-
-
-def test_title_from_show_siblings_none_when_no_show_folder_has_one(tmp_path):
- show = tmp_path / "Some Show"
- specials = show / "Specials"
- specials.mkdir(parents=True)
- (specials / "Bonus Feature One.mkv").touch()
- (specials / "Bonus Feature Two.mkv").touch()
-
- assert _title_from_show_siblings(specials / "Bonus Feature One.mkv") is None
-
-
-def test_title_from_show_siblings_not_specific_to_the_word_specials(tmp_path):
- # Genericity check: the same gap (a season-like folder whose files carry
- # no episode grammar of their own) can show up under a plain numbered
- # season folder too, not only one named "Specials" — nothing in
- # _title_from_show_siblings should assume otherwise.
- show = tmp_path / "Some Show"
- season2 = show / "Season 2"
- season2.mkdir(parents=True)
- (season2 / "One-Off Episode Title.mkv").touch()
- season1 = show / "Season 1"
- season1.mkdir()
- (season1 / "Some Show.S01E01.mkv").touch()
-
- assert _title_from_show_siblings(season2 / "One-Off Episode Title.mkv") == "Some Show"
-
-
def test_synthetic_episode_number_is_stable_alphabetical_rank(tmp_path):
folder = tmp_path / "Specials"
folder.mkdir()
@@ -298,3 +286,40 @@ async def test_enricher_handles_specials_folder_with_no_episode_grammar(tmp_path
assert fields["display_title"] == "Some Show"
assert fields["season"] == 0
assert fields["episode"] is not None
+
+
+@pytestmark_ffmpeg
+@pytest.mark.asyncio
+async def test_enricher_groups_bare_numbered_episodes_under_the_show_folder(tmp_path, media_cache):
+ """
+ The real-world shape this whole fix is for: every episode (and every
+ Bonus feature) named "<number> <its own one-off title>", with the
+ show's name appearing nowhere in any filename at all — only in the
+ show's own root folder. guessit still finds an episode number here
+ (unlike the plain-Specials case above), and invents a "title" from
+ whatever text follows it — a different one for every file. Trusting
+ that per-file title, as the code used to, groups nothing together at
+ all: every episode becomes its own single-episode "show", searched
+ against TMDB by its own one-off title, and mismatched to whichever
+ unrelated real film or show happens to share it.
+ """
+ show = tmp_path / "Some Show"
+ season1_eps = show / "Livre I" / "Episodes"
+ season1_eps.mkdir(parents=True)
+ (season1_eps / "001 First Episode's Own Title.mkv").touch()
+ clip = season1_eps / "002 Second Episode's Own Title.mkv"
+ _make_clip(clip)
+ season2_eps = show / "Livre II" / "Episodes"
+ season2_eps.mkdir(parents=True)
+ (season2_eps / "001 A Season 2 Episode's Own Title.mkv").touch()
+ entry = IndexEntry(id="fileid4", name=clip.name, path=str(clip.relative_to(tmp_path)),
+ size=clip.stat().st_size, type="video", added_at=0)
+
+ enricher = Enricher(media_cache)
+ _, fields = await _run(enricher, entry, clip)
+
+ # Not "Second Episode's Own Title" — every episode has a different
+ # one, and none of them is the show.
+ assert fields["display_title"] == "Some Show"
+ assert fields["season"] == 1
+ assert fields["episode"] == 2