feat(release): v2 enricher pass for audio/video-meta/edition/language
The EASY pipeline now extracts the full ParsedRelease surface from
known-group releases, not just the structural backbone. Behavior is
unchanged for releases that don't carry these tokens.
Pipeline (parser/pipeline.py):
- Structural walk (renamed _annotate_structural): no longer requires
body to be fully consumed. Tokens passed over between schema chunks
remain UNKNOWN so the enricher pass can claim them.
- _find_chunk(): scans forward in the body for the next token matching
a given role, skipping already-annotated tokens. Lets optional and
mandatory chunks both tolerate intercalated enricher tokens.
- _annotate_enrichers(): new non-positional pass. Walks UNKNOWN tokens
and tags AUDIO_CODEC / AUDIO_CHANNELS / BIT_DEPTH / HDR / EDITION /
LANGUAGE. Multi-token sequences from kb.audio / kb.video_meta /
kb.editions are matched first (longest-first ordering preserved from
the YAML), single tokens after.
- _apply_sequences(): mutates the token list, tagging the first token
of a matched sequence with extra['sequence']=<canonical value> and
trailing members with extra['sequence_member']='True' so assemble
skips them.
- _detect_channel_pairs(): handles the '5.1' / '7.1' case where the
'.' separator splits the layout into two tokens. Strips a trailing
'-GROUP' suffix on the second before joining.
Assemble:
- New fields populated: languages (list), audio_codec, audio_channels,
bit_depth, hdr_format, edition. Each role-handler skips
sequence_member tokens.
- media_type heuristic extended: edition in {COMPLETE, INTEGRALE,
COLLECTION} + no season → tv_complete (mirrors legacy).
Tests:
- 4 new TestEnrichers cases covering bit_depth+audio_codec+channels,
HDR sequence + edition sequence + TrueHD.Atmos + 7.1, multi-language
with DTS-HD.MA sequence, TV episode with single language.
- All 14 v2 tests + 30 fixture tests still green. Suite: 1011 passed,
8 skipped.
Refs: project_release_parser_v2_specs (memory)
This commit is contained in:
@@ -140,3 +140,65 @@ class TestAssemble:
|
||||
assert fields["source"] is None # ELiTE omits it
|
||||
assert fields["tech_string"] == "1080p.x265"
|
||||
assert fields["group"] == "ELiTE"
|
||||
|
||||
|
||||
class TestEnrichers:
|
||||
"""Non-positional roles populated alongside the structural walk.
|
||||
|
||||
These releases would have failed the v2 EASY path before the enricher
|
||||
pass landed (leftover unknown tokens would force a fallback). They
|
||||
now succeed in v2 with rich metadata.
|
||||
"""
|
||||
|
||||
def test_bit_depth_and_audio(self) -> None:
|
||||
name = "Back.in.Action.2025.1080p.WEBRip.10bit.DDP.5.1.x265-KONTRAST"
|
||||
tokens, tag = tokenize(name, _KB)
|
||||
annotated = annotate(tokens, _KB)
|
||||
assert annotated is not None
|
||||
fields = assemble(annotated, tag, name, _KB)
|
||||
|
||||
assert fields["title"] == "Back.in.Action"
|
||||
assert fields["bit_depth"] == "10bit"
|
||||
assert fields["audio_codec"] == "DDP"
|
||||
assert fields["audio_channels"] == "5.1"
|
||||
|
||||
def test_hdr_sequence(self) -> None:
|
||||
# DV.HDR10 sequence + TrueHD.Atmos sequence + 7.1 channels +
|
||||
# DIRECTORS.CUT edition all in one release.
|
||||
name = (
|
||||
"Some.Movie.2024.DIRECTORS.CUT.2160p.BluRay.DV.HDR10."
|
||||
"TrueHD.Atmos.7.1.x265-KONTRAST"
|
||||
)
|
||||
tokens, tag = tokenize(name, _KB)
|
||||
annotated = annotate(tokens, _KB)
|
||||
assert annotated is not None
|
||||
fields = assemble(annotated, tag, name, _KB)
|
||||
|
||||
assert fields["edition"] == "DIRECTORS.CUT"
|
||||
assert fields["hdr_format"] == "DV.HDR10"
|
||||
assert fields["audio_codec"] == "TrueHD.Atmos"
|
||||
assert fields["audio_channels"] == "7.1"
|
||||
|
||||
def test_multiple_languages(self) -> None:
|
||||
name = "Movie.2020.FRENCH.MULTI.1080p.WEBRip.DTS.HD.MA.5.1.x265-KONTRAST"
|
||||
tokens, tag = tokenize(name, _KB)
|
||||
annotated = annotate(tokens, _KB)
|
||||
assert annotated is not None
|
||||
fields = assemble(annotated, tag, name, _KB)
|
||||
|
||||
assert fields["languages"] == ["FRENCH", "MULTI"]
|
||||
assert fields["audio_codec"] == "DTS-HD.MA"
|
||||
assert fields["audio_channels"] == "5.1"
|
||||
|
||||
def test_tv_with_language(self) -> None:
|
||||
name = "Show.S01E05.FRENCH.1080p.WEBRip.x265-KONTRAST"
|
||||
tokens, tag = tokenize(name, _KB)
|
||||
annotated = annotate(tokens, _KB)
|
||||
assert annotated is not None
|
||||
fields = assemble(annotated, tag, name, _KB)
|
||||
|
||||
assert fields["title"] == "Show"
|
||||
assert fields["season"] == 1
|
||||
assert fields["episode"] == 5
|
||||
assert fields["languages"] == ["FRENCH"]
|
||||
assert fields["media_type"] == "tv_show"
|
||||
|
||||
Reference in New Issue
Block a user