88f156b7a4
The old name conflated 'might become a placed subtitle' with 'what a scan pass produced'. The class is the output of a scan/identify pass — language/format may still be None while classification is in progress, confidence reflects classifier certainty, raw_tokens holds filename fragments under analysis. SubtitleScanResult says that directly. Pure rename + refreshed docstring; no behavior change. Touches the domain entity, the matcher/identifier/utils services, the manage_subtitles use case, the placer, the metadata store, the shared-media cross-ref comment, and 7 test modules.
94 lines
3.1 KiB
Python
94 lines
3.1 KiB
Python
"""
|
|
SubtitleMetadataStore — subtitle-specific helper on top of MetadataStore.
|
|
|
|
Owns the shape of `subtitle_history` entries (track-level fields, type
|
|
inference from the destination filename) and delegates all I/O to the
|
|
generic MetadataStore.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from datetime import UTC, datetime
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from alfred.domain.subtitles.entities import SubtitleScanResult
|
|
from alfred.application.subtitles.placer import PlacedTrack
|
|
from alfred.infrastructure.metadata.store import MetadataStore
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class SubtitleMetadataStore:
|
|
"""
|
|
Subtitle-pipeline view of the per-release `.alfred/metadata.yaml`.
|
|
|
|
Backed by a generic MetadataStore; this class only knows how to build
|
|
a subtitle_history entry from PlacedTrack/SubtitleScanResult pairs.
|
|
"""
|
|
|
|
def __init__(self, library_root: Path):
|
|
self._store = MetadataStore(library_root)
|
|
|
|
# ---- Pattern -----------------------------------------------------
|
|
|
|
def confirmed_pattern(self) -> str | None:
|
|
return self._store.confirmed_pattern()
|
|
|
|
def mark_pattern_confirmed(
|
|
self, pattern_id: str, media_info: dict | None = None
|
|
) -> None:
|
|
self._store.mark_pattern_confirmed(pattern_id, media_info)
|
|
|
|
# ---- History -----------------------------------------------------
|
|
|
|
def append_history(
|
|
self,
|
|
placed_pairs: list[tuple[PlacedTrack, SubtitleScanResult]],
|
|
season: int | None = None,
|
|
episode: int | None = None,
|
|
release_group: str | None = None,
|
|
) -> None:
|
|
"""Append one history entry with all placed tracks."""
|
|
if not placed_pairs:
|
|
return
|
|
|
|
tracks_data: list[dict[str, Any]] = []
|
|
for placed, track in placed_pairs:
|
|
# Infer type from destination filename parts (e.g. en.sdh.srt → sdh)
|
|
parts = placed.filename.rsplit(".", 2)
|
|
inferred_type = parts[1] if len(parts) == 3 else "standard"
|
|
|
|
tracks_data.append(
|
|
{
|
|
"language": track.language.code if track.language else "unknown",
|
|
"type": inferred_type,
|
|
"format": placed.destination.suffix.lstrip("."),
|
|
"is_embedded": track.is_embedded,
|
|
"source_file": placed.source.name,
|
|
"placed_as": placed.filename,
|
|
"confidence": round(track.confidence, 3),
|
|
}
|
|
)
|
|
|
|
entry: dict[str, Any] = {
|
|
"placed_at": datetime.now(UTC).isoformat(),
|
|
"release_group": release_group,
|
|
"tracks": tracks_data,
|
|
}
|
|
if season is not None:
|
|
entry["season"] = season
|
|
if episode is not None:
|
|
entry["episode"] = episode
|
|
|
|
self._store.append_subtitle_history_entry(entry)
|
|
marker = f"S{season:02d}E{episode:02d}" if season and episode else "movie"
|
|
logger.info(
|
|
f"SubtitleMetadataStore: appended history "
|
|
f"({marker}) — {len(tracks_data)} track(s)"
|
|
)
|
|
|
|
def history(self) -> list[dict]:
|
|
return self._store.subtitle_history()
|