fix: deterministic video/thumbnail classification in acquire stage

This commit is contained in:
2026-07-25 19:31:34 -07:00
parent 19a4f6e1ee
commit 504bc34889
2 changed files with 46 additions and 7 deletions
+13 -7
View File
@@ -5,6 +5,18 @@ from pathlib import Path
from ..media import ffmpeg
from ..pipeline import Ctx, PipelineError, Stage
IMAGE_EXTENSIONS = {".jpg", ".jpeg", ".png", ".webp", ".avif", ".gif"}
def _classify_downloads(dest: Path) -> tuple[Path, Path | None]:
files = list(dest.glob("source_video.*"))
thumbs = [p for p in files if p.suffix.lower() in IMAGE_EXTENSIONS]
videos = [p for p in files if p.suffix.lower() not in IMAGE_EXTENSIONS]
if not videos:
raise PipelineError("yt-dlp produced no video file")
video = max(videos, key=lambda p: p.stat().st_size)
return video, thumbs[0] if thumbs else None
def download_youtube(url: str, dest: Path) -> tuple[Path, Path | None]:
import yt_dlp
@@ -16,13 +28,7 @@ def download_youtube(url: str, dest: Path) -> tuple[Path, Path | None]:
}
with yt_dlp.YoutubeDL(opts) as ydl:
ydl.extract_info(url, download=True)
videos = [p for p in dest.glob("source_video.*")
if p.suffix not in (".jpg", ".png", ".webp")]
if not videos:
raise PipelineError("yt-dlp produced no video file")
thumbs = [p for p in dest.glob("source_video.*")
if p.suffix in (".jpg", ".png", ".webp")]
return videos[0], thumbs[0] if thumbs else None
return _classify_downloads(dest)
def _run(ctx: Ctx) -> None:
+33
View File
@@ -44,3 +44,36 @@ def test_requires_exactly_one_source(tmp_path):
ctx = make_ctx(tmp_path)
with pytest.raises(PipelineError):
acquire.acquire_stage().run(ctx)
def test_classify_ordinary_webm_and_jpg(tmp_path):
(tmp_path / "source_video.webm").write_bytes(b"v")
(tmp_path / "source_video.jpg").write_bytes(b"t")
video, thumb = acquire._classify_downloads(tmp_path)
assert video.name == "source_video.webm"
assert thumb.name == "source_video.jpg"
def test_classify_unexpected_thumbnail_extension(tmp_path):
(tmp_path / "source_video.webm").write_bytes(b"v")
(tmp_path / "source_video.avif").write_bytes(b"t")
video, thumb = acquire._classify_downloads(tmp_path)
assert video.name == "source_video.webm"
assert thumb.name == "source_video.avif"
def test_classify_no_thumbnail(tmp_path):
(tmp_path / "source_video.mp4").write_bytes(b"v")
video, thumb = acquire._classify_downloads(tmp_path)
assert video.name == "source_video.mp4"
assert thumb is None
def test_classify_no_video_raises(tmp_path):
import pytest
from karaoke_maker.pipeline import PipelineError
(tmp_path / "source_video.jpg").write_bytes(b"t")
with pytest.raises(PipelineError):
acquire._classify_downloads(tmp_path)
def test_classify_picks_largest_video_when_multiple(tmp_path):
(tmp_path / "source_video.f137.mp4").write_bytes(b"small")
(tmp_path / "source_video.mp4").write_bytes(b"much larger contents here")
video, _ = acquire._classify_downloads(tmp_path)
assert video.name == "source_video.mp4"