refactor(application): inject kb/prober into resolve_destination use cases
Remove the module-level _KB / _PROBER singletons from
alfred/application/filesystem/resolve_destination.py. The four
resolve_{season,episode,movie,series}_destination use cases now take
kb: ReleaseKnowledge and prober: MediaProber as required arguments,
matching the shape of inspect_release.
The singletons now live at the agent-tools frontier
(alfred/agent/tools/filesystem.py), where the LLM-facing wrappers
instantiate YamlReleaseKnowledge / FfprobeMediaProber once and thread
them through. The wrappers' Python signatures are unchanged — the
inspect-based JSON-schema generator in agent/registry.py still sees the
same LLM-passable params.
analyze_release drops the dirty 'from ... import _KB' indirection.
Tests inject their own stubs by keyword (prober=_StubProber(...)) via
thin convenience wrappers, replacing the prior
monkeypatch.setattr(rd, '_PROBER', ...) pattern.
testing/debug_release.py: instantiate YamlReleaseKnowledge() /
FfprobeMediaProber() inline at the two call sites.
Suite: 1077 passed.
This commit is contained in:
@@ -31,13 +31,53 @@ from alfred.application.filesystem.resolve_destination import (
|
||||
_Clarification,
|
||||
_find_existing_tvshow_folders,
|
||||
_resolve_series_folder,
|
||||
resolve_episode_destination,
|
||||
resolve_movie_destination,
|
||||
resolve_season_destination,
|
||||
resolve_series_destination,
|
||||
resolve_episode_destination as _resolve_episode_destination,
|
||||
resolve_movie_destination as _resolve_movie_destination,
|
||||
resolve_season_destination as _resolve_season_destination,
|
||||
resolve_series_destination as _resolve_series_destination,
|
||||
)
|
||||
from alfred.infrastructure.knowledge.release_kb import YamlReleaseKnowledge
|
||||
from alfred.infrastructure.persistence import Memory, set_memory
|
||||
|
||||
_KB = YamlReleaseKnowledge()
|
||||
|
||||
|
||||
class _NullProber:
|
||||
"""Default prober stub — never returns probe data."""
|
||||
|
||||
def list_subtitle_streams(self, video): # pragma: no cover
|
||||
return []
|
||||
|
||||
def probe(self, video):
|
||||
return None
|
||||
|
||||
|
||||
_DEFAULT_PROBER = _NullProber()
|
||||
|
||||
|
||||
def resolve_season_destination(*args, prober=None, **kwargs):
|
||||
return _resolve_season_destination(
|
||||
*args, kb=_KB, prober=prober or _DEFAULT_PROBER, **kwargs
|
||||
)
|
||||
|
||||
|
||||
def resolve_episode_destination(*args, prober=None, **kwargs):
|
||||
return _resolve_episode_destination(
|
||||
*args, kb=_KB, prober=prober or _DEFAULT_PROBER, **kwargs
|
||||
)
|
||||
|
||||
|
||||
def resolve_movie_destination(*args, prober=None, **kwargs):
|
||||
return _resolve_movie_destination(
|
||||
*args, kb=_KB, prober=prober or _DEFAULT_PROBER, **kwargs
|
||||
)
|
||||
|
||||
|
||||
def resolve_series_destination(*args, prober=None, **kwargs):
|
||||
return _resolve_series_destination(
|
||||
*args, kb=_KB, prober=prober or _DEFAULT_PROBER, **kwargs
|
||||
)
|
||||
|
||||
REL_EPISODE = "Oz.S01E01.1080p.WEBRip.x265-KONTRAST"
|
||||
REL_SEASON = "Oz.S03.1080p.WEBRip.x265-KONTRAST"
|
||||
REL_MOVIE = "Inception.2010.1080p.BluRay.x265-GROUP"
|
||||
@@ -365,46 +405,40 @@ class TestProbeEnrichmentWiring:
|
||||
should pick up ffprobe data via inspect_release and let the enriched
|
||||
tech_string land in the destination name."""
|
||||
|
||||
def test_movie_picks_up_probe_quality(
|
||||
self, cfg_memory, tmp_path, monkeypatch
|
||||
):
|
||||
from alfred.application.filesystem import resolve_destination as rd
|
||||
|
||||
monkeypatch.setattr(rd, "_PROBER", _StubProber(_stereo_movie_info()))
|
||||
def test_movie_picks_up_probe_quality(self, cfg_memory, tmp_path):
|
||||
# Release name parses to "movie" but is missing the quality token;
|
||||
# probe must supply 1080p and refresh tech_string.
|
||||
bare_name = "Inception.2010.BluRay.x264-GROUP"
|
||||
video = tmp_path / "movie.mkv"
|
||||
video.write_bytes(b"")
|
||||
|
||||
out = resolve_movie_destination(bare_name, str(video), "Inception", 2010)
|
||||
out = resolve_movie_destination(
|
||||
bare_name,
|
||||
str(video),
|
||||
"Inception",
|
||||
2010,
|
||||
prober=_StubProber(_stereo_movie_info()),
|
||||
)
|
||||
|
||||
assert out.status == "ok"
|
||||
# tech_string -> "1080p.BluRay.x264" -> "1080p" shows up in names.
|
||||
assert "1080p" in out.movie_folder_name
|
||||
assert "1080p" in out.filename
|
||||
|
||||
def test_movie_skips_probe_when_path_missing(self, cfg_memory, monkeypatch):
|
||||
def test_movie_skips_probe_when_path_missing(self, cfg_memory):
|
||||
# If the file doesn't exist, no probe runs (the stub would have
|
||||
# injected 1080p — its absence proves the skip).
|
||||
from alfred.application.filesystem import resolve_destination as rd
|
||||
|
||||
monkeypatch.setattr(rd, "_PROBER", _StubProber(_stereo_movie_info()))
|
||||
out = resolve_movie_destination(
|
||||
"Inception.2010.BluRay.x264-GROUP",
|
||||
"/nowhere/m.mkv",
|
||||
"Inception",
|
||||
2010,
|
||||
prober=_StubProber(_stereo_movie_info()),
|
||||
)
|
||||
assert out.status == "ok"
|
||||
assert "1080p" not in out.movie_folder_name
|
||||
|
||||
def test_season_picks_up_probe_via_source_path(
|
||||
self, cfg_memory, tmp_path, monkeypatch
|
||||
):
|
||||
from alfred.application.filesystem import resolve_destination as rd
|
||||
|
||||
monkeypatch.setattr(rd, "_PROBER", _StubProber(_stereo_movie_info()))
|
||||
def test_season_picks_up_probe_via_source_path(self, cfg_memory, tmp_path):
|
||||
# Season pack name missing quality token; probe must add it.
|
||||
bare_name = "Oz.S03.BluRay.x265-KONTRAST"
|
||||
release_dir = tmp_path / bare_name
|
||||
@@ -412,7 +446,11 @@ class TestProbeEnrichmentWiring:
|
||||
(release_dir / "episode.mkv").write_bytes(b"")
|
||||
|
||||
out = resolve_season_destination(
|
||||
bare_name, "Oz", 1997, source_path=str(release_dir)
|
||||
bare_name,
|
||||
"Oz",
|
||||
1997,
|
||||
source_path=str(release_dir),
|
||||
prober=_StubProber(_stereo_movie_info()),
|
||||
)
|
||||
|
||||
assert out.status == "ok"
|
||||
|
||||
Reference in New Issue
Block a user