feat(persistence): add .alfred sidecar serializer (DTO ↔ dict)
Step 2 of the specs/dot_alfred.md plan. Pure-dict in/out (serialize(sidecar) -> dict, deserialize(data) -> ShowSidecar); YAML I/O lives in the repository layer (step 3) and is kept out for trivial testability. DTOs mirror the YAML schema field-for-field: - ShowSidecar (root: imdb_id, tmdb_id, schema_version, seasons) - SeasonSidecar (number, path, optional audio/subtitles, optional episodes) - EpisodeSidecar (number, path, optional audio/subtitles) - SubtitleEntry (language, source, type) The sidecar acts as a scan cache: it stores only what is genuinely costly to recompute — folder/file paths (skipping the FS walk) and probed track metadata (skipping ffprobe). Release identifiers (group, source, quality, codec) live in folder/file names and are derived on demand by the parser; they are deliberately absent from the schema and rejected as unknown keys on deserialize. The serializer is strict on schema: unknown keys at any level raise SidecarSchemaError, missing required fields raise clearly, and bool cannot sneak in as a season/episode number. Optional fields (tmdb_id, empty audio/subtitles/episodes) are omitted from the output rather than emitted as null / []. Tests cover round-trip equivalence (DTO → dict → DTO and DTO → YAML text → DTO), the Foundation S01 PACK case (real-world fixture with mixed sub types — superset captured at season scope), and a Breaking Bad S05 EPISODIC case. An on-disk tmp_path fixture recreates the Foundation folder structure with placeholder files, ready to be reused by the upcoming repository walk tests in step 3.
This commit is contained in:
@@ -17,6 +17,31 @@ callers).
|
||||
|
||||
### Added
|
||||
|
||||
- **`.alfred` sidecar serializer
|
||||
(`alfred/infrastructure/persistence/dot_alfred/`).** Implements step 2
|
||||
of the `specs/dot_alfred.md` plan. Pure-dict in/out
|
||||
(`serialize(sidecar) -> dict`, `deserialize(data) -> ShowSidecar`) —
|
||||
YAML I/O lives in the repository layer (step 3) and is kept out for
|
||||
trivial testability. Ships the DTOs that mirror the YAML schema
|
||||
field-for-field (`ShowSidecar`, `SeasonSidecar`, `EpisodeSidecar`,
|
||||
`SubtitleEntry`). The sidecar acts as a **scan cache**: it stores
|
||||
only what is genuinely costly to recompute — folder/file paths
|
||||
(skipping the FS walk) and probed track metadata (skipping ffprobe).
|
||||
Release identifiers (group, source, quality, codec) live in folder
|
||||
and file names and are derived on demand by the parser — they are
|
||||
deliberately absent from the schema and rejected on deserialize. The
|
||||
serializer is **strict on schema**: unknown keys at any level raise
|
||||
`SidecarSchemaError`, missing required fields raise clearly, and
|
||||
`bool` cannot sneak in as a season/episode number. Optional fields
|
||||
(`tmdb_id`, empty `audio`/`subtitles`/`episodes`) are omitted from
|
||||
the output rather than emitted as `null` / `[]`. Tests cover
|
||||
round-trip equivalence (DTO → dict → DTO and DTO → YAML text → DTO),
|
||||
the Foundation S01 PACK case (real-world fixture with mixed sub
|
||||
types — superset captured at season scope), and a Breaking Bad S05
|
||||
EPISODIC case. An on-disk `tmp_path` fixture recreates the Foundation
|
||||
folder structure with placeholder files, ready to be reused by the
|
||||
upcoming repository walk tests in step 3.
|
||||
|
||||
- **`TVShowBuilder` / `SeasonBuilder` — sole construction surface for the
|
||||
TVShow aggregate** (`alfred/domain/tv_shows/builders.py`). The aggregate
|
||||
is now fully frozen; building goes through a mutable scratchpad that
|
||||
|
||||
Reference in New Issue
Block a user