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
42 changes: 40 additions & 2 deletions bdpl/analyze/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,11 +310,26 @@ def _detect_special_features(
# chapter-selection / main-play page.
if h.jump_title in chapter_selection_jt:
continue
# Skip if this page also has buttons targeting non-episode
# playlists — the episode button is likely navigation (e.g.
# "back to movie") rather than a commentary feature.
page_has_non_ep_target = any(
title_to_mpls.get(jt_val - 1) not in ep_playlists
for jt_val in page_jt.get(h.page_id, set())
if title_to_mpls.get(jt_val - 1) is not None
)
if page_has_non_ep_target:
continue
category = "commentary"
else:
category = classifications.get(mpls, "extra")

ch_start = h.register_sets.get(2)
# For digital_archive playlists, ch_start=0 means "play from
# beginning" — normalise to None so it deduplicates with the
# title-hint fallback entry for the whole playlist.
if category == "digital_archive" and ch_start == 0:
ch_start = None
key = (mpls, ch_start)
if key in seen:
continue
Expand Down Expand Up @@ -864,6 +879,7 @@ def _maybe_collapse_variant_episodes(
episodes: list[Episode],
playlists: list[Playlist],
variant_mpls: set[str],
all_playlists: list[Playlist] | None = None,
) -> list[Episode]:
"""Collapse chapter-split episodes back to one when variant dedup caused it.

Expand Down Expand Up @@ -897,6 +913,18 @@ def _maybe_collapse_variant_episodes(
if playlist is None:
return episodes

# Only collapse when a removed variant actually shares clips with the
# episode playlist. Unrelated variant groups (e.g. duplicate specials)
# should not trigger a collapse.
if all_playlists and playlist.play_items:
ep_clips = {pi.clip_id for pi in playlist.play_items}
has_related_variant = any(
pl.mpls in variant_mpls and any(pi.clip_id in ep_clips for pi in pl.play_items)
for pl in all_playlists
)
if not has_related_variant:
return episodes

segments = [
SegmentRef(
key=pi.segment_key(),
Expand Down Expand Up @@ -1075,11 +1103,20 @@ def scan_disc(
label_segments(unique_playlists, segment_freq)

# 5. Classify playlists
classifications = classify_playlists(unique_playlists, play_all)
title_hint_mpls: set[str] = set()
for pl_nums in hints.get("title_playlists", {}).values():
for n in pl_nums:
title_hint_mpls.add(f"{n:05d}.mpls")
classifications = classify_playlists(
unique_playlists, play_all, title_hint_mpls=title_hint_mpls
)
analysis["classifications"] = classifications

# 6. Order episodes
episodes = order_episodes(unique_playlists, play_all, classifications)
ig_marks = hints.get("ig_menu", {}).get("chapter_marks")
episodes = order_episodes(
unique_playlists, play_all, classifications, ig_chapter_marks=ig_marks
)

episodes = _maybe_keep_single_title_episode(
episodes,
Expand All @@ -1094,6 +1131,7 @@ def scan_disc(
episodes,
unique_playlists,
variant_mpls,
all_playlists=playlists,
)

# If episodes came from Play All decomposition, reclassify playlists
Expand Down
61 changes: 55 additions & 6 deletions bdpl/analyze/classify.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,58 @@
_PREVIEW_MAX = 60
_BODY_MIN_S = 300 # 5 minutes
_DIGITAL_ARCHIVE_MIN_ITEMS = 20
_DIGITAL_ARCHIVE_HINT_MIN_ITEMS = 5
_DIGITAL_ARCHIVE_MAX_TOTAL_S = 300
_DIGITAL_ARCHIVE_MAX_AVG_ITEM_S = 0.5
_DIGITAL_ARCHIVE_MIN_UNIQUE_RATIO = 0.8
_DIGITAL_ARCHIVE_NO_AUDIO_RATIO = 0.8
_AUDIO_CODECS = frozenset(
{
"LPCM",
"AC3",
"E-AC3",
"DTS",
"DTS-HD",
"DTS-HD MA",
"TrueHD",
}
)


def _items_lack_audio(pl: Playlist) -> bool:
"""Return True when most play items have no audio streams (still images)."""
if not pl.play_items:
return False
no_audio = sum(
1 for pi in pl.play_items if not any(s.codec in _AUDIO_CODECS for s in pi.streams)
)
return no_audio / len(pl.play_items) >= _DIGITAL_ARCHIVE_NO_AUDIO_RATIO


def is_digital_archive_playlist(pl: Playlist) -> bool:
def is_digital_archive_playlist(
pl: Playlist,
*,
has_title_hint: bool = False,
) -> bool:
"""Return True when playlist shape resembles an image archive.

Heuristic targets menu-like playlists made of many ultra-short items
(often one still image per clip) and avoids short video extras.
Three independent signals lower the item-count floor when combined
with the base shape checks (avg duration ≤ 0.5 s, unique ratio ≥ 0.8):

1. **Item count ≥ 20** — strong shape signal, sufficient alone.
2. **Title hint** — disc navigation references the playlist as real
content. Lowers floor to 5 items.
3. **No audio streams** — play items contain only video (+ IG overlay),
characteristic of still-image galleries. Lowers floor to 5 items.
"""
item_count = len(pl.play_items)
if item_count < _DIGITAL_ARCHIVE_MIN_ITEMS:

# Determine minimum item threshold based on available evidence.
has_structural_evidence = has_title_hint or _items_lack_audio(pl)
min_items = (
_DIGITAL_ARCHIVE_HINT_MIN_ITEMS if has_structural_evidence else _DIGITAL_ARCHIVE_MIN_ITEMS
)
if item_count < min_items:
return False

total_s = pl.duration_seconds
Expand Down Expand Up @@ -110,13 +149,23 @@ def label_segments(playlists: list[Playlist], segment_freq: dict[tuple, int]) ->
pi.label = "UNKNOWN"


def classify_playlists(playlists: list[Playlist], play_all: list[Playlist]) -> dict[str, str]:
def classify_playlists(
playlists: list[Playlist],
play_all: list[Playlist],
title_hint_mpls: set[str] | None = None,
) -> dict[str, str]:
"""Return dict mpls_name -> category string.

Parameters:
title_hint_mpls: MPLS names referenced by disc title navigation
hints. Used as structural evidence for digital archive
detection when the item count is below the strict threshold.

Categories: 'episode', 'play_all', 'menu', 'extra', 'bumper',
'creditless_op', 'creditless_ed', 'digital_archive'.
"""
play_all_names = {pl.mpls for pl in play_all}
hint_names = title_hint_mpls or set()
result: dict[str, str] = {}

for pl in playlists:
Expand All @@ -126,7 +175,7 @@ def classify_playlists(playlists: list[Playlist], play_all: list[Playlist]) -> d
result[pl.mpls] = "play_all"
continue

if is_digital_archive_playlist(pl):
if is_digital_archive_playlist(pl, has_title_hint=pl.mpls in hint_names):
result[pl.mpls] = "digital_archive"
continue

Expand Down
22 changes: 20 additions & 2 deletions bdpl/analyze/ordering.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,18 @@ def _episodes_from_play_all(

def _episodes_from_chapters(
playlist: Playlist,
ig_chapter_marks: list[int] | None = None,
) -> list[Episode]:
"""Split a single long playlist into episodes using chapter marks.

Used when a playlist contains one (or few) very long play item(s) with
multiple episodes encoded back-to-back, distinguishable only by chapters.

When *ig_chapter_marks* are provided (from IG menu buttons), they serve as
structural confirmation that the playlist contains multiple episodes.
Without such evidence, a minimum of 3 estimated episodes is required —
an ``est_count`` of 2 is ambiguous (could be a single ~50 min movie).

Heuristic: group consecutive chapters into blocks whose total duration
falls within episode range (10–45 min). When a running block exceeds the
expected episode length, start a new episode at the chapter boundary.
Expand Down Expand Up @@ -139,6 +145,13 @@ def _episodes_from_chapters(
if est_count <= 1:
return [] # Not worth splitting

# IG chapter marks provide structural evidence of multiple episodes.
# Without such evidence, require est_count >= 3 because est_count == 2
# (~50 min total) is ambiguous — could be a single movie.
has_ig_confirmation = ig_chapter_marks is not None and len(ig_chapter_marks) >= 2
if est_count <= 2 and not has_ig_confirmation:
return []

# Target duration per episode
target_dur_ms = total_dur_ms / est_count
# Tolerance: 60% to 140% of target
Expand Down Expand Up @@ -222,9 +235,14 @@ def order_episodes(
playlists: list[Playlist],
play_all_playlists: list[Playlist],
classifications: dict[str, str] | None = None,
ig_chapter_marks: list[int] | None = None,
) -> list[Episode]:
"""Infer ordered episode list.

Parameters:
ig_chapter_marks: Chapter indices from IG menu buttons that confirm
episode boundaries. Passed through to chapter-splitting logic.

Strategy:
1. If there are individual episode-length playlists (>10 min, not in
play_all list) with unique body segments, use those.
Expand Down Expand Up @@ -255,7 +273,7 @@ def order_episodes(
pa_episodes = _episodes_from_play_all(best_pa)
# If play-all decomposition yields only 1 episode, try chapter-based
if len(pa_episodes) <= 1 and best_pa.chapters:
ch_episodes = _episodes_from_chapters(best_pa)
ch_episodes = _episodes_from_chapters(best_pa, ig_chapter_marks)
if len(ch_episodes) > len(pa_episodes):
pa_episodes = ch_episodes

Expand Down Expand Up @@ -285,7 +303,7 @@ def order_episodes(
# it likely contains multiple episodes in a single m2ts
if len(individual_eps) == 1:
candidate = individual_eps[0]
ch_episodes = _episodes_from_chapters(candidate)
ch_episodes = _episodes_from_chapters(candidate, ig_chapter_marks)
if len(ch_episodes) >= 2:
return ch_episodes
return _episodes_from_individual(individual_eps)
Expand Down
60 changes: 60 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,66 @@ def disc13_analysis(disc13_path):
return _analyze_fixture(disc13_path)


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


@pytest.fixture(scope="session")
def disc15_analysis(disc15_path):
"""Run and cache full analysis for the bundled disc15 fixture."""
return _analyze_fixture(disc15_path)


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


@pytest.fixture(scope="session")
def disc16_analysis(disc16_path):
"""Run and cache full analysis for the bundled disc16 fixture."""
return _analyze_fixture(disc16_path)


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


@pytest.fixture(scope="session")
def disc17_analysis(disc17_path):
"""Run and cache full analysis for the bundled disc17 fixture."""
return _analyze_fixture(disc17_path)


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


@pytest.fixture(scope="session")
def disc18_analysis(disc18_path):
"""Run and cache full analysis for the bundled disc18 fixture."""
return _analyze_fixture(disc18_path)


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


@pytest.fixture(scope="session")
def disc19_analysis(disc19_path):
"""Run and cache full analysis for the bundled disc19 fixture."""
return _analyze_fixture(disc19_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/disc15/CLIPINF/00000.clpi
Binary file not shown.
Binary file added tests/fixtures/disc15/CLIPINF/00001.clpi
Binary file not shown.
Binary file added tests/fixtures/disc15/CLIPINF/00002.clpi
Binary file not shown.
Binary file added tests/fixtures/disc15/CLIPINF/00003.clpi
Binary file not shown.
Binary file added tests/fixtures/disc15/CLIPINF/00004.clpi
Binary file not shown.
Binary file added tests/fixtures/disc15/CLIPINF/00006.clpi
Binary file not shown.
Binary file added tests/fixtures/disc15/CLIPINF/00007.clpi
Binary file not shown.
6 changes: 6 additions & 0 deletions tests/fixtures/disc15/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 15</di:name></di:title>
</di:discinfo>
</disclib>
Binary file added tests/fixtures/disc15/MovieObject.bdmv
Binary file not shown.
Binary file added tests/fixtures/disc15/PLAYLIST/00000.mpls
Binary file not shown.
Binary file added tests/fixtures/disc15/PLAYLIST/00001.mpls
Binary file not shown.
Binary file added tests/fixtures/disc15/PLAYLIST/00002.mpls
Binary file not shown.
Binary file added tests/fixtures/disc15/ics_menu.bin
Binary file not shown.
Binary file added tests/fixtures/disc15/index.bdmv
Binary file not shown.
Binary file added tests/fixtures/disc16/CLIPINF/00000.clpi
Binary file not shown.
Binary file added tests/fixtures/disc16/CLIPINF/00001.clpi
Binary file not shown.
Binary file added tests/fixtures/disc16/CLIPINF/00002.clpi
Binary file not shown.
Binary file added tests/fixtures/disc16/CLIPINF/00003.clpi
Binary file not shown.
Binary file added tests/fixtures/disc16/CLIPINF/00004.clpi
Binary file not shown.
Binary file added tests/fixtures/disc16/CLIPINF/00005.clpi
Binary file not shown.
Binary file added tests/fixtures/disc16/CLIPINF/00006.clpi
Binary file not shown.
Binary file added tests/fixtures/disc16/CLIPINF/00007.clpi
Binary file not shown.
Binary file added tests/fixtures/disc16/CLIPINF/00008.clpi
Binary file not shown.
Binary file added tests/fixtures/disc16/CLIPINF/00009.clpi
Binary file not shown.
Binary file added tests/fixtures/disc16/CLIPINF/00010.clpi
Binary file not shown.
Binary file added tests/fixtures/disc16/CLIPINF/00011.clpi
Binary file not shown.
6 changes: 6 additions & 0 deletions tests/fixtures/disc16/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 16</di:name></di:title>
</di:discinfo>
</disclib>
Binary file added tests/fixtures/disc16/MovieObject.bdmv
Binary file not shown.
Binary file added tests/fixtures/disc16/PLAYLIST/00000.mpls
Binary file not shown.
Binary file added tests/fixtures/disc16/PLAYLIST/00001.mpls
Binary file not shown.
Binary file added tests/fixtures/disc16/PLAYLIST/00002.mpls
Binary file not shown.
Binary file added tests/fixtures/disc16/PLAYLIST/00003.mpls
Binary file not shown.
Binary file added tests/fixtures/disc16/PLAYLIST/00004.mpls
Binary file not shown.
Binary file added tests/fixtures/disc16/PLAYLIST/00005.mpls
Binary file not shown.
Binary file added tests/fixtures/disc16/PLAYLIST/00006.mpls
Binary file not shown.
Binary file added tests/fixtures/disc16/PLAYLIST/00007.mpls
Binary file not shown.
Binary file added tests/fixtures/disc16/PLAYLIST/00008.mpls
Binary file not shown.
Binary file added tests/fixtures/disc16/PLAYLIST/00009.mpls
Binary file not shown.
Binary file added tests/fixtures/disc16/ics_menu.bin
Binary file not shown.
Binary file added tests/fixtures/disc16/index.bdmv
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00000.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00001.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00002.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00003.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00004.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00005.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00006.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00007.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00008.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00009.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00010.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00011.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00012.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00013.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00014.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00015.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00016.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00017.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00018.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00019.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00020.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00021.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00022.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00023.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00024.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00025.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00026.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00027.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00028.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00029.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00030.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00031.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00032.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00033.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00034.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00035.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00036.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00037.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00038.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00039.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00040.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00041.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00042.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00043.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00044.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00045.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00046.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00047.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00048.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00049.clpi
Binary file not shown.
Binary file added tests/fixtures/disc17/CLIPINF/00050.clpi
Binary file not shown.
6 changes: 6 additions & 0 deletions tests/fixtures/disc17/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 17</di:name></di:title>
</di:discinfo>
</disclib>
Binary file added tests/fixtures/disc17/MovieObject.bdmv
Binary file not shown.
Binary file added tests/fixtures/disc17/PLAYLIST/00000.mpls
Binary file not shown.
Binary file added tests/fixtures/disc17/PLAYLIST/00001.mpls
Binary file not shown.
Binary file added tests/fixtures/disc17/PLAYLIST/00002.mpls
Binary file not shown.
Binary file added tests/fixtures/disc17/PLAYLIST/00003.mpls
Binary file not shown.
Binary file added tests/fixtures/disc17/ics_menu.bin
Binary file not shown.
Binary file added tests/fixtures/disc17/index.bdmv
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00000.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00001.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00002.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00003.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00004.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00005.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00006.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00007.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00008.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00009.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00010.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00011.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00012.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00013.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00014.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00015.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00016.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00017.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00018.clpi
Binary file not shown.
Binary file added tests/fixtures/disc18/CLIPINF/00019.clpi
Binary file not shown.
6 changes: 6 additions & 0 deletions tests/fixtures/disc18/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 18</di:name></di:title>
</di:discinfo>
</disclib>
Binary file added tests/fixtures/disc18/MovieObject.bdmv
Binary file not shown.
Binary file added tests/fixtures/disc18/PLAYLIST/00000.mpls
Binary file not shown.
Binary file added tests/fixtures/disc18/PLAYLIST/00001.mpls
Binary file not shown.
Binary file added tests/fixtures/disc18/PLAYLIST/00002.mpls
Binary file not shown.
Binary file added tests/fixtures/disc18/PLAYLIST/00003.mpls
Binary file not shown.
Binary file added tests/fixtures/disc18/PLAYLIST/00004.mpls
Binary file not shown.
Binary file added tests/fixtures/disc18/PLAYLIST/00005.mpls
Binary file not shown.
Binary file added tests/fixtures/disc18/ics_menu.bin
Binary file not shown.
Binary file added tests/fixtures/disc18/index.bdmv
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00000.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00001.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00002.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00003.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00004.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00005.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00006.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00007.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00008.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00009.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00010.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00011.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00012.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00013.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00014.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00015.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00016.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00017.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00018.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00019.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00020.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00021.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00022.clpi
Binary file not shown.
Binary file added tests/fixtures/disc19/CLIPINF/00023.clpi
Binary file not shown.
6 changes: 6 additions & 0 deletions tests/fixtures/disc19/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 19</di:name></di:title>
</di:discinfo>
</disclib>
Binary file added tests/fixtures/disc19/MovieObject.bdmv
Binary file not shown.
Binary file added tests/fixtures/disc19/PLAYLIST/00000.mpls
Binary file not shown.
Binary file added tests/fixtures/disc19/PLAYLIST/00001.mpls
Binary file not shown.
Binary file added tests/fixtures/disc19/PLAYLIST/00002.mpls
Binary file not shown.
Binary file added tests/fixtures/disc19/PLAYLIST/00003.mpls
Binary file not shown.
Binary file added tests/fixtures/disc19/ics_menu.bin
Binary file not shown.
Binary file added tests/fixtures/disc19/index.bdmv
Binary file not shown.
7 changes: 6 additions & 1 deletion tests/test_digital_archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
export_digital_archive_images,
get_digital_archive_dry_run,
)
from bdpl.model import StreamInfo
from tests.builders import (
build_disc_analysis,
build_play_item,
Expand All @@ -27,8 +28,12 @@ def test_digital_archive_playlist_detected_from_structure() -> None:


def test_digital_archive_playlist_rejects_low_item_count() -> None:
"""Few short items should not trigger digital archive classification."""
"""Few short items with audio should not trigger digital archive classification."""
items = [build_play_item(f"{i:05d}", 0.0, 0.04) for i in range(10)]
# Add audio streams so the no-audio signal does not lower the threshold.
audio = StreamInfo(pid=0x1100, stream_type=128, codec="LPCM", lang="jpn")
for item in items:
item.streams = [audio]
pl = build_playlist("00003.mpls", items)
assert not is_digital_archive_playlist(pl)

Expand Down
Loading