Skip to content

feat(markers): design spec for multi-server intro/credits detection#241

Draft
stevezau wants to merge 17 commits into
devfrom
feat/markers-detection
Draft

feat(markers): design spec for multi-server intro/credits detection#241
stevezau wants to merge 17 commits into
devfrom
feat/markers-detection

Conversation

@stevezau

Copy link
Copy Markdown
Owner

Summary

Draft PR carrying the design spec for adding multi-server intro/credits detection (Plex + Emby + Jellyfin). No code yet — this PR is the design document only, opened in draft so it can be reviewed in GitHub-context before any implementation work lands.

Spec lives at docs/design/2026-05-17-intro-credits-detection-design.md.

Supersedes #191 (Plex-only, blackdetect+silencedetect heuristic that failed on Superman II and NCIS:Sydney — see the spec's §1 retrospective).

Headline design choices

  • Detection: 4-tier cascade — TheIntroDB lookup (free, TMDb-keyed) → chromaprint cross-episode (TV, reimplemented from intro-skipper spec) → adaptive binary-search blackdetect (movies — the structural fix for PR feat: add intro and credits detection with Plex marker support #191's mid-scene-black failure mode) → optional PaddleOCR PP-OCRv5 (Apache-2.0, GPU).
  • Single canonical sidecar<canonical_path>.markers.json next to media. One detection run, multiple publishers fan out.
  • Per-server publishers mirror the existing OutputAdapter pattern:
    • Plex — trigger native via episode.analyze() for Plex Pass; direct SQLite taggings write (off by default, provenance/restore) for non-Pass.
    • Emby — read via GET /Items/{Id}?Fields=Chapters; write via the existing community sydlexius/Segment_Reporting plugin.
    • Jellyfin — ship a new C# companion plugin (MediaPreviewSegments) implementing IMediaSegmentProvider. Built in our CI, distributed via a plugin-manifest URL hosted by our web app.
  • Marker Inspector UI — new /inspector/markers page (sibling of BIF Inspector). Search → audio waveform + timeline + side-by-side server vs detected markers + manual nudge + one-click apply.

Why the write-path matrix is the core constraint

Server HTTP write DB write Plugin write
Plex ❌ 400 on intro/credits ⚠️ taggings (risky) N/A
Emby ❌ no endpoint ⚠️ rewrites on scan ✅ Segment_Reporting
Jellyfin ❌ GET-only controller ⚠️ wiped by next scan ✅ our new plugin

All three native HTTP write paths are unusable. Plugin/DB is the only sustainable route, and Jellyfin requires us to ship a plugin (which is why this is multi-week work and not multi-day).

Phased rollout

The spec breaks into four PRs against feat/markers-detection:

  1. Phase A — Scaffolding + TheIntroDB lookup + read-only Inspector (~1 week, useful on its own)
  2. Phase B — Detection algorithms (chromaprint + adaptive blackdetect) + sidecar writes (~2 weeks)
  3. Phase C — Per-server publishers + C# Jellyfin plugin (~2 weeks)
  4. Phase D — Polish, optional OCR, bulk Inspector, TheIntroDB submit-back (~1.5 weeks)

Open questions (also tracked in spec §13)

  • Submit detections back to TheIntroDB by default, or opt-in only?
  • C# Jellyfin plugin: subdir of this repo (recommended) or separate repo?
  • Tier 4 OCR: bundled in main Docker image (+2GB) or separate :with-ocr tag?
  • Marker Inspector — separate from or unified with BIF Inspector (tabs)?

Test plan (for the spec itself, not implementation)

  • Spec reads cleanly end-to-end
  • Phase A scope is implementable as a single follow-up PR
  • Open questions in §13 are decided before Phase B starts
  • No factual drift between spec and codebase (Architecture Review pre-commit found 3 LOW issues, fixed inline)

🤖 Generated with Claude Code

stevezau and others added 3 commits May 17, 2026 09:39
Supersedes the stalled PR #191 (Plex-only, blackdetect+silencedetect
heuristic that failed on Superman II and NCIS:Sydney). Designs a
multi-server pipeline that:

