fix: deterministic video/thumbnail classification in acquire stage
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user