diff --git a/bdpl/analyze/__init__.py b/bdpl/analyze/__init__.py
index a359b2f..1f4dcc0 100644
--- a/bdpl/analyze/__init__.py
+++ b/bdpl/analyze/__init__.py
@@ -365,8 +365,15 @@ def _detect_special_features(
if pl is None:
continue
category = classifications.get(mpls, "extra")
- if category in {"episode", "play_all"}:
+ if category == "play_all":
continue
+ # An "episode" playlist not used as an actual episode source
+ # (episodes came from play_all decomposition) is a commentary
+ # or alternate-audio track.
+ if category == "episode":
+ if mpls in ep_playlists:
+ continue
+ category = "commentary"
new_features = _build_chapter_split_features(
pl,
@@ -379,6 +386,13 @@ def _detect_special_features(
features.extend(new_features)
idx += len(new_features)
+ # A special whose classification is "episode" (individual playlist that
+ # was bypassed in favour of play_all decomposition) is really a
+ # commentary / alternate-audio track, not a distinct episode.
+ for f in features:
+ if f.category == "episode":
+ f.category = "commentary"
+
return features
diff --git a/bdpl/analyze/ordering.py b/bdpl/analyze/ordering.py
index 9b2e7df..7a49282 100644
--- a/bdpl/analyze/ordering.py
+++ b/bdpl/analyze/ordering.py
@@ -266,10 +266,18 @@ def order_episodes(
if individual_eps and pa_episodes:
avg_indiv = sum(p.duration_ms for p in individual_eps) / len(individual_eps)
avg_pa = sum(e.duration_ms for e in pa_episodes) / len(pa_episodes) if pa_episodes else 0
- # If Play All yields more episodes whose average duration is much
- # longer, the individual playlists are probably extras, not episodes.
- if len(pa_episodes) > len(individual_eps) and avg_pa > avg_indiv * 1.5:
- return pa_episodes
+ if len(pa_episodes) > len(individual_eps):
+ # If individual episode clips are a strict subset of the
+ # play_all clips, the individual playlists only cover some
+ # episodes (the rest are play_all-only). Use play_all.
+ indiv_clips = {pi.clip_id for p in individual_eps for pi in p.play_items}
+ pa_clips = {seg.clip_id for ep in pa_episodes for seg in ep.segments}
+ if indiv_clips <= pa_clips:
+ return pa_episodes
+ # If Play All episodes are much longer on average, the
+ # individual playlists are probably extras, not episodes.
+ if avg_pa > avg_indiv * 1.5:
+ return pa_episodes
return _episodes_from_individual(individual_eps)
if individual_eps:
diff --git a/tests/conftest.py b/tests/conftest.py
index 08ba101..85c5bcb 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -160,6 +160,54 @@ def disc9_analysis(disc9_path):
return _analyze_fixture(disc9_path)
+@pytest.fixture(scope="session")
+def disc10_path() -> Path:
+ """Return path to bundled disc10 fixture."""
+ return _fixture_path("disc10")
+
+
+@pytest.fixture(scope="session")
+def disc10_analysis(disc10_path):
+ """Run and cache full analysis for the bundled disc10 fixture."""
+ return _analyze_fixture(disc10_path)
+
+
+@pytest.fixture(scope="session")
+def disc11_path() -> Path:
+ """Return path to bundled disc11 fixture."""
+ return _fixture_path("disc11")
+
+
+@pytest.fixture(scope="session")
+def disc11_analysis(disc11_path):
+ """Run and cache full analysis for the bundled disc11 fixture."""
+ return _analyze_fixture(disc11_path)
+
+
+@pytest.fixture(scope="session")
+def disc12_path() -> Path:
+ """Return path to bundled disc12 fixture."""
+ return _fixture_path("disc12")
+
+
+@pytest.fixture(scope="session")
+def disc12_analysis(disc12_path):
+ """Run and cache full analysis for the bundled disc12 fixture."""
+ return _analyze_fixture(disc12_path)
+
+
+@pytest.fixture(scope="session")
+def disc13_path() -> Path:
+ """Return path to bundled disc13 fixture."""
+ return _fixture_path("disc13")
+
+
+@pytest.fixture(scope="session")
+def disc13_analysis(disc13_path):
+ """Run and cache full analysis for the bundled disc13 fixture."""
+ return _analyze_fixture(disc13_path)
+
+
@pytest.fixture
def cli_runner() -> Callable[..., subprocess.CompletedProcess[str]]:
"""Return helper to invoke `python -m bdpl.cli` consistently in tests."""
diff --git a/tests/fixtures/disc10/CLIPINF/00000.clpi b/tests/fixtures/disc10/CLIPINF/00000.clpi
new file mode 100644
index 0000000..3cb2f61
Binary files /dev/null and b/tests/fixtures/disc10/CLIPINF/00000.clpi differ
diff --git a/tests/fixtures/disc10/CLIPINF/00001.clpi b/tests/fixtures/disc10/CLIPINF/00001.clpi
new file mode 100644
index 0000000..be8e532
Binary files /dev/null and b/tests/fixtures/disc10/CLIPINF/00001.clpi differ
diff --git a/tests/fixtures/disc10/CLIPINF/00002.clpi b/tests/fixtures/disc10/CLIPINF/00002.clpi
new file mode 100644
index 0000000..aa2ffbb
Binary files /dev/null and b/tests/fixtures/disc10/CLIPINF/00002.clpi differ
diff --git a/tests/fixtures/disc10/CLIPINF/00003.clpi b/tests/fixtures/disc10/CLIPINF/00003.clpi
new file mode 100644
index 0000000..2fb99ee
Binary files /dev/null and b/tests/fixtures/disc10/CLIPINF/00003.clpi differ
diff --git a/tests/fixtures/disc10/CLIPINF/00004.clpi b/tests/fixtures/disc10/CLIPINF/00004.clpi
new file mode 100644
index 0000000..4db621b
Binary files /dev/null and b/tests/fixtures/disc10/CLIPINF/00004.clpi differ
diff --git a/tests/fixtures/disc10/CLIPINF/00005.clpi b/tests/fixtures/disc10/CLIPINF/00005.clpi
new file mode 100644
index 0000000..5fa92bf
Binary files /dev/null and b/tests/fixtures/disc10/CLIPINF/00005.clpi differ
diff --git a/tests/fixtures/disc10/CLIPINF/00006.clpi b/tests/fixtures/disc10/CLIPINF/00006.clpi
new file mode 100644
index 0000000..6bd0678
Binary files /dev/null and b/tests/fixtures/disc10/CLIPINF/00006.clpi differ
diff --git a/tests/fixtures/disc10/CLIPINF/00007.clpi b/tests/fixtures/disc10/CLIPINF/00007.clpi
new file mode 100644
index 0000000..67f7799
Binary files /dev/null and b/tests/fixtures/disc10/CLIPINF/00007.clpi differ
diff --git a/tests/fixtures/disc10/CLIPINF/00008.clpi b/tests/fixtures/disc10/CLIPINF/00008.clpi
new file mode 100644
index 0000000..1b0e797
Binary files /dev/null and b/tests/fixtures/disc10/CLIPINF/00008.clpi differ
diff --git a/tests/fixtures/disc10/CLIPINF/00009.clpi b/tests/fixtures/disc10/CLIPINF/00009.clpi
new file mode 100644
index 0000000..5909ed6
Binary files /dev/null and b/tests/fixtures/disc10/CLIPINF/00009.clpi differ
diff --git a/tests/fixtures/disc10/CLIPINF/00010.clpi b/tests/fixtures/disc10/CLIPINF/00010.clpi
new file mode 100644
index 0000000..d19cb06
Binary files /dev/null and b/tests/fixtures/disc10/CLIPINF/00010.clpi differ
diff --git a/tests/fixtures/disc10/CLIPINF/00011.clpi b/tests/fixtures/disc10/CLIPINF/00011.clpi
new file mode 100644
index 0000000..05eeb21
Binary files /dev/null and b/tests/fixtures/disc10/CLIPINF/00011.clpi differ
diff --git a/tests/fixtures/disc10/META/DL/bdmt_eng.xml b/tests/fixtures/disc10/META/DL/bdmt_eng.xml
new file mode 100644
index 0000000..9c8575e
--- /dev/null
+++ b/tests/fixtures/disc10/META/DL/bdmt_eng.xml
@@ -0,0 +1,9 @@
+
+
+
+
+ TEST DISC 10
+
+
+
diff --git a/tests/fixtures/disc10/MovieObject.bdmv b/tests/fixtures/disc10/MovieObject.bdmv
new file mode 100644
index 0000000..039dd35
Binary files /dev/null and b/tests/fixtures/disc10/MovieObject.bdmv differ
diff --git a/tests/fixtures/disc10/PLAYLIST/00000.mpls b/tests/fixtures/disc10/PLAYLIST/00000.mpls
new file mode 100644
index 0000000..3e9593d
Binary files /dev/null and b/tests/fixtures/disc10/PLAYLIST/00000.mpls differ
diff --git a/tests/fixtures/disc10/PLAYLIST/00001.mpls b/tests/fixtures/disc10/PLAYLIST/00001.mpls
new file mode 100644
index 0000000..eae4e65
Binary files /dev/null and b/tests/fixtures/disc10/PLAYLIST/00001.mpls differ
diff --git a/tests/fixtures/disc10/PLAYLIST/00002.mpls b/tests/fixtures/disc10/PLAYLIST/00002.mpls
new file mode 100644
index 0000000..3af0ebe
Binary files /dev/null and b/tests/fixtures/disc10/PLAYLIST/00002.mpls differ
diff --git a/tests/fixtures/disc10/PLAYLIST/00003.mpls b/tests/fixtures/disc10/PLAYLIST/00003.mpls
new file mode 100644
index 0000000..14163ce
Binary files /dev/null and b/tests/fixtures/disc10/PLAYLIST/00003.mpls differ
diff --git a/tests/fixtures/disc10/PLAYLIST/00004.mpls b/tests/fixtures/disc10/PLAYLIST/00004.mpls
new file mode 100644
index 0000000..0f9e867
Binary files /dev/null and b/tests/fixtures/disc10/PLAYLIST/00004.mpls differ
diff --git a/tests/fixtures/disc10/PLAYLIST/00005.mpls b/tests/fixtures/disc10/PLAYLIST/00005.mpls
new file mode 100644
index 0000000..7e055ed
Binary files /dev/null and b/tests/fixtures/disc10/PLAYLIST/00005.mpls differ
diff --git a/tests/fixtures/disc10/ics_menu.bin b/tests/fixtures/disc10/ics_menu.bin
new file mode 100644
index 0000000..c6257da
Binary files /dev/null and b/tests/fixtures/disc10/ics_menu.bin differ
diff --git a/tests/fixtures/disc10/index.bdmv b/tests/fixtures/disc10/index.bdmv
new file mode 100644
index 0000000..5796e01
Binary files /dev/null and b/tests/fixtures/disc10/index.bdmv differ
diff --git a/tests/fixtures/disc11/CLIPINF/00000.clpi b/tests/fixtures/disc11/CLIPINF/00000.clpi
new file mode 100644
index 0000000..3cb2f61
Binary files /dev/null and b/tests/fixtures/disc11/CLIPINF/00000.clpi differ
diff --git a/tests/fixtures/disc11/CLIPINF/00001.clpi b/tests/fixtures/disc11/CLIPINF/00001.clpi
new file mode 100644
index 0000000..be8e532
Binary files /dev/null and b/tests/fixtures/disc11/CLIPINF/00001.clpi differ
diff --git a/tests/fixtures/disc11/CLIPINF/00002.clpi b/tests/fixtures/disc11/CLIPINF/00002.clpi
new file mode 100644
index 0000000..aa2ffbb
Binary files /dev/null and b/tests/fixtures/disc11/CLIPINF/00002.clpi differ
diff --git a/tests/fixtures/disc11/CLIPINF/00003.clpi b/tests/fixtures/disc11/CLIPINF/00003.clpi
new file mode 100644
index 0000000..2fb99ee
Binary files /dev/null and b/tests/fixtures/disc11/CLIPINF/00003.clpi differ
diff --git a/tests/fixtures/disc11/CLIPINF/00004.clpi b/tests/fixtures/disc11/CLIPINF/00004.clpi
new file mode 100644
index 0000000..c1fbe35
Binary files /dev/null and b/tests/fixtures/disc11/CLIPINF/00004.clpi differ
diff --git a/tests/fixtures/disc11/CLIPINF/00005.clpi b/tests/fixtures/disc11/CLIPINF/00005.clpi
new file mode 100644
index 0000000..5fa92bf
Binary files /dev/null and b/tests/fixtures/disc11/CLIPINF/00005.clpi differ
diff --git a/tests/fixtures/disc11/CLIPINF/00006.clpi b/tests/fixtures/disc11/CLIPINF/00006.clpi
new file mode 100644
index 0000000..14adffb
Binary files /dev/null and b/tests/fixtures/disc11/CLIPINF/00006.clpi differ
diff --git a/tests/fixtures/disc11/CLIPINF/00007.clpi b/tests/fixtures/disc11/CLIPINF/00007.clpi
new file mode 100644
index 0000000..9b4bc34
Binary files /dev/null and b/tests/fixtures/disc11/CLIPINF/00007.clpi differ
diff --git a/tests/fixtures/disc11/CLIPINF/00008.clpi b/tests/fixtures/disc11/CLIPINF/00008.clpi
new file mode 100644
index 0000000..c594a24
Binary files /dev/null and b/tests/fixtures/disc11/CLIPINF/00008.clpi differ
diff --git a/tests/fixtures/disc11/CLIPINF/00009.clpi b/tests/fixtures/disc11/CLIPINF/00009.clpi
new file mode 100644
index 0000000..f1d9b23
Binary files /dev/null and b/tests/fixtures/disc11/CLIPINF/00009.clpi differ
diff --git a/tests/fixtures/disc11/CLIPINF/00010.clpi b/tests/fixtures/disc11/CLIPINF/00010.clpi
new file mode 100644
index 0000000..dd44a8a
Binary files /dev/null and b/tests/fixtures/disc11/CLIPINF/00010.clpi differ
diff --git a/tests/fixtures/disc11/CLIPINF/00011.clpi b/tests/fixtures/disc11/CLIPINF/00011.clpi
new file mode 100644
index 0000000..6b1f9b9
Binary files /dev/null and b/tests/fixtures/disc11/CLIPINF/00011.clpi differ
diff --git a/tests/fixtures/disc11/CLIPINF/00012.clpi b/tests/fixtures/disc11/CLIPINF/00012.clpi
new file mode 100644
index 0000000..a8ee62c
Binary files /dev/null and b/tests/fixtures/disc11/CLIPINF/00012.clpi differ
diff --git a/tests/fixtures/disc11/CLIPINF/00013.clpi b/tests/fixtures/disc11/CLIPINF/00013.clpi
new file mode 100644
index 0000000..5207422
Binary files /dev/null and b/tests/fixtures/disc11/CLIPINF/00013.clpi differ
diff --git a/tests/fixtures/disc11/META/DL/bdmt_eng.xml b/tests/fixtures/disc11/META/DL/bdmt_eng.xml
new file mode 100644
index 0000000..6dcc7ca
--- /dev/null
+++ b/tests/fixtures/disc11/META/DL/bdmt_eng.xml
@@ -0,0 +1,9 @@
+
+
+
+
+ TEST DISC 11
+
+
+
diff --git a/tests/fixtures/disc11/MovieObject.bdmv b/tests/fixtures/disc11/MovieObject.bdmv
new file mode 100644
index 0000000..8d37449
Binary files /dev/null and b/tests/fixtures/disc11/MovieObject.bdmv differ
diff --git a/tests/fixtures/disc11/PLAYLIST/00000.mpls b/tests/fixtures/disc11/PLAYLIST/00000.mpls
new file mode 100644
index 0000000..3e9593d
Binary files /dev/null and b/tests/fixtures/disc11/PLAYLIST/00000.mpls differ
diff --git a/tests/fixtures/disc11/PLAYLIST/00001.mpls b/tests/fixtures/disc11/PLAYLIST/00001.mpls
new file mode 100644
index 0000000..eae4e65
Binary files /dev/null and b/tests/fixtures/disc11/PLAYLIST/00001.mpls differ
diff --git a/tests/fixtures/disc11/PLAYLIST/00002.mpls b/tests/fixtures/disc11/PLAYLIST/00002.mpls
new file mode 100644
index 0000000..52dba41
Binary files /dev/null and b/tests/fixtures/disc11/PLAYLIST/00002.mpls differ
diff --git a/tests/fixtures/disc11/PLAYLIST/00003.mpls b/tests/fixtures/disc11/PLAYLIST/00003.mpls
new file mode 100644
index 0000000..2dda935
Binary files /dev/null and b/tests/fixtures/disc11/PLAYLIST/00003.mpls differ
diff --git a/tests/fixtures/disc11/ics_menu.bin b/tests/fixtures/disc11/ics_menu.bin
new file mode 100644
index 0000000..24c8cb8
Binary files /dev/null and b/tests/fixtures/disc11/ics_menu.bin differ
diff --git a/tests/fixtures/disc11/index.bdmv b/tests/fixtures/disc11/index.bdmv
new file mode 100644
index 0000000..cee9035
Binary files /dev/null and b/tests/fixtures/disc11/index.bdmv differ
diff --git a/tests/fixtures/disc12/CLIPINF/00000.clpi b/tests/fixtures/disc12/CLIPINF/00000.clpi
new file mode 100644
index 0000000..3cb2f61
Binary files /dev/null and b/tests/fixtures/disc12/CLIPINF/00000.clpi differ
diff --git a/tests/fixtures/disc12/CLIPINF/00001.clpi b/tests/fixtures/disc12/CLIPINF/00001.clpi
new file mode 100644
index 0000000..be8e532
Binary files /dev/null and b/tests/fixtures/disc12/CLIPINF/00001.clpi differ
diff --git a/tests/fixtures/disc12/CLIPINF/00002.clpi b/tests/fixtures/disc12/CLIPINF/00002.clpi
new file mode 100644
index 0000000..aa2ffbb
Binary files /dev/null and b/tests/fixtures/disc12/CLIPINF/00002.clpi differ
diff --git a/tests/fixtures/disc12/CLIPINF/00003.clpi b/tests/fixtures/disc12/CLIPINF/00003.clpi
new file mode 100644
index 0000000..a928f19
Binary files /dev/null and b/tests/fixtures/disc12/CLIPINF/00003.clpi differ
diff --git a/tests/fixtures/disc12/CLIPINF/00004.clpi b/tests/fixtures/disc12/CLIPINF/00004.clpi
new file mode 100644
index 0000000..4db621b
Binary files /dev/null and b/tests/fixtures/disc12/CLIPINF/00004.clpi differ
diff --git a/tests/fixtures/disc12/CLIPINF/00005.clpi b/tests/fixtures/disc12/CLIPINF/00005.clpi
new file mode 100644
index 0000000..5fa92bf
Binary files /dev/null and b/tests/fixtures/disc12/CLIPINF/00005.clpi differ
diff --git a/tests/fixtures/disc12/CLIPINF/00006.clpi b/tests/fixtures/disc12/CLIPINF/00006.clpi
new file mode 100644
index 0000000..4142e2f
Binary files /dev/null and b/tests/fixtures/disc12/CLIPINF/00006.clpi differ
diff --git a/tests/fixtures/disc12/CLIPINF/00007.clpi b/tests/fixtures/disc12/CLIPINF/00007.clpi
new file mode 100644
index 0000000..6029198
Binary files /dev/null and b/tests/fixtures/disc12/CLIPINF/00007.clpi differ
diff --git a/tests/fixtures/disc12/CLIPINF/00008.clpi b/tests/fixtures/disc12/CLIPINF/00008.clpi
new file mode 100644
index 0000000..e3a7fe8
Binary files /dev/null and b/tests/fixtures/disc12/CLIPINF/00008.clpi differ
diff --git a/tests/fixtures/disc12/CLIPINF/00009.clpi b/tests/fixtures/disc12/CLIPINF/00009.clpi
new file mode 100644
index 0000000..36e0ed9
Binary files /dev/null and b/tests/fixtures/disc12/CLIPINF/00009.clpi differ
diff --git a/tests/fixtures/disc12/CLIPINF/00010.clpi b/tests/fixtures/disc12/CLIPINF/00010.clpi
new file mode 100644
index 0000000..83d4ccd
Binary files /dev/null and b/tests/fixtures/disc12/CLIPINF/00010.clpi differ
diff --git a/tests/fixtures/disc12/CLIPINF/00011.clpi b/tests/fixtures/disc12/CLIPINF/00011.clpi
new file mode 100644
index 0000000..05eeb21
Binary files /dev/null and b/tests/fixtures/disc12/CLIPINF/00011.clpi differ
diff --git a/tests/fixtures/disc12/META/DL/bdmt_eng.xml b/tests/fixtures/disc12/META/DL/bdmt_eng.xml
new file mode 100644
index 0000000..332de4c
--- /dev/null
+++ b/tests/fixtures/disc12/META/DL/bdmt_eng.xml
@@ -0,0 +1,9 @@
+
+
+
+
+ TEST DISC 12
+
+
+
diff --git a/tests/fixtures/disc12/MovieObject.bdmv b/tests/fixtures/disc12/MovieObject.bdmv
new file mode 100644
index 0000000..039dd35
Binary files /dev/null and b/tests/fixtures/disc12/MovieObject.bdmv differ
diff --git a/tests/fixtures/disc12/PLAYLIST/00000.mpls b/tests/fixtures/disc12/PLAYLIST/00000.mpls
new file mode 100644
index 0000000..3e9593d
Binary files /dev/null and b/tests/fixtures/disc12/PLAYLIST/00000.mpls differ
diff --git a/tests/fixtures/disc12/PLAYLIST/00001.mpls b/tests/fixtures/disc12/PLAYLIST/00001.mpls
new file mode 100644
index 0000000..eae4e65
Binary files /dev/null and b/tests/fixtures/disc12/PLAYLIST/00001.mpls differ
diff --git a/tests/fixtures/disc12/PLAYLIST/00002.mpls b/tests/fixtures/disc12/PLAYLIST/00002.mpls
new file mode 100644
index 0000000..e0d3e25
Binary files /dev/null and b/tests/fixtures/disc12/PLAYLIST/00002.mpls differ
diff --git a/tests/fixtures/disc12/PLAYLIST/00003.mpls b/tests/fixtures/disc12/PLAYLIST/00003.mpls
new file mode 100644
index 0000000..72b99f4
Binary files /dev/null and b/tests/fixtures/disc12/PLAYLIST/00003.mpls differ
diff --git a/tests/fixtures/disc12/PLAYLIST/00004.mpls b/tests/fixtures/disc12/PLAYLIST/00004.mpls
new file mode 100644
index 0000000..d584fc4
Binary files /dev/null and b/tests/fixtures/disc12/PLAYLIST/00004.mpls differ
diff --git a/tests/fixtures/disc12/PLAYLIST/00005.mpls b/tests/fixtures/disc12/PLAYLIST/00005.mpls
new file mode 100644
index 0000000..dedcacf
Binary files /dev/null and b/tests/fixtures/disc12/PLAYLIST/00005.mpls differ
diff --git a/tests/fixtures/disc12/ics_menu.bin b/tests/fixtures/disc12/ics_menu.bin
new file mode 100644
index 0000000..19b76b2
Binary files /dev/null and b/tests/fixtures/disc12/ics_menu.bin differ
diff --git a/tests/fixtures/disc12/index.bdmv b/tests/fixtures/disc12/index.bdmv
new file mode 100644
index 0000000..5796e01
Binary files /dev/null and b/tests/fixtures/disc12/index.bdmv differ
diff --git a/tests/fixtures/disc13/CLIPINF/00000.clpi b/tests/fixtures/disc13/CLIPINF/00000.clpi
new file mode 100644
index 0000000..3cb2f61
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00000.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00001.clpi b/tests/fixtures/disc13/CLIPINF/00001.clpi
new file mode 100644
index 0000000..be8e532
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00001.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00002.clpi b/tests/fixtures/disc13/CLIPINF/00002.clpi
new file mode 100644
index 0000000..aa2ffbb
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00002.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00003.clpi b/tests/fixtures/disc13/CLIPINF/00003.clpi
new file mode 100644
index 0000000..ef71722
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00003.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00004.clpi b/tests/fixtures/disc13/CLIPINF/00004.clpi
new file mode 100644
index 0000000..1898dda
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00004.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00005.clpi b/tests/fixtures/disc13/CLIPINF/00005.clpi
new file mode 100644
index 0000000..5fa92bf
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00005.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00006.clpi b/tests/fixtures/disc13/CLIPINF/00006.clpi
new file mode 100644
index 0000000..9ccf866
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00006.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00007.clpi b/tests/fixtures/disc13/CLIPINF/00007.clpi
new file mode 100644
index 0000000..1e7e10c
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00007.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00008.clpi b/tests/fixtures/disc13/CLIPINF/00008.clpi
new file mode 100644
index 0000000..81cbee1
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00008.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00009.clpi b/tests/fixtures/disc13/CLIPINF/00009.clpi
new file mode 100644
index 0000000..4ecf3f7
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00009.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00010.clpi b/tests/fixtures/disc13/CLIPINF/00010.clpi
new file mode 100644
index 0000000..2ba9054
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00010.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00011.clpi b/tests/fixtures/disc13/CLIPINF/00011.clpi
new file mode 100644
index 0000000..329243d
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00011.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00012.clpi b/tests/fixtures/disc13/CLIPINF/00012.clpi
new file mode 100644
index 0000000..e70da3f
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00012.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00013.clpi b/tests/fixtures/disc13/CLIPINF/00013.clpi
new file mode 100644
index 0000000..006e58d
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00013.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00014.clpi b/tests/fixtures/disc13/CLIPINF/00014.clpi
new file mode 100644
index 0000000..f53fcaf
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00014.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00015.clpi b/tests/fixtures/disc13/CLIPINF/00015.clpi
new file mode 100644
index 0000000..2d51142
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00015.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00016.clpi b/tests/fixtures/disc13/CLIPINF/00016.clpi
new file mode 100644
index 0000000..c6f486a
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00016.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00017.clpi b/tests/fixtures/disc13/CLIPINF/00017.clpi
new file mode 100644
index 0000000..17d82c5
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00017.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00018.clpi b/tests/fixtures/disc13/CLIPINF/00018.clpi
new file mode 100644
index 0000000..9187c02
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00018.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00019.clpi b/tests/fixtures/disc13/CLIPINF/00019.clpi
new file mode 100644
index 0000000..fdde136
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00019.clpi differ
diff --git a/tests/fixtures/disc13/CLIPINF/00020.clpi b/tests/fixtures/disc13/CLIPINF/00020.clpi
new file mode 100644
index 0000000..2591ee1
Binary files /dev/null and b/tests/fixtures/disc13/CLIPINF/00020.clpi differ
diff --git a/tests/fixtures/disc13/META/DL/bdmt_eng.xml b/tests/fixtures/disc13/META/DL/bdmt_eng.xml
new file mode 100644
index 0000000..32b1c66
--- /dev/null
+++ b/tests/fixtures/disc13/META/DL/bdmt_eng.xml
@@ -0,0 +1,6 @@
+
+
+
+TEST DISC 13
+
+
diff --git a/tests/fixtures/disc13/MovieObject.bdmv b/tests/fixtures/disc13/MovieObject.bdmv
new file mode 100644
index 0000000..1e2b09d
Binary files /dev/null and b/tests/fixtures/disc13/MovieObject.bdmv differ
diff --git a/tests/fixtures/disc13/PLAYLIST/00000.mpls b/tests/fixtures/disc13/PLAYLIST/00000.mpls
new file mode 100644
index 0000000..3e9593d
Binary files /dev/null and b/tests/fixtures/disc13/PLAYLIST/00000.mpls differ
diff --git a/tests/fixtures/disc13/PLAYLIST/00001.mpls b/tests/fixtures/disc13/PLAYLIST/00001.mpls
new file mode 100644
index 0000000..eae4e65
Binary files /dev/null and b/tests/fixtures/disc13/PLAYLIST/00001.mpls differ
diff --git a/tests/fixtures/disc13/PLAYLIST/00002.mpls b/tests/fixtures/disc13/PLAYLIST/00002.mpls
new file mode 100644
index 0000000..86f928d
Binary files /dev/null and b/tests/fixtures/disc13/PLAYLIST/00002.mpls differ
diff --git a/tests/fixtures/disc13/PLAYLIST/00003.mpls b/tests/fixtures/disc13/PLAYLIST/00003.mpls
new file mode 100644
index 0000000..24f6100
Binary files /dev/null and b/tests/fixtures/disc13/PLAYLIST/00003.mpls differ
diff --git a/tests/fixtures/disc13/PLAYLIST/00004.mpls b/tests/fixtures/disc13/PLAYLIST/00004.mpls
new file mode 100644
index 0000000..7e6053a
Binary files /dev/null and b/tests/fixtures/disc13/PLAYLIST/00004.mpls differ
diff --git a/tests/fixtures/disc13/PLAYLIST/00005.mpls b/tests/fixtures/disc13/PLAYLIST/00005.mpls
new file mode 100644
index 0000000..1b3f486
Binary files /dev/null and b/tests/fixtures/disc13/PLAYLIST/00005.mpls differ
diff --git a/tests/fixtures/disc13/PLAYLIST/00006.mpls b/tests/fixtures/disc13/PLAYLIST/00006.mpls
new file mode 100644
index 0000000..3d256b6
Binary files /dev/null and b/tests/fixtures/disc13/PLAYLIST/00006.mpls differ
diff --git a/tests/fixtures/disc13/PLAYLIST/00007.mpls b/tests/fixtures/disc13/PLAYLIST/00007.mpls
new file mode 100644
index 0000000..48d0cbc
Binary files /dev/null and b/tests/fixtures/disc13/PLAYLIST/00007.mpls differ
diff --git a/tests/fixtures/disc13/PLAYLIST/00008.mpls b/tests/fixtures/disc13/PLAYLIST/00008.mpls
new file mode 100644
index 0000000..77c371c
Binary files /dev/null and b/tests/fixtures/disc13/PLAYLIST/00008.mpls differ
diff --git a/tests/fixtures/disc13/PLAYLIST/00009.mpls b/tests/fixtures/disc13/PLAYLIST/00009.mpls
new file mode 100644
index 0000000..ab63b6b
Binary files /dev/null and b/tests/fixtures/disc13/PLAYLIST/00009.mpls differ
diff --git a/tests/fixtures/disc13/PLAYLIST/00010.mpls b/tests/fixtures/disc13/PLAYLIST/00010.mpls
new file mode 100644
index 0000000..5a3399f
Binary files /dev/null and b/tests/fixtures/disc13/PLAYLIST/00010.mpls differ
diff --git a/tests/fixtures/disc13/PLAYLIST/00011.mpls b/tests/fixtures/disc13/PLAYLIST/00011.mpls
new file mode 100644
index 0000000..17a12e5
Binary files /dev/null and b/tests/fixtures/disc13/PLAYLIST/00011.mpls differ
diff --git a/tests/fixtures/disc13/ics_menu.bin b/tests/fixtures/disc13/ics_menu.bin
new file mode 100644
index 0000000..1bb03c3
Binary files /dev/null and b/tests/fixtures/disc13/ics_menu.bin differ
diff --git a/tests/fixtures/disc13/index.bdmv b/tests/fixtures/disc13/index.bdmv
new file mode 100644
index 0000000..f3bdcac
Binary files /dev/null and b/tests/fixtures/disc13/index.bdmv differ
diff --git a/tests/test_disc10_scan.py b/tests/test_disc10_scan.py
new file mode 100644
index 0000000..f4a7579
--- /dev/null
+++ b/tests/test_disc10_scan.py
@@ -0,0 +1,77 @@
+"""Integration tests for the disc10 fixture scan results.
+
+Disc10 is a five-episode bonus disc with commentary specials:
+- Play_all (00002.mpls, 6 clips, 31 chapters) decomposes into 5 episodes
+ at IG chapter marks [0, 6, 12, 18, 24]. Each episode ~24 min.
+- Three individual playlists (00003-00005) duplicate episodes 1-3 with
+ commentary audio; detected as commentary specials via IG page 4 buttons.
+- Only episodes 1-3 have individual playlists; episodes 4-5 are
+ play_all-only, driving the play_all-subset ordering heuristic.
+"""
+
+import pytest
+
+from bdpl.model import DiscAnalysis
+
+pytestmark = pytest.mark.integration
+
+
+class TestDisc10Episodes:
+ def test_finds_five_episodes(self, disc10_analysis: DiscAnalysis) -> None:
+ """Disc10 should infer exactly five episodes from play_all."""
+ assert len(disc10_analysis.episodes) == 5
+
+ def test_episodes_are_ordered(self, disc10_analysis: DiscAnalysis) -> None:
+ """Verify inferred episode sequence is [1, 2, 3, 4, 5]."""
+ assert [ep.episode for ep in disc10_analysis.episodes] == [1, 2, 3, 4, 5]
+
+ def test_all_episodes_from_play_all(self, disc10_analysis: DiscAnalysis) -> None:
+ """All episodes should come from the play_all playlist."""
+ for ep in disc10_analysis.episodes:
+ assert ep.playlist == "00002.mpls"
+
+ def test_episode_durations_reasonable(self, disc10_analysis: DiscAnalysis) -> None:
+ """Each episode should be ~20–28 min."""
+ for ep in disc10_analysis.episodes:
+ dur_min = ep.duration_ms / 60_000
+ assert 20 < dur_min < 28, f"Ep {ep.episode} duration {dur_min:.1f}min out of range"
+
+ def test_episodes_have_scenes(self, disc10_analysis: DiscAnalysis) -> None:
+ """Each episode should have at least 1 scene."""
+ for ep in disc10_analysis.episodes:
+ assert len(ep.scenes) >= 1, f"Ep {ep.episode} has no scenes"
+
+
+class TestDisc10Specials:
+ def test_special_count(self, disc10_analysis: DiscAnalysis) -> None:
+ """Disc10 should have 3 specials (commentaries for episodes 1-3)."""
+ assert len(disc10_analysis.special_features) == 3
+
+ def test_all_commentaries(self, disc10_analysis: DiscAnalysis) -> None:
+ """All specials should be commentary tracks."""
+ for sf in disc10_analysis.special_features:
+ assert sf.category == "commentary", (
+ f"Special {sf.playlist} has category '{sf.category}', expected 'commentary'"
+ )
+
+ def test_commentary_playlists(self, disc10_analysis: DiscAnalysis) -> None:
+ """Commentary tracks should reference individual episode playlists."""
+ playlists = {sf.playlist for sf in disc10_analysis.special_features}
+ assert playlists == {"00003.mpls", "00004.mpls", "00005.mpls"}
+
+
+class TestDisc10Metadata:
+ def test_disc_title(self, disc10_analysis: DiscAnalysis) -> None:
+ """Disc title should be extracted from META/DL/bdmt_eng.xml."""
+ assert disc10_analysis.disc_title == "TEST DISC 10"
+
+ def test_play_all_detected(self, disc10_analysis: DiscAnalysis) -> None:
+ """00002.mpls should be classified as play_all."""
+ classes = disc10_analysis.analysis.get("classifications", {})
+ assert classes.get("00002.mpls") == "play_all"
+
+ def test_ig_chapter_marks(self, disc10_analysis: DiscAnalysis) -> None:
+ """IG hints should report 5 chapter marks for episode starts."""
+ ig = disc10_analysis.analysis.get("disc_hints", {}).get("ig_menu", {})
+ marks = ig.get("chapter_marks", [])
+ assert marks == [0, 6, 12, 18, 24]
diff --git a/tests/test_disc11_scan.py b/tests/test_disc11_scan.py
new file mode 100644
index 0000000..4f0757b
--- /dev/null
+++ b/tests/test_disc11_scan.py
@@ -0,0 +1,69 @@
+"""Integration tests for the disc11 fixture scan results.
+
+Disc11 is a six-episode bonus disc with one short special:
+- Play_all (00002.mpls, 7 clips, 37 chapters) decomposes into 6 episodes
+ at IG chapter marks [0, 6, 12, 18, 24, 30]. Each episode ~24 min.
+- One special feature (00003.mpls, clip 00013, ~3.5 min) classified as
+ extra, detected via title hint (title 1 → playlist 3).
+- No individual episode playlists — all episodes come from play_all.
+"""
+
+import pytest
+
+from bdpl.model import DiscAnalysis
+
+pytestmark = pytest.mark.integration
+
+
+class TestDisc11Episodes:
+ def test_finds_six_episodes(self, disc11_analysis: DiscAnalysis) -> None:
+ """Disc11 should infer exactly six episodes from play_all."""
+ assert len(disc11_analysis.episodes) == 6
+
+ def test_episodes_are_ordered(self, disc11_analysis: DiscAnalysis) -> None:
+ """Verify inferred episode sequence is [1..6]."""
+ assert [ep.episode for ep in disc11_analysis.episodes] == [1, 2, 3, 4, 5, 6]
+
+ def test_all_episodes_from_play_all(self, disc11_analysis: DiscAnalysis) -> None:
+ """All episodes should come from the play_all playlist."""
+ for ep in disc11_analysis.episodes:
+ assert ep.playlist == "00002.mpls"
+
+ def test_episode_durations_reasonable(self, disc11_analysis: DiscAnalysis) -> None:
+ """Each episode should be ~20–28 min."""
+ for ep in disc11_analysis.episodes:
+ dur_min = ep.duration_ms / 60_000
+ assert 20 < dur_min < 28, f"Ep {ep.episode} duration {dur_min:.1f}min out of range"
+
+
+class TestDisc11Specials:
+ def test_special_count(self, disc11_analysis: DiscAnalysis) -> None:
+ """Disc11 should have 1 special feature."""
+ assert len(disc11_analysis.special_features) == 1
+
+ def test_special_is_short(self, disc11_analysis: DiscAnalysis) -> None:
+ """The special should be ~3–5 min."""
+ sf = disc11_analysis.special_features[0]
+ dur_min = sf.duration_ms / 60_000
+ assert 2 < dur_min < 5, f"Special {sf.playlist} duration {dur_min:.1f}min out of range"
+
+ def test_special_playlist(self, disc11_analysis: DiscAnalysis) -> None:
+ """Special should be on 00003.mpls."""
+ assert disc11_analysis.special_features[0].playlist == "00003.mpls"
+
+
+class TestDisc11Metadata:
+ def test_disc_title(self, disc11_analysis: DiscAnalysis) -> None:
+ """Disc title should be extracted from META/DL/bdmt_eng.xml."""
+ assert disc11_analysis.disc_title == "TEST DISC 11"
+
+ def test_play_all_detected(self, disc11_analysis: DiscAnalysis) -> None:
+ """00002.mpls should be classified as play_all."""
+ classes = disc11_analysis.analysis.get("classifications", {})
+ assert classes.get("00002.mpls") == "play_all"
+
+ def test_ig_chapter_marks(self, disc11_analysis: DiscAnalysis) -> None:
+ """IG hints should report 6 chapter marks for episode starts."""
+ ig = disc11_analysis.analysis.get("disc_hints", {}).get("ig_menu", {})
+ marks = ig.get("chapter_marks", [])
+ assert marks == [0, 6, 12, 18, 24, 30]
diff --git a/tests/test_disc12_scan.py b/tests/test_disc12_scan.py
new file mode 100644
index 0000000..51effb8
--- /dev/null
+++ b/tests/test_disc12_scan.py
@@ -0,0 +1,70 @@
+"""Integration tests for the disc12 fixture scan results.
+
+Disc12 is a five-episode bonus disc with commentary specials (same
+structure as disc10):
+- Play_all (00002.mpls, 6 clips, 31 chapters) decomposes into 5 episodes
+ at IG chapter marks [0, 6, 12, 18, 24]. Each episode ~24 min.
+- Three individual playlists (00003-00005) duplicate episodes 2-4 with
+ commentary audio; detected as commentary specials via IG menu.
+- Episodes 1 and 5 are play_all-only.
+"""
+
+import pytest
+
+from bdpl.model import DiscAnalysis
+
+pytestmark = pytest.mark.integration
+
+
+class TestDisc12Episodes:
+ def test_finds_five_episodes(self, disc12_analysis: DiscAnalysis) -> None:
+ """Disc12 should infer exactly five episodes from play_all."""
+ assert len(disc12_analysis.episodes) == 5
+
+ def test_episodes_are_ordered(self, disc12_analysis: DiscAnalysis) -> None:
+ """Verify inferred episode sequence is [1..5]."""
+ assert [ep.episode for ep in disc12_analysis.episodes] == [1, 2, 3, 4, 5]
+
+ def test_all_episodes_from_play_all(self, disc12_analysis: DiscAnalysis) -> None:
+ """All episodes should come from the play_all playlist."""
+ for ep in disc12_analysis.episodes:
+ assert ep.playlist == "00002.mpls"
+
+ def test_episode_durations_reasonable(self, disc12_analysis: DiscAnalysis) -> None:
+ """Each episode should be ~20–28 min."""
+ for ep in disc12_analysis.episodes:
+ dur_min = ep.duration_ms / 60_000
+ assert 20 < dur_min < 28, f"Ep {ep.episode} duration {dur_min:.1f}min out of range"
+
+
+class TestDisc12Specials:
+ def test_special_count(self, disc12_analysis: DiscAnalysis) -> None:
+ """Disc12 should have 3 commentary specials."""
+ assert len(disc12_analysis.special_features) == 3
+
+ def test_all_commentaries(self, disc12_analysis: DiscAnalysis) -> None:
+ """All specials should be commentary tracks."""
+ for sf in disc12_analysis.special_features:
+ assert sf.category == "commentary"
+
+ def test_commentary_playlists(self, disc12_analysis: DiscAnalysis) -> None:
+ """Commentary tracks should reference individual episode playlists."""
+ playlists = {sf.playlist for sf in disc12_analysis.special_features}
+ assert playlists == {"00003.mpls", "00004.mpls", "00005.mpls"}
+
+
+class TestDisc12Metadata:
+ def test_disc_title(self, disc12_analysis: DiscAnalysis) -> None:
+ """Disc title should be extracted from META/DL/bdmt_eng.xml."""
+ assert disc12_analysis.disc_title == "TEST DISC 12"
+
+ def test_play_all_detected(self, disc12_analysis: DiscAnalysis) -> None:
+ """00002.mpls should be classified as play_all."""
+ classes = disc12_analysis.analysis.get("classifications", {})
+ assert classes.get("00002.mpls") == "play_all"
+
+ def test_ig_chapter_marks(self, disc12_analysis: DiscAnalysis) -> None:
+ """IG hints should report 5 chapter marks for episode starts."""
+ ig = disc12_analysis.analysis.get("disc_hints", {}).get("ig_menu", {})
+ marks = ig.get("chapter_marks", [])
+ assert marks == [0, 6, 12, 18, 24]
diff --git a/tests/test_disc13_scan.py b/tests/test_disc13_scan.py
new file mode 100644
index 0000000..d38d2d9
--- /dev/null
+++ b/tests/test_disc13_scan.py
@@ -0,0 +1,87 @@
+"""Integration tests for the disc13 fixture scan results.
+
+Disc13 is a six-episode bonus disc with the most complex special features
+page in the box set (9 specials):
+- Play_all (00002.mpls, 7 clips, 38 chapters) decomposes into 6 episodes
+ at IG chapter marks [0, 6, 13, 19, 25, 31]. Five ~24 min, one ~23.6 min.
+- Two individual playlists (00003-00004) are commentary / alt-audio tracks
+ for episodes. Both detected as commentary specials.
+- Five creditless OP/ED playlists (00005-00008, 00011) each ~1.5-2 min.
+- Two extra / promotional playlists (00009, 00010) — 3.3 min and 8.8 min.
+"""
+
+import pytest
+
+from bdpl.model import DiscAnalysis
+
+pytestmark = pytest.mark.integration
+
+
+class TestDisc13Episodes:
+ def test_finds_six_episodes(self, disc13_analysis: DiscAnalysis) -> None:
+ """Disc13 should infer exactly six episodes from play_all."""
+ assert len(disc13_analysis.episodes) == 6
+
+ def test_episodes_are_ordered(self, disc13_analysis: DiscAnalysis) -> None:
+ """Verify inferred episode sequence is [1..6]."""
+ assert [ep.episode for ep in disc13_analysis.episodes] == [1, 2, 3, 4, 5, 6]
+
+ def test_all_episodes_from_play_all(self, disc13_analysis: DiscAnalysis) -> None:
+ """All episodes should come from the play_all playlist."""
+ for ep in disc13_analysis.episodes:
+ assert ep.playlist == "00002.mpls"
+
+ def test_episode_durations_reasonable(self, disc13_analysis: DiscAnalysis) -> None:
+ """Each episode should be ~20–28 min."""
+ for ep in disc13_analysis.episodes:
+ dur_min = ep.duration_ms / 60_000
+ assert 20 < dur_min < 28, f"Ep {ep.episode} duration {dur_min:.1f}min out of range"
+
+
+class TestDisc13Specials:
+ def test_special_count(self, disc13_analysis: DiscAnalysis) -> None:
+ """Disc13 should have 9 specials total."""
+ assert len(disc13_analysis.special_features) == 9
+
+ def test_commentary_count(self, disc13_analysis: DiscAnalysis) -> None:
+ """Two specials should be commentary / alt-audio tracks."""
+ commentaries = [
+ sf for sf in disc13_analysis.special_features if sf.category == "commentary"
+ ]
+ assert len(commentaries) == 2
+
+ def test_commentary_playlists(self, disc13_analysis: DiscAnalysis) -> None:
+ """Commentary tracks should reference individual episode playlists."""
+ playlists = {
+ sf.playlist for sf in disc13_analysis.special_features if sf.category == "commentary"
+ }
+ assert playlists == {"00003.mpls", "00004.mpls"}
+
+ def test_creditless_count(self, disc13_analysis: DiscAnalysis) -> None:
+ """Five specials should be creditless OP/ED tracks."""
+ creditless = [
+ sf for sf in disc13_analysis.special_features if sf.category == "creditless_ed"
+ ]
+ assert len(creditless) == 5
+
+ def test_extra_count(self, disc13_analysis: DiscAnalysis) -> None:
+ """Two specials should be extras (promotional content)."""
+ extras = [sf for sf in disc13_analysis.special_features if sf.category == "extra"]
+ assert len(extras) == 2
+
+
+class TestDisc13Metadata:
+ def test_disc_title(self, disc13_analysis: DiscAnalysis) -> None:
+ """Disc title should be extracted from META/DL/bdmt_eng.xml."""
+ assert disc13_analysis.disc_title == "TEST DISC 13"
+
+ def test_play_all_detected(self, disc13_analysis: DiscAnalysis) -> None:
+ """00002.mpls should be classified as play_all."""
+ classes = disc13_analysis.analysis.get("classifications", {})
+ assert classes.get("00002.mpls") == "play_all"
+
+ def test_ig_chapter_marks(self, disc13_analysis: DiscAnalysis) -> None:
+ """IG hints should report 6 chapter marks for episode starts."""
+ ig = disc13_analysis.analysis.get("disc_hints", {}).get("ig_menu", {})
+ marks = ig.get("chapter_marks", [])
+ assert marks == [0, 6, 13, 19, 25, 31]
diff --git a/tests/test_disc_matrix.py b/tests/test_disc_matrix.py
index 0383132..af7cffc 100644
--- a/tests/test_disc_matrix.py
+++ b/tests/test_disc_matrix.py
@@ -21,6 +21,10 @@
("disc7_analysis", 2, ["00003.mpls", "00004.mpls"]),
("disc8_analysis", 2, ["00003.mpls", "00004.mpls"]),
("disc9_analysis", 1, ["00002.mpls"]),
+ ("disc10_analysis", 5, ["00002.mpls"] * 5),
+ ("disc11_analysis", 6, ["00002.mpls"] * 6),
+ ("disc12_analysis", 5, ["00002.mpls"] * 5),
+ ("disc13_analysis", 6, ["00002.mpls"] * 6),
],
)
def test_disc_episode_expectation_matrix(
@@ -47,6 +51,10 @@ def test_disc_episode_expectation_matrix(
("disc7_analysis", 2, 2), # 2 title-hint specials (stream variants)
("disc8_analysis", 3, 3), # 2 commentaries + 1 lyrics ending
("disc9_analysis", 1, 1), # alt-audio variant detected as special
+ ("disc10_analysis", 3, 3), # 3 commentaries (play_all-only episodes)
+ ("disc11_analysis", 1, 1), # 1 short extra
+ ("disc12_analysis", 3, 3), # 3 commentaries (play_all-only episodes)
+ ("disc13_analysis", 9, 9), # 2 commentary + 5 creditless + 2 extra
],
)
def test_disc_special_visibility_expectation_matrix(
@@ -77,6 +85,10 @@ def test_disc_special_visibility_expectation_matrix(
"disc7_analysis",
"disc8_analysis",
"disc9_analysis",
+ "disc10_analysis",
+ "disc11_analysis",
+ "disc12_analysis",
+ "disc13_analysis",
],
)
def test_disc_episode_segment_boundaries_matrix(
@@ -111,6 +123,10 @@ def test_disc_episode_segment_boundaries_matrix(
"disc7_analysis",
"disc8_analysis",
"disc9_analysis",
+ "disc10_analysis",
+ "disc11_analysis",
+ "disc12_analysis",
+ "disc13_analysis",
],
)
def test_disc_special_boundary_semantics_matrix(
@@ -152,6 +168,10 @@ def test_disc_special_boundary_semantics_matrix(
("disc7_analysis", 0),
("disc8_analysis", 0),
("disc9_analysis", 0),
+ ("disc10_analysis", 0),
+ ("disc11_analysis", 0),
+ ("disc12_analysis", 0),
+ ("disc13_analysis", 0),
],
)
def test_disc_special_chapter_split_expectation_matrix(
@@ -176,6 +196,10 @@ def test_disc_special_chapter_split_expectation_matrix(
("disc7_analysis", "TEST DISC 7 VOL 2"),
("disc8_analysis", "TEST DISC 8"),
("disc9_analysis", "TEST DISC 9"),
+ ("disc10_analysis", "TEST DISC 10"),
+ ("disc11_analysis", "TEST DISC 11"),
+ ("disc12_analysis", "TEST DISC 12"),
+ ("disc13_analysis", "TEST DISC 13"),
],
)
def test_disc_title_extraction_matrix(