- Reads existing markers from Plex/Emby/Jellyfin via their public APIs
- Detects via a 4-tier cascade: TheIntroDB lookup, chromaprint
  cross-episode (TV), adaptive binary-search blackdetect (movies),
  optional PaddleOCR (Tier 4, GPU)
- Emits canonical .markers.json sidecars next to media
- Publishes per-server: Plex SQLite (provenance/restore for non-Pass);
  Emby via sydlexius/Segment_Reporting; Jellyfin via a new C# companion
  plugin (MediaPreviewSegments) shipped in this repo
- Adds a Marker Inspector UI page (sibling of BIF Inspector)

Phased rollout over 4 PRs (A scaffolding + TheIntroDB, B algorithms,
C publishers + Jellyfin plugin, D polish + OCR).

Architecture Review run pre-commit; 3 LOW findings (operator precedence
in code block, class name nits, file-path drift) addressed inline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- TheIntroDB submit-back is opt-in only (default off)
- Jellyfin plugin: extend existing Jellyfin.Plugin.MediaPreviewBridge
  rather than ship a second plugin. Adds MarkerBridgeController +
  MarkerSegmentProvider to the same project; bumps version to
  10.11.1.0; reuses existing CI workflow and manifest URL.
- Inspector unified at /inspector with tabs (Frames / Markers / Audio);
  /bif-viewer 301-redirects to /inspector?tab=frames
- OCR Tier 4 still open — clarified the three concrete options
  (drop entirely, bundle, separate :with-ocr tag)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Plex's native credits detection uses OCR-style scrolling-text
recognition combined with black-frame detection (Plex 2023 blog).
EmbyCredits uses Tesseract OCR. Only Jellyfin's intro-skipper omits
OCR, and movies are its known gap. Adopting OCR brings non-Pass users
to feature parity with Plex's gold standard.

Tag separation keeps the default image lean (~2GB smaller). Settings
flag is runtime-detected so the UI only offers it when paddleocr is
importable — users switch tags by changing one line in compose.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
stevezau and others added 10 commits May 17, 2026 10:13
Live-tested the API: real path is /v1/media (not /media), real param
is tmdb_id (not tmdbId). Earlier research agent had both wrong.

Real coverage (from /v1/stats today):
- 1,744 shows + 272 movies, 45,274 episodes, 323,404 submissions
- 295 contributors, 81,435 accepted timestamps
- Empirical hit rate: ~40% popular TV S1E1, ~18% popular movies

Rate limits are binding: 100/day anonymous per IP, 500/day per
authenticated user. No bulk-export endpoint. Implication: Tier 1
is opportunistic (new items via webhook, Inspector lookups, slow
background backfill) NOT a library-bootstrap fast path.

Mirrored OpenAPI spec to docs/design/theintrodb-openapi-v2.yaml so
implementation can work offline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…s, Plex DB write details

