feat(tv_shows): sync_show populates library index from TMDB
New orchestrator alfred.application.tv_shows.sync.sync_show calls TMDBClient.get_tv_show_info, combines the response with the on-disk release loaded via DotAlfredSeriesReleaseRepository.load_by_tmdb_id, and upserts the result into DotAlfredTVShowLibraryIndex. Policy: * placeholders (auto-healed entries, status=="unknown") always refresh regardless of TTL, * fresh entries within Settings.tmdb_cache_ttl_days are no-ops, * stale entries past TTL refresh, * force=True overrides both gates, * indexed shows whose per-show sidecar is gone still get a fresh TMDB pass — slot map clears until rescan repopulates it, * truly absent shows raise ShowNotFoundInLibrary from the new alfred.application.exceptions module.
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
"""Shared fixtures for ``alfred.application.tv_shows`` tests.
|
||||
|
||||
These mirror the v2 dot_alfred conftest (tv_library + foundation_release
|
||||
+ now_utc) so the sync orchestrator tests can compose against the same
|
||||
realistic aggregate without cross-package fixture inheritance.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from alfred.domain.releases.entities import (
|
||||
EpisodeRelease,
|
||||
SeasonRelease,
|
||||
SeriesRelease,
|
||||
TrackProfile,
|
||||
)
|
||||
from alfred.domain.releases.value_objects import EpisodeRange, ReleaseMode
|
||||
from alfred.domain.shared.media import AudioTrack
|
||||
from alfred.domain.shared.value_objects import FilePath, ImdbId, TmdbId
|
||||
from alfred.domain.tv_shows.value_objects import EpisodeNumber, SeasonNumber
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def tv_library(tmp_path):
|
||||
"""Empty ``tv_shows/`` with a Foundation/ folder ready for sidecars."""
|
||||
root = tmp_path / "tv_shows"
|
||||
root.mkdir()
|
||||
(root / "Foundation").mkdir()
|
||||
return root
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def foundation_release() -> SeriesRelease:
|
||||
"""Minimal Foundation S01 PACK — enough for slot-map assertions."""
|
||||
season = SeasonRelease(
|
||||
season_number=SeasonNumber(1),
|
||||
folder="Foundation.S01",
|
||||
mode=ReleaseMode.PACK,
|
||||
episodes=(
|
||||
EpisodeRelease(
|
||||
episodes=EpisodeRange(EpisodeNumber(1), EpisodeNumber(1)),
|
||||
file_path=FilePath("Foundation.S01/Foundation.S01E01.mkv"),
|
||||
tracks=TrackProfile(
|
||||
audio_tracks=(
|
||||
AudioTrack(
|
||||
index=0,
|
||||
codec="eac3",
|
||||
channels=6,
|
||||
channel_layout="5.1",
|
||||
language="eng",
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
return SeriesRelease(
|
||||
tmdb_id=TmdbId(84958),
|
||||
imdb_id=ImdbId("tt0804484"),
|
||||
seasons=(season,),
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def now_utc() -> datetime:
|
||||
"""Stable UTC reference for deterministic fetched_at fields."""
|
||||
return datetime(2026, 5, 25, 8, 30, 0, tzinfo=UTC)
|
||||
Reference in New Issue
Block a user