Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 42 additions & 4 deletions bdpl/analyze/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def _parse_disc_hints(bdmv_path: Path, clips: dict[str, ClipInfo] | None = None)
# Build title → playlist mapping via index titles → movie objects
obj_playlists: dict[int, list[int]] = {}
obj_play_marks: dict[int, list[tuple[int, int]]] = {}
obj_jump_titles: dict[int, list[int]] = {}
for obj in mo.objects:
if obj.referenced_playlists:
obj_playlists[obj.object_id] = obj.referenced_playlists
Expand All @@ -96,10 +97,14 @@ def _parse_disc_hints(bdmv_path: Path, clips: dict[str, ClipInfo] | None = None)
]
if marks:
obj_play_marks[obj.object_id] = marks
jts = obj.referenced_titles
if jts:
obj_jump_titles[obj.object_id] = jts
hints["movie_objects"] = {
"count": len(mo.objects),
"obj_playlists": obj_playlists,
"obj_play_marks": obj_play_marks,
"obj_jump_titles": obj_jump_titles,
}
except Exception:
log.debug("Failed to parse MovieObject.bdmv", exc_info=True)
Expand Down Expand Up @@ -289,6 +294,16 @@ def _detect_special_features(
# All buttons on this page target the same title — this is
# either the main-play page or a chapter-selection page.
chapter_selection_jt.update(jts)
continue
# A page where every button targets an episode playlist is an
# episode-selection page (e.g. per-episode CHAPTER menu).
all_episode = all(
title_to_mpls.get(jt_val - 1) in ep_playlists
for jt_val in jts
if title_to_mpls.get(jt_val - 1) is not None
)
if all_episode:
chapter_selection_jt.update(jts)

# --- Walk IG hints and build features -----------------------------------
seen: set[tuple[str, int | None]] = set()
Expand Down Expand Up @@ -373,9 +388,12 @@ def _detect_special_features(
# Supplement with title-hint specials not already covered by IG buttons.
title_hint_entries = _title_hint_non_episode_entries(hints, classifications, episodes)
existing_keys = {(feature.playlist, feature.chapter_start) for feature in features}
nav_playlists = _nav_playlists_from_hints(hints)
for mpls, chapter_starts in title_hint_entries:
if mpls in variant_mpls:
continue
if mpls in nav_playlists:
continue
pl = pl_by_name.get(mpls)
if pl is None:
continue
Expand Down Expand Up @@ -477,15 +495,35 @@ def _nav_playlists_from_hints(hints: dict) -> set[str]:

These are navigation playlists (disc intro, menu background) and should
not be treated as special features.

Follows one level of JumpTitle indirection: if the first_playback MO
jumps to a title whose MO plays a playlist, that playlist is included.
"""
index_hints = hints.get("index", {})
obj_pl = hints.get("movie_objects", {}).get("obj_playlists", {})
mo_hints = hints.get("movie_objects", {})
obj_pl = mo_hints.get("obj_playlists", {})
obj_jt = mo_hints.get("obj_jump_titles", {})
nav: set[str] = set()

# Build title → movie_object map for JumpTitle resolution.
title_to_obj: dict[int, int] = {
entry["title"]: entry["movie_object"] for entry in index_hints.get("titles", [])
}

for key in ("first_playback_obj", "top_menu_obj"):
obj_id = index_hints.get(key)
if obj_id is not None:
for pl_num in obj_pl.get(obj_id, []):
nav.add(f"{pl_num:05d}.mpls")
if obj_id is None:
continue
# Direct PlayPl commands.
for pl_num in obj_pl.get(obj_id, []):
nav.add(f"{pl_num:05d}.mpls")
# Follow JumpTitle → title → MO → PlayPl (one level).
for jt_num in obj_jt.get(obj_id, []):
title_idx = jt_num - 1 # JumpTitle operand is 1-based
target_obj = title_to_obj.get(title_idx)
if target_obj is not None:
for pl_num in obj_pl.get(target_obj, []):
nav.add(f"{pl_num:05d}.mpls")
return nav


Expand Down
48 changes: 48 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,54 @@ def disc25_analysis(disc25_path):
return _analyze_fixture(disc25_path)


@pytest.fixture(scope="session")
def disc26_path() -> Path:
"""Return path to bundled disc26 fixture."""
return _fixture_path("disc26")


@pytest.fixture(scope="session")
def disc26_analysis(disc26_path):
"""Run and cache full analysis for the bundled disc26 fixture."""
return _analyze_fixture(disc26_path)


@pytest.fixture(scope="session")
def disc27_path() -> Path:
"""Return path to bundled disc27 fixture."""
return _fixture_path("disc27")


@pytest.fixture(scope="session")
def disc27_analysis(disc27_path):
"""Run and cache full analysis for the bundled disc27 fixture."""
return _analyze_fixture(disc27_path)


@pytest.fixture(scope="session")
def disc28_path() -> Path:
"""Return path to bundled disc28 fixture."""
return _fixture_path("disc28")


@pytest.fixture(scope="session")
def disc28_analysis(disc28_path):
"""Run and cache full analysis for the bundled disc28 fixture."""
return _analyze_fixture(disc28_path)


@pytest.fixture(scope="session")
def disc29_path() -> Path:
"""Return path to bundled disc29 fixture."""
return _fixture_path("disc29")


@pytest.fixture(scope="session")
def disc29_analysis(disc29_path):
"""Run and cache full analysis for the bundled disc29 fixture."""
return _analyze_fixture(disc29_path)


@pytest.fixture
def cli_runner() -> Callable[..., subprocess.CompletedProcess[str]]:
"""Return helper to invoke `python -m bdpl.cli` consistently in tests."""
Expand Down
Binary file added tests/fixtures/disc26/CLIPINF/00000.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00001.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00002.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00003.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00004.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00005.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00006.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00007.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00008.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00009.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00010.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00011.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00012.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00013.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00014.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00015.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00016.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00017.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00018.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00019.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00020.clpi
Binary file not shown.
Binary file added tests/fixtures/disc26/CLIPINF/00021.clpi
Binary file not shown.
6 changes: 6 additions & 0 deletions tests/fixtures/disc26/META/DL/bdmt_eng.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<disclib>
<di:discinfo xmlns:di="urn:BDA:bdmv;discinfo">
<di:title><di:name>TEST DISC 26</di:name></di:title>
</di:discinfo>
</disclib>
Binary file added tests/fixtures/disc26/MovieObject.bdmv
Binary file not shown.
Binary file added tests/fixtures/disc26/PLAYLIST/00000.mpls
Binary file not shown.
Binary file added tests/fixtures/disc26/PLAYLIST/00001.mpls
Binary file not shown.
Binary file added tests/fixtures/disc26/PLAYLIST/00002.mpls
Binary file not shown.
Binary file added tests/fixtures/disc26/PLAYLIST/00003.mpls
Binary file not shown.
Binary file added tests/fixtures/disc26/PLAYLIST/00004.mpls
Binary file not shown.
Binary file added tests/fixtures/disc26/PLAYLIST/00005.mpls
Binary file not shown.
Binary file added tests/fixtures/disc26/PLAYLIST/00006.mpls
Binary file not shown.
Binary file added tests/fixtures/disc26/PLAYLIST/00007.mpls
Binary file not shown.
Binary file added tests/fixtures/disc26/PLAYLIST/00008.mpls
Binary file not shown.
Binary file added tests/fixtures/disc26/PLAYLIST/00009.mpls
Binary file not shown.
Binary file added tests/fixtures/disc26/PLAYLIST/00010.mpls
Binary file not shown.
Binary file added tests/fixtures/disc26/PLAYLIST/00011.mpls
Binary file not shown.
Binary file added tests/fixtures/disc26/PLAYLIST/00012.mpls
Binary file not shown.
Binary file added tests/fixtures/disc26/PLAYLIST/00013.mpls
Binary file not shown.
Binary file added tests/fixtures/disc26/PLAYLIST/00014.mpls
Binary file not shown.
Binary file added tests/fixtures/disc26/PLAYLIST/00015.mpls
Binary file not shown.
Binary file added tests/fixtures/disc26/PLAYLIST/00016.mpls
Binary file not shown.
Binary file added tests/fixtures/disc26/ics_menu.bin
Binary file not shown.
Binary file added tests/fixtures/disc26/index.bdmv
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00000.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00001.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00002.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00003.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00004.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00005.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00006.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00007.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00008.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00009.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00010.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00011.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00012.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00013.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00014.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00015.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00016.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00017.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00018.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00019.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00020.clpi
Binary file not shown.
Binary file added tests/fixtures/disc27/CLIPINF/00021.clpi
Binary file not shown.
6 changes: 6 additions & 0 deletions tests/fixtures/disc27/META/DL/bdmt_eng.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<disclib>
<di:discinfo xmlns:di="urn:BDA:bdmv;discinfo">
<di:title><di:name>TEST DISC 27</di:name></di:title>
</di:discinfo>
</disclib>
Binary file added tests/fixtures/disc27/MovieObject.bdmv
Binary file not shown.
Binary file added tests/fixtures/disc27/PLAYLIST/00000.mpls
Binary file not shown.
Binary file added tests/fixtures/disc27/PLAYLIST/00001.mpls
Binary file not shown.
Binary file added tests/fixtures/disc27/PLAYLIST/00002.mpls
Binary file not shown.
Binary file added tests/fixtures/disc27/PLAYLIST/00003.mpls
Binary file not shown.
Binary file added tests/fixtures/disc27/PLAYLIST/00004.mpls
Binary file not shown.
Binary file added tests/fixtures/disc27/PLAYLIST/00005.mpls
Binary file not shown.
Binary file added tests/fixtures/disc27/PLAYLIST/00006.mpls
Binary file not shown.
Binary file added tests/fixtures/disc27/PLAYLIST/00007.mpls
Binary file not shown.
Binary file added tests/fixtures/disc27/PLAYLIST/00008.mpls
Binary file not shown.
Binary file added tests/fixtures/disc27/PLAYLIST/00009.mpls
Binary file not shown.
Binary file added tests/fixtures/disc27/PLAYLIST/00010.mpls
Binary file not shown.
Binary file added tests/fixtures/disc27/PLAYLIST/00011.mpls
Binary file not shown.
Binary file added tests/fixtures/disc27/PLAYLIST/00012.mpls
Binary file not shown.
Binary file added tests/fixtures/disc27/PLAYLIST/00013.mpls
Binary file not shown.
Binary file added tests/fixtures/disc27/PLAYLIST/00014.mpls
Binary file not shown.
Binary file added tests/fixtures/disc27/PLAYLIST/00015.mpls
Binary file not shown.
Binary file added tests/fixtures/disc27/PLAYLIST/00016.mpls
Binary file not shown.
Binary file added tests/fixtures/disc27/ics_menu.bin
Binary file not shown.
Binary file added tests/fixtures/disc27/index.bdmv
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00000.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00001.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00002.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00003.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00004.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00005.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00006.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00007.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00008.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00009.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00010.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00011.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00012.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00013.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00014.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00015.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00016.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00017.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00018.clpi
Binary file not shown.
Binary file added tests/fixtures/disc28/CLIPINF/00019.clpi
Binary file not shown.
6 changes: 6 additions & 0 deletions tests/fixtures/disc28/META/DL/bdmt_eng.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<disclib>
<di:discinfo xmlns:di="urn:BDA:bdmv;discinfo">
<di:title><di:name>TEST DISC 28</di:name></di:title>
</di:discinfo>
</disclib>
Binary file added tests/fixtures/disc28/MovieObject.bdmv
Binary file not shown.
Binary file added tests/fixtures/disc28/PLAYLIST/00000.mpls
Binary file not shown.
Binary file added tests/fixtures/disc28/PLAYLIST/00001.mpls
Binary file not shown.
Binary file added tests/fixtures/disc28/PLAYLIST/00002.mpls
Binary file not shown.
Binary file added tests/fixtures/disc28/PLAYLIST/00003.mpls
Binary file not shown.
Binary file added tests/fixtures/disc28/PLAYLIST/00004.mpls
Binary file not shown.
Binary file added tests/fixtures/disc28/PLAYLIST/00005.mpls
Binary file not shown.
Binary file added tests/fixtures/disc28/PLAYLIST/00006.mpls
Binary file not shown.
Binary file added tests/fixtures/disc28/PLAYLIST/00007.mpls
Binary file not shown.
Binary file added tests/fixtures/disc28/PLAYLIST/00008.mpls
Binary file not shown.
Binary file added tests/fixtures/disc28/PLAYLIST/00009.mpls
Binary file not shown.
Binary file added tests/fixtures/disc28/PLAYLIST/00010.mpls
Binary file not shown.
Binary file added tests/fixtures/disc28/PLAYLIST/00011.mpls
Binary file not shown.
Binary file added tests/fixtures/disc28/PLAYLIST/00012.mpls
Binary file not shown.
Binary file added tests/fixtures/disc28/PLAYLIST/00013.mpls
Binary file not shown.
Binary file added tests/fixtures/disc28/PLAYLIST/00014.mpls
Binary file not shown.
Binary file added tests/fixtures/disc28/ics_menu.bin
Binary file not shown.
Binary file added tests/fixtures/disc28/index.bdmv
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00000.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00001.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00002.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00003.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00004.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00005.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00006.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00007.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00008.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00009.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00010.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00011.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00012.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00013.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00014.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00015.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00016.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00017.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00018.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00019.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00020.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00021.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00022.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00023.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00024.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00025.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00026.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00027.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00028.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00029.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00030.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00031.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00032.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00033.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00034.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00035.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00036.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00037.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00038.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00039.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00040.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00041.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00042.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00043.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00044.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00045.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00046.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00047.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00048.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00049.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00050.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00051.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00052.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00053.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00054.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00055.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00056.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00057.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00058.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00059.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00060.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00061.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00062.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00063.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00064.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00065.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00066.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00067.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00068.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00069.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00070.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00071.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00072.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00073.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00074.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00075.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00076.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00077.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00078.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00079.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00080.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00081.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00082.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00083.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00084.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00085.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00086.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00087.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00088.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00089.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00090.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00091.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00092.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00093.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00094.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00095.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00096.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00097.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00098.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00099.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00100.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00101.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00102.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00103.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00104.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00105.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00106.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00107.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00108.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00109.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00110.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00111.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00112.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00113.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00114.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00115.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00116.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00117.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00118.clpi
Binary file not shown.
Binary file added tests/fixtures/disc29/CLIPINF/00119.clpi
Binary file not shown.
6 changes: 6 additions & 0 deletions tests/fixtures/disc29/META/DL/bdmt_eng.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<disclib>
<di:discinfo xmlns:di="urn:BDA:bdmv;discinfo">
<di:title><di:name>TEST DISC 29</di:name></di:title>
</di:discinfo>
</disclib>
Binary file added tests/fixtures/disc29/MovieObject.bdmv
Binary file not shown.
Binary file added tests/fixtures/disc29/PLAYLIST/00000.mpls
Binary file not shown.
Binary file added tests/fixtures/disc29/PLAYLIST/00001.mpls
Binary file not shown.
Binary file added tests/fixtures/disc29/PLAYLIST/00002.mpls
Binary file not shown.
Binary file added tests/fixtures/disc29/PLAYLIST/00003.mpls
Binary file not shown.
Binary file added tests/fixtures/disc29/PLAYLIST/00004.mpls
Binary file not shown.
Binary file added tests/fixtures/disc29/PLAYLIST/00005.mpls
Binary file not shown.
Binary file added tests/fixtures/disc29/ics_menu.bin
Binary file not shown.
Binary file added tests/fixtures/disc29/index.bdmv
Binary file not shown.
49 changes: 49 additions & 0 deletions tests/test_disc26_scan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""Integration tests for the disc26 fixture — 3-episode OVA disc with commentary + extras."""

from __future__ import annotations

import pytest

from bdpl.model import DiscAnalysis

pytestmark = pytest.mark.integration


class TestDisc26Episodes:
def test_episode_count(self, disc26_analysis: DiscAnalysis) -> None:
assert len(disc26_analysis.episodes) == 3

def test_episodes_are_ordered(self, disc26_analysis: DiscAnalysis) -> None:
assert [ep.episode for ep in disc26_analysis.episodes] == list(range(1, 4))

def test_episode_playlists(self, disc26_analysis: DiscAnalysis) -> None:
assert [ep.playlist for ep in disc26_analysis.episodes] == [
"00002.mpls",
"00003.mpls",
"00004.mpls",
]

def test_episode_durations(self, disc26_analysis: DiscAnalysis) -> None:
for ep in disc26_analysis.episodes:
dur_min = ep.duration_ms / 60000
assert 25 < dur_min < 30, f"ep{ep.episode} duration {dur_min:.1f}min out of range"


class TestDisc26Specials:
def test_special_count(self, disc26_analysis: DiscAnalysis) -> None:
assert len(disc26_analysis.special_features) == 12

def test_no_commentary(self, disc26_analysis: DiscAnalysis) -> None:
commentary = [sf for sf in disc26_analysis.special_features if sf.category == "commentary"]
assert len(commentary) == 0

def test_has_creditless_ed(self, disc26_analysis: DiscAnalysis) -> None:
creditless = [
sf for sf in disc26_analysis.special_features if sf.category == "creditless_ed"
]
assert len(creditless) == 4


class TestDisc26Metadata:
def test_disc_title(self, disc26_analysis: DiscAnalysis) -> None:
assert disc26_analysis.disc_title == "TEST DISC 26"
49 changes: 49 additions & 0 deletions tests/test_disc27_scan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""Integration tests for the disc27 fixture — 3-episode OVA disc with commentary + extras."""

from __future__ import annotations

import pytest

from bdpl.model import DiscAnalysis

pytestmark = pytest.mark.integration


class TestDisc27Episodes:
def test_episode_count(self, disc27_analysis: DiscAnalysis) -> None:
assert len(disc27_analysis.episodes) == 3

def test_episodes_are_ordered(self, disc27_analysis: DiscAnalysis) -> None:
assert [ep.episode for ep in disc27_analysis.episodes] == list(range(1, 4))

def test_episode_playlists(self, disc27_analysis: DiscAnalysis) -> None:
assert [ep.playlist for ep in disc27_analysis.episodes] == [
"00002.mpls",
"00003.mpls",
"00004.mpls",
]

def test_episode_durations(self, disc27_analysis: DiscAnalysis) -> None:
for ep in disc27_analysis.episodes:
dur_min = ep.duration_ms / 60000
assert 26 < dur_min < 31, f"ep{ep.episode} duration {dur_min:.1f}min out of range"


class TestDisc27Specials:
def test_special_count(self, disc27_analysis: DiscAnalysis) -> None:
assert len(disc27_analysis.special_features) == 12

def test_no_commentary(self, disc27_analysis: DiscAnalysis) -> None:
commentary = [sf for sf in disc27_analysis.special_features if sf.category == "commentary"]
assert len(commentary) == 0

def test_has_creditless_ed(self, disc27_analysis: DiscAnalysis) -> None:
creditless = [
sf for sf in disc27_analysis.special_features if sf.category == "creditless_ed"
]
assert len(creditless) == 6


class TestDisc27Metadata:
def test_disc_title(self, disc27_analysis: DiscAnalysis) -> None:
assert disc27_analysis.disc_title == "TEST DISC 27"
49 changes: 49 additions & 0 deletions tests/test_disc28_scan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""Integration tests for the disc28 fixture — 3-episode OVA disc with creditless + extras."""

from __future__ import annotations

import pytest

from bdpl.model import DiscAnalysis

pytestmark = pytest.mark.integration


class TestDisc28Episodes:
def test_episode_count(self, disc28_analysis: DiscAnalysis) -> None:
assert len(disc28_analysis.episodes) == 3

def test_episodes_are_ordered(self, disc28_analysis: DiscAnalysis) -> None:
assert [ep.episode for ep in disc28_analysis.episodes] == list(range(1, 4))

def test_episode_playlists(self, disc28_analysis: DiscAnalysis) -> None:
assert [ep.playlist for ep in disc28_analysis.episodes] == [
"00002.mpls",
"00003.mpls",
"00004.mpls",
]

def test_episode_durations(self, disc28_analysis: DiscAnalysis) -> None:
for ep in disc28_analysis.episodes:
dur_min = ep.duration_ms / 60000
assert 25 < dur_min < 33, f"ep{ep.episode} duration {dur_min:.1f}min out of range"


class TestDisc28Specials:
def test_special_count(self, disc28_analysis: DiscAnalysis) -> None:
assert len(disc28_analysis.special_features) == 10

def test_no_commentary(self, disc28_analysis: DiscAnalysis) -> None:
commentary = [sf for sf in disc28_analysis.special_features if sf.category == "commentary"]
assert len(commentary) == 0

def test_has_creditless_ed(self, disc28_analysis: DiscAnalysis) -> None:
creditless = [
sf for sf in disc28_analysis.special_features if sf.category == "creditless_ed"
]
assert len(creditless) == 7


class TestDisc28Metadata:
def test_disc_title(self, disc28_analysis: DiscAnalysis) -> None:
assert disc28_analysis.disc_title == "TEST DISC 28"
35 changes: 35 additions & 0 deletions tests/test_disc29_scan.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""Integration tests for the disc29 fixture — special disc with OVA + digital archives."""

from __future__ import annotations

import pytest

from bdpl.model import DiscAnalysis

pytestmark = pytest.mark.integration


class TestDisc29Episodes:
def test_episode_count(self, disc29_analysis: DiscAnalysis) -> None:
assert len(disc29_analysis.episodes) == 1

def test_episode_playlist(self, disc29_analysis: DiscAnalysis) -> None:
assert disc29_analysis.episodes[0].playlist == "00002.mpls"

def test_episode_duration(self, disc29_analysis: DiscAnalysis) -> None:
dur_min = disc29_analysis.episodes[0].duration_ms / 60000
assert 43 < dur_min < 45, f"OVA duration {dur_min:.1f}min, expected ~44min"


class TestDisc29Specials:
def test_special_feature_count(self, disc29_analysis: DiscAnalysis) -> None:
assert len(disc29_analysis.special_features) == 3

def test_all_digital_archives(self, disc29_analysis: DiscAnalysis) -> None:
for sf in disc29_analysis.special_features:
assert sf.category == "digital_archive"


class TestDisc29Metadata:
def test_disc_title(self, disc29_analysis: DiscAnalysis) -> None:
assert disc29_analysis.disc_title == "TEST DISC 29"
Loading