CRITICAL: TheIntroDB v1 sunsets 2026-08-16. Every /v1/* response carries
sunset header. Spec now uses /v2/media throughout.

Added Tier 1b (IntroDB.app, ~73% hit rate on TV but mostly single-
submission entries — gated by confidence floor) and Tier 1c
(anime-skip.com for anime libraries — AniList-keyed, separate ecosystem,
only fires on kind="anime" libraries).

Sustainability note: TheIntroDB is one-maintainer (Pasithea0) but
community-active (295 contributors, real consensus voting, 3 plugin
releases in 10 weeks). MED risk over 12 months — mitigated by caching
positive hits forever.

Plex DB write section rewritten with verified 2026 details:
- REST marker API still 400s (Plex admin confirmed in Feb-Apr 2026
  dev forum thread #931778)
- Use narrow endpoints PUT /library/metadata/{id}/intro and /credits,
  not the broad /analyze (markers-only, async fire-and-forget)
- ONE tags row (tag_type=12) for ALL markers; intro/credits/commercial
  differentiated by taggings.text — earlier spec had this wrong
- MUST write BOTH taggings AND media_parts.extra_data (the load-bearing
  detail Casvt's script misses but MarkerEditorForPlex gets right —
  without the part-level denormalized JSON, markers vanish on re-analyze)
- Editions vs versions handled separately
- extra_data JSON shape version-specific (PMS ≥1.40 vs older)
- Provenance lives in side-car DB, not in Plex; thumb_url sentinel
  is a legacy hack now abandoned
- Plex Pass requirement is on PLAYER account, not just server admin

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…h-review findings

Empirical finding from 160-file probe of user's /data library:
- 20% TV / 16% movies have explicit credit-marker chapter names
- Netflix/Amazon WEBDLs heavily over-indexed (frame-accurate boundaries
  authored by the streamer)
- Bluray rips rarely have semantically-labelled chapters

New Tier 0 piggybacks on the EXISTING pymediainfo MediaInfo.parse() call
in processing/generator.py:291 — Menu track exposes chapter names with
HH_MM_SSmmm key format and 'en:'-prefixed values. Live-verified.

Other findings incorporated:
- AcoustID side-channel DEAD (empirically 0/5 popular shows match;
  in-show audio mixes differ from MusicBrainz recordings)
- Subtitle dialogue gaps too noisy (top gap was a scene break, not intro)
- HLS/SCTE-35 doesn't transfer to MKV containers (RFC 9559 verified)
- Sonarr/Radarr release group becomes a routing hint, not marker source
- ChapterDB.org → chapterdb.plex.tv read-only mirror as Phase D
  opportunistic Tier 3b for movies

Cascade now has 5 tiers. Phase A starts with Tier 0 (free) + Tier 1
TheIntroDB v2 + Tier 1c anime-skip read-only.

Architecture Review pre-commit found 2 MED + 1 LOW; all addressed:
- MED: original spec claimed Tier 0 piggybacks on ffprobe; codebase
  actually uses pymediainfo. Verified live that Menu-track parse exposes
  chapter names equivalently — spec rewritten around pymediainfo.
- MED: global settings nested under `settings.markers` but actual
  settings.json layout is flat at root. Now top-level `markers` key
  sibling of gpu_config/media_servers.
- LOW: Phase A claimed Inspector tab, but unified-Inspector shell
  doesn't exist yet. Phase A now ships standalone /markers page;
  Phase D handles the BIF→tabbed-Inspector port.

Also added empirical hit-rate data, expanded risk section to 9 items
with concrete mitigations, and committed to TheIntroDB v2 URL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Five parallel research streams (Plex/Jellyfin/Emby community sentiment,
cross-server patterns, UX feature-request mine) surfaced concrete
gaps no existing tool fills. Major additions:

NEW §7.5 — Community-validated UX features (the differentiator):
- 7.5.1 Locked markers + per-show overrides (5.75-year community pain)
- 7.5.2 Apply-pattern-to-season (nurbles 2020, never built)
- 7.5.3 Per-client compatibility matrix in Inspector (truth-table
  showing which clients render which markers — Swiftfin/Roku/Tizen
  blind spots make this critical UX)
- 7.5.4 Multi-OP anime mode (intro-skipper #658 dismissed)
- 7.5.5 Cross-server marker bridge (Plex → Jellyfin/Emby) — THE
  killer feature solving shared-user entitlement gap + migration
- 7.5.6 EDL sidecar export (free Kodi support)
- 7.5.7 Submit-back to TheIntroDB + SkipMe.db (both, not just one)
- 7.5.8 Cache sharding from day one (50TB lib = 500k files)
- 7.5.9 Bulk-edit grid view
- 7.5.10 Webhook on segment events

NEW Tier 2.5 — Subtitle-keyword recap detection (THE holy-grail
feature no tool ships — intro-skipper #763 open May 2026, #136
open since 2024, Emby #120144, Plex #787447 all punted). bw_plex
demonstrated subtitle keyword "Previously on" approach works.
~10ms per episode, no GPU, near-100% subtitle coverage on streamer
WEBDLs. Closes a 5-year community gap.

MarkerSegment additions:
- locked: bool — re-detection never overrides
- seed: bool — user-blessed fingerprint anchor for apply-to-season
- schema_version: bumped to 1
- source enum expanded with introdb/anime_skip/skipmedb/manual/
  chapter/subtitle_recap

Chromaprint algorithm constants corrected against intro-skipper
PluginConfiguration.cs canonical values:
- MaximumFingerprintPointDifferences = 6 (was 8 in spec)
- BlackFrameThreshold = 28 of 255 (was 0.10)
- ChromaprintConstants.SampleDuration = 4096/11025/3 ≈ 0.124s
- All other defaults verified

Known-failure-mode documentation added:
- Bob's Burgers S01 chromaprint failure (skipme.db #29)
- Plex 10-min ceiling matches Emby ceiling (NCIS:Sydney pattern)
- Plex multi-version file replacement bug (#782058, since March 2022)
- Plex shared-user entitlement gating (#937108)

Settings schema expanded:
- per_show_overrides (the killer setting)
- subtitle_recap_keywords (multilingual)
- client_compatibility_path
- anime_max_op_clusters
- skipmedb_submit, edl_export, webhook_events
- cache_shard_depth (operational correctness)

Spec is now 1239 lines (was 1003). PR #241 updated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Architecture Review pre-commit run against the 1239-line spec found:
- 5 HIGH severity issues
- 5 MED severity issues
- 3 LOW severity issues

All HIGHs and most MEDs fixed inline:

HIGH #1 — MediaInfo.parse line number: corrected from :291 (startup
  probe) to :769 (per-file pipeline call site). Tier 0's "free
  piggyback" claim is preserved.

HIGH #2 + #3 — Phase A scope expansion: tightened from claimed-1-week-
  but-actually-2-3-weeks to a real 5-7-day MVP. Tier 1c, IntroDB
  fallback, Emby/Jellyfin reads, sidecar writes, cache sharding moved
  to Phase B. Settings migration writes ONLY Phase A keys (9 keys)
  instead of all 18 to avoid stranding feature flags.

HIGH #4 — Tier 2.5 subtitle recap detector now wired into §9 pipeline
  as sub-phase 2c (subtitle extract) + 2d (subtitle scan). Full 7-step
  detection-phase table added showing tier ordering, skip conditions,
  output shape. Tier 2 (chromaprint) clarified as "deposits fingerprint,
  pass-2 runs post-dispatch via new marker_post_detection job type".

HIGH #5 — Tier numbering inconsistency: §0 TL;DR now says "seven-step
  cascade — five primary tiers (0/1/2/3/4) with sub-tier fallbacks
  (1b, 1c, 2.5)". Consistent across §0/§5/§12.

MED #6 — Library.kind clarified: existing servers/base.py:118 field is
  opaque and set to movie/show by enumeration. We add a separate per-
  library setting markers.anime_mode_libraries: list[str] instead of
  repurposing kind. Phase D may add auto-detection from genre.

MED #7 — MarkerSegment.locked/seed propagated to:
  - Canonical sidecar JSON example (now shows all 9 fields)
  - Provenance DB schema (added locked, seed, source, detector columns)
  - Plex restore loop (checks locked before re-INSERT; locked=1 wins
    over re-detection candidate)
  - Consumer rules section documenting forward-compat behaviour

MED #8 — Cross-server bridge now has its own subsection in §9
  describing job type (source=bridge), failure scope (per-server
  try/except), and confidence-gate bypass for native_plex segments.

MED #9 — Plex /intro and /credits endpoints: added explicit BoolInt
  param shape (force=1 not True), full server.query() snippet, and
  mandatory test asserting isinstance(params['force'], int) and not
  isinstance(params['force'], bool) to catch the BoolInt 500 trap.

MED #10 — media_parts.extra_data merge spec: full input-state matrix
  (NULL/empty/legacy/≥1.40), key invariants (array always, url
  URL-encoded, final true only on credits, keys alphabetized,
  attributeName matches parent key), worked example with before/after
  byte-for-byte, Phase C test count 18 rows.

LOW #11 — Worker._process_item vs process_item conflated: §9 clarifies
  hook point is inside Worker._process_item at jobs/worker.py:340
  AFTER the existing BIF call.

LOW #12 — Phase A plugin version check fixed: JellyfinMarkerPublisher
  returns READ_ONLY unconditionally in Phase A regardless of plugin
  version, so existing trickplay users don't see spurious Setup Health
  warnings. Version gate enabled in Phase C with the writes.

Spec is now 1374 lines (was 1239). All cross-references verified.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…x Tier 1/2

Background agent ran the proposed algorithms against the user's actual
/data library (4856 TV dirs, 9753 movie dirs). Concrete findings either
confirmed, refined, or REFUTED spec claims.

REFUTED:
- Tier 2.5 subtitle-keyword recap detection — 0/30 hits on real files.
  "Previously on" is a graphical title card on streaming releases, NOT
  in subtitle streams. Mr. Robot S01E06's 90s recap montage has
  subtitled dialogue but no keyword chyron in SRT. Reason no existing
  tool ships this approach: it doesn't work.
  → DELETED Tier 2.5 from cascade. Recap handling routes through
    Tier 0 chapter names (verified working — Dead Boy Detectives
    S01E05 has "Recap" chapter), Tier 1 TheIntroDB's recap segments,
    Tier 4 OCR (optional, chyron-region keyword scan), or manual
    Inspector edits.

REFINED:
- Tier 0 hit rate: spec said 20% TV / 16% movies; measured 40% TV /
  23% movies. Spec was conservative by 2× on TV. Updated.
- Tier 1 hit rate: spec said ~57% TV; measured 5% on user's
  heterogeneous library (1/20 random IMDb-keyed lookups). Popular-show
  cross-check confirmed 70% on mainstream — the 57% figure is a
  popularity-biased number. Added tmdb_popularity_min setting + popularity
  gate before query to avoid wasted rate-limit quota.
- Tier 2 chromaprint: validated working (Hart to Hart S01 = 102/231
  pair matches; theme region 0-78s identified consistently across
  pairs). One Piece anime = 10/10 pairs, OP 0-110s — anime myth
  busted. BUT discovered release-source variance: cross-encoder
  pairs (WEBDL-GRAVE vs Bluray-COLL3CTiF) match poorly.
  → ADDED release-source grouping to Pass 2: extract release group
    from filename, run pairwise within-source first (near-100%),
    then cross-source with relaxed thresholds.

CONFIRMED:
- Tier 3 adaptive blackdetect: 5 random movies, all converged in
  7 probes (1.5-6.3s elapsed, median 4s). PR #191's naive linear
  scan was 131s on equivalent 4K HDR. ~30x speedup verified.
- TheIntroDB v2 API + response shape matches spec exactly. null
  semantics ("from beginning" / "to end") confirmed.

UNCONFIRMED:
- Tier 5 Emby: local Emby (4.9.3.0) doesn't have MediaPreviewBridge
  or Segment_Reporting installed; can't live-verify Phase C writes.
  Surfaced as Setup Health requirement.

New §11.5 section captures all the empirical evidence with citations
to test artifacts at /tmp/intro_validation/. Future implementers can
re-run the tests against new content to verify accuracy stays high.

Spec is now 1488 lines (was 1374). PR #241 commit count: 11.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
External SOTA research stream (Korolkov 2025, Hao 2021, AWS, TwelveLabs,
Cognitive Mill, Chapter-Llama, intro-skipper survey) provided concrete
F1 ceilings:

- Academic SOTA: 0.91 F1 (Korolkov CLIP+attention; no public weights)
- Commercial baseline: 0.73 F1 (Hao/AWS Rekognition)
- Our cascade: ~0.75-0.85 F1 (FOSS Pareto frontier)
- Cognitive Mill 99.99%: unverified marketing, dismissed

Two HIGH-leverage additions surfaced:

1. Tier 2c — SoundFingerprinting escalation path. When chromaprint Pass 2
   match rate within season < 30% (cross-source Hart to Hart problem),
   automatically escalate to peak-pair fingerprinting (MIT, used by
   plex-credits-detect). 3× slower but handles re-encodes.

2. Tier 5 — Chapter-Llama (MIT, weights public on HF). First open-source
   SOTA-class option. Llama-3.1-8B + LoRA, 16+GB VRAM, F1 45.3 on chapter
   generation. Deferred to future Phase E; documented as the realistic
   open-source path past 0.85 F1.

Documented:
- AWS Rekognition pricing math ($11,250 to bootstrap 5000-ep library)
  as paid-tier escape hatch, not v1 dependency
- TwelveLabs Marengo Bedrock as alternative paid embedding source
- Signal hierarchy by marker type (audio fp wins for themed TV intros,
  OCR wins for credits, blackdetect wins for boundaries, etc.)
- Explicit acknowledgement: chromaprint is 2017-era, ~18 F1 below
  academic SOTA. Survives as free fast-path, not best signal.

Spec is now 1547 lines (was 1488). PR #241 commit 12.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Background agent extracted Plex Media Server binary from
linuxserver/plex:latest Docker image and ran strings/readelf/xxd
analysis. The COMPLETE Plex algorithm is now known:

§11.5.1 Pipeline decoded:
1. Decode (FFmpeg + EAE for Dolby only — myth: EAE is NOT a fingerprinter)
2. Essentia mel-bands + MFCC features (2048 frame @ 22050 Hz, 1024 hop)
3. Music.tflite classifier (3.1MB CNN: 8 Conv2D + 2 Dense + Sigmoid)
4. Chromaprint fingerprinting (Plex Media Fingerprinter = fpcalc
   statically linked, SAME library as intro-skipper)
5. IntroDetectorManager: Hamming-LCS + ≥50% quorum rule
6. Persist to metadata_item_setting_markers (NEW: differs from
   MarkerEditor's taggings table — flagged for Phase C verification)
7. Cloud submit to metadata.provider.plex.tv

§11.5.2 BogoHash = SHA-256 of first 4096 bytes. Confirmed by
binary class hierarchy + Plex staffer ChuckPa forum post. We can
compute this EXACTLY — possible future cloud-query capability,
documented but not committed (ToS grey area).

§11.5.3 Credits = OpenCV EAST text-bbox + Music.tflite + blackdetect.
Our PaddleOCR PP-OCRv5 beats EAST on stylized text (Plex only finds
bboxes, doesn't read text content).

§11.5.4 Plex Commercial Skipper IS literally comskip (GPLv2 OSS,
Erik Kaashoek's). Same CSV columns, same comskip.ini config.

§11.5.5 Anime NCOP regex extracted verbatim from binary — we adopt
it for filename-based intro detection (NCOP files ARE the opening).

§11.5.6 Accuracy moat = ZERO. Plex's components are:
- chromaprint (same as us)
- Essentia (open AGPLv3)
- 3MB CNN (replaceable with YAMNet)
- comskip (we'd ship same)
- OpenCV EAST (we use better — PaddleOCR)
A third-party impl matches Plex intro within ~2%, credits within
~5-10%. The only moat is the metadata.provider.plex.tv cached DB
which becomes irrelevant once we run local detection once.

§5 Tier 2 chromaprint algorithm now includes Plex's binary-verified
50% quorum rule: "if fewer than half of episodes in season match,
drop ALL intros for the season".

Spec is now 1632 lines (was 1547).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Background research stream did IL decompilation of Emby.Providers.dll
(closed-source Emby Premiere) and line-by-line analysis of intro-skipper
source. The findings collapse the implementation uncertainty for Tier 2
chromaprint.

Algorithm lineage confirmed:
VictorBitca/matcher (Go 2019) → puzzledsam (Python 2019) →
chefbennyj1 (C# 2020) → Emby Premiere (C# 2022, 4.7+ licensed in)

Both Emby and Jellyfin's algorithms decoded with code snippets included:
- Jellyfin: inverted-index, O(N) per pair, known LHS/RHS mismatch bug
- Emby: sliding-window cross-correlation, O(N²) per pair, single
  consistent offset, 3-sample lookahead filters spurious matches

Recommendation: start with Jellyfin's approach, FIX the LHS/RHS-
mismatch bug via triple tracking (shift, lhsRange, rhsRange), ADD
pairwise consensus (≥2 pairs agreeing) — strictly stronger than
intro-skipper's longest-wins-per-episode rule which explains the
~80% accuracy ceiling.

Canonical constants captured for Python re-impl:
- SAMPLE_DURATION = 4096/11025/3 (exact)
- MAX_BIT_DIFF = 6 (Jellyfin tightened from VictorBitca's 8)
- MAX_TIME_SKIP = 3.5s, MIN_INTRO = 15s, MAX_INTRO = 120s
- INVERTED_INDEX_SHIFT = 2
- ANALYSIS_PERCENT = 0.25, ANALYSIS_LENGTH_LIMIT = 600s
- MIN_PAIRS_FOR_CONSENSUS = 2 (OUR addition, fixes 80% ceiling)

SWAR popcount formula included — bit-identical to BOTH Emby's
GetFastHammingDistance AND intro-skipper's BitOperations.PopCount,
verified by manual IL trace.

Boundary refinement spec (intro-skipper's three-stage; Emby skips):
chapter snap → silence snap → keyframe snap, asymmetric windows
favor shrinking over extending.

Per-mode analyzer chain ordering documented (Intro=Chapter+Chromaprint,
Credits non-anime=Chapter+BlackFrame+Chromaprint, Credits anime
flipped, Recap/Preview/Commercial=Chapter only).

TEST FIXTURE BREAKTHROUGH: VictorBitca/matcher repo has Jojo-01.wav
through Jojo-10.wav (10 episodes, 17MB each) as canonical pre-
validated test corpus. Intros start near 0, end near 60s. Phase B's
first test.

Spec is now ~1700 lines.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ECT verdict

Larger empirical sweep across 20 shows in 10 content categories
corrected and calibrated earlier numbers:

CORRECTED:
- Tier 0 chapters: ~11% library-wide (was 40%) — small sample bias
  in round 1. Almost exclusively anime fansubs. Western Bluray rips
  ship generic "Chapter NN".
- Tier 1 TheIntroDB: ~50% on mixed library (was 5%) — round 1's 5%
  came from random-IMDb sampling that hit recent/niche shows.

VALIDATED:
- Multi-OP cluster mode: One Piece S01 vs S10 vs S20 = 0% match
  (chromaprint correctly distinguishes different OPs). Simple
  k-means on fingerprint medians will cluster cours.
- Release-source grouping is MANDATORY: Hart to Hart within-source
  100%, cross-source 33%. 67-point drop validates spec.
- Bob's Burgers "skipme.db #29 failure" debunked: 47% within
  -CtrlHD source; the reported failure was cross-source pairs.

NEW per-content-type strategy (verdict table in §11.5.9):
- Talk shows (LWT): 100% match, 0.6s stddev — Tier 2 wins
- Western cartoons: 47-100% — Tier 2 wins with source grouping
- Long-running anime within-cour: 100% — Tier 2 wins, cluster by cour
- Sitcoms: 40-73% — Tier 2 + Tier 1 fallback
- Modern drama: 20-33% weak chromaprint, Tier 1 carries (BrBa,
  Severance both 5/5 TheIntroDB)
- Anime rotating OP: 27% (multi-OP confuses) — cluster mandatory
- Reality TV (Survivor): 0% — REJECT, no recurring theme
- Mini-series (Chernobyl): 0% — REJECT, unique cold opens
- Single-season prestige (Watchmen): 0% — REJECT, same problem

NEW: Tier 2 confidence threshold function based on empirical data:
- HIGH ≥80% match + ≤5s stddev
- MEDIUM 40-80% + ≤20s
- LOW <40% or >30s
- REJECT 0 matches (don't synthesize low-confidence guess)

NEW: REJECT verdict for content with structurally no marker signal.
Reality/mini-series/single-season → Inspector shows "no markers
detected" rather than wrong markers. Better UX than guessing.

Spec is now ~1900 lines. PR #241 commit 15.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
stevezau and others added 4 commits May 18, 2026 12:14
…eline

Self-contained HTML mockup at docs/design/inspector-mockup.html
demonstrating the Inspector UI across every state we have to handle:

01. Single-item Inspector — Severance S01E03 with audio waveform,
    server markers vs detected markers vs recap, confidence,
    per-client compatibility matrix, full action set
02. Per-server matrix — 8 distinct server states (Plex Pass,
    Plex no-Pass DB write, Emby+Premiere+plugin, Emby plugin
    missing, Jellyfin upgraded, Jellyfin needs update, Jellyfin
    no plugin, server unreachable)
03. Library coverage dashboard — bootstrap progress for 5000-ep
    library with per-library breakdown, ETA, REJECT bucket
04. Cross-server bridge — Plex → Jellyfin marker push UI
05. Bulk editor — Phase D spreadsheet view with shift-N-seconds
06. Pipeline diagram — shows what reuses existing infra (BIF,
    FFmpeg, worker pool, SocketIO) vs what's new
07. Edge cases — REJECT verdict, rate limit, plugin missing,
    locked markers, mini-series partial

Design language: dark theme, IBM Plex Sans + Mono + Bricolage
Grotesque, teal/amber/purple marker palette (intro/credits/recap).
No external dependencies beyond Google Fonts.

Open in a browser: file:///path/to/docs/design/inspector-mockup.html
Or via PR #241 raw URL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Previous mockup used a custom dark aesthetic (Bricolage Grotesque +
IBM Plex Sans, teal/amber accent colors, custom CSS framework) that
didn't match the existing app. Steve correctly called this out.

Rewritten using the live app's design tokens verbatim:
- Bootstrap 5.3 (same CDN + version as base.html)
- Bootstrap Icons (bi-*)
- Plex orange (--plex-orange #e5a00d) as scalpel for primary CTA
- Cool-slate light theme + dark Plex theme via data-bs-theme
- *-bg-subtle + *-text-emphasis pattern for status badges (matches
  style.css guidance)
- .page-header / .page-title / .page-subtitle pattern from base.html
- .card with 1px border, no shadow (matches bif_viewer.html)
- .nav nav-pills nav-fill for tabs
- Same theme-toggle JS pattern

The mockup now reads as a NEW PAGE INSIDE the existing app rather
than a separate design exploration. Drops into web/templates/ shape.

Marker color palette retained (intro=#5EEAD4 / credits=#F59E0B /
recap=#A78BFA) as data-accent colors only — these are content
colors for the timeline visualization, not brand colors.

Same 7 sections preserved: single-item Inspector, per-server matrix
(8 states), library coverage, cross-server bridge, bulk editor,
pipeline integration, edge cases. Plus an alert callout for the
integration gaps that still need design work (frame cache reuse,
GPU pool sharing, SocketIO events, setup wizard, scheduler).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant