From e5989c8270bce6aac40e6f1f54bd411ad244de16 Mon Sep 17 00:00:00 2001 From: MattJackson <1085847+MattJackson@users.noreply.github.com> Date: Sun, 10 May 2026 07:42:45 -0700 Subject: [PATCH] labels: expose analyze() for corpus regression tooling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Promotes `mod labels` to `pub mod labels` and adds `analyze()` plus `LabelAnalysis` (both `#[doc(hidden)]`) so an out-of-tree diagnostic binary (freemkv-tools labels-analyze) can introspect which BD-J parser matched a given disc, what JAR files the discriminators saw, and what labels came out — without going through the production `apply()` path that mutates DiscTitles. Also adds `tracing::info!(parser = name, "label parser matched")` / "no label parser matched" inside `extract()`. Dev-only signal: users get the same seamless behavior; developers can finally tell whether a disc hit a real parser or fell through to the codec-name fallback in fill_defaults(). The new `jar_inventory()` helper deduplicates and sorts filenames under any `/BDMV/JAR//` subdirectory — same plumbing the existing `jar_file_exists()` discriminators use, just enumerated rather than predicate-tested. Used by `analyze()` to surface unrecognized parser-source files when no parser matches, which is the input to "do we need a new parser?" triage. No behavior change to the production label path. `apply()` and `extract()` remain functionally identical; the new public surface exists alongside. --- src/labels/mod.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++++- src/lib.rs | 2 +- 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/src/labels/mod.rs b/src/labels/mod.rs index 43386be..409f440 100644 --- a/src/labels/mod.rs +++ b/src/labels/mod.rs @@ -268,16 +268,85 @@ fn generate_audio_label( } fn extract(reader: &mut dyn SectorReader, udf: &UdfFs) -> Vec { - for (_name, detect, parse) in PARSERS { + for (name, detect, parse) in PARSERS { if detect(udf) { + tracing::info!(parser = name, "label parser matched"); if let Some(labels) = parse(reader, udf) { return labels; } } } + tracing::info!("no label parser matched"); Vec::new() } +/// Diagnostic introspection — returns the parser that matched, the +/// labels it emitted, and the inventory of files under `/BDMV/JAR/*/` +/// that the discriminators looked at. Intended for `freemkv-tools +/// labels-analyze` and corpus regression tooling, not production code +/// paths. The matching/parsing logic is identical to [`extract`]; only +/// the return shape is richer. +#[doc(hidden)] +pub fn analyze(reader: &mut dyn SectorReader, udf: &UdfFs) -> LabelAnalysis { + let inventory = jar_inventory(udf); + for (name, detect, parse) in PARSERS { + if detect(udf) { + tracing::info!(parser = name, "label parser matched"); + if let Some(labels) = parse(reader, udf) { + return LabelAnalysis { + parser: Some(name), + jar_inventory: inventory, + labels, + }; + } + } + } + tracing::info!("no label parser matched"); + LabelAnalysis { + parser: None, + jar_inventory: inventory, + labels: Vec::new(), + } +} + +/// Result of [`analyze`]. +#[doc(hidden)] +#[derive(Debug, Clone)] +pub struct LabelAnalysis { + /// Which parser matched ("paramount" / "criterion" / "pixelogic" / + /// "ctrm"), or `None` if no parser matched and the labels code + /// would have fallen through to `fill_defaults`. + pub parser: Option<&'static str>, + /// Filenames found under any `/BDMV/JAR/*/` subdirectory, deduped + /// and sorted. Helps spot unknown authoring formats when `parser` + /// is `None`. + pub jar_inventory: Vec, + /// Raw labels emitted by the matched parser (empty if `parser` is + /// `None`). + pub labels: Vec, +} + +/// List filenames found under any `/BDMV/JAR//` subdirectory of +/// the disc. Deduped, sorted. Returns an empty vec if no JAR dir is +/// present. +fn jar_inventory(udf: &UdfFs) -> Vec { + let Some(jar_dir) = udf.find_dir("/BDMV/JAR") else { + return Vec::new(); + }; + let mut out: Vec = Vec::new(); + for entry in &jar_dir.entries { + if entry.is_dir { + for child in &entry.entries { + if !child.is_dir && !out.contains(&child.name) { + out.push(child.name.clone()); + } + } + } + } + out.sort(); + out +} + // ── Shared helpers ───────────────────────────────────────────────────────── /// Check if a file exists in any BDMV/JAR subdirectory. diff --git a/src/lib.rs b/src/lib.rs index 5fa8b35..774e7c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -84,7 +84,7 @@ pub(crate) mod identity; pub(crate) mod ifo; pub(crate) mod io; pub mod keydb; -pub(crate) mod labels; +pub mod labels; pub(crate) mod mpls; pub mod mux; pub mod pes;