feat(music-lab): video_producer — FFmpeg 비주얼라이저·슬라이드쇼 + Claude 메타데이터
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
98
music-lab/tests/test_video_producer.py
Normal file
98
music-lab/tests/test_video_producer.py
Normal file
@@ -0,0 +1,98 @@
|
||||
# music-lab/tests/test_video_producer.py
|
||||
import os
|
||||
from unittest.mock import patch, MagicMock
|
||||
import pytest
|
||||
|
||||
|
||||
def test_build_visualizer_cmd():
|
||||
from app.video_producer import _build_visualizer_cmd
|
||||
cmd = _build_visualizer_cmd(
|
||||
audio_path="/data/music/test.mp3",
|
||||
bg_path="/tmp/bg.jpg",
|
||||
output_path="/data/videos/1/output.mp4",
|
||||
)
|
||||
assert cmd[0] == "ffmpeg"
|
||||
assert "/data/music/test.mp3" in cmd
|
||||
assert "/data/videos/1/output.mp4" in cmd
|
||||
assert any("showwaves" in str(c) for c in cmd)
|
||||
|
||||
|
||||
def test_make_gradient_bg_uses_pillow(tmp_path):
|
||||
from app.video_producer import _make_gradient_bg
|
||||
out = str(tmp_path / "bg.jpg")
|
||||
_make_gradient_bg(1920, 1080, "lo-fi", out)
|
||||
assert os.path.exists(out)
|
||||
assert os.path.getsize(out) > 0
|
||||
|
||||
|
||||
def test_extract_thumbnail_cmd():
|
||||
from app.video_producer import _build_thumbnail_cmd
|
||||
cmd = _build_thumbnail_cmd("/data/videos/1/output.mp4", "/data/videos/1/thumbnail.jpg")
|
||||
assert cmd[0] == "ffmpeg"
|
||||
assert "00:00:05" in cmd
|
||||
assert "/data/videos/1/thumbnail.jpg" in cmd
|
||||
|
||||
|
||||
def test_build_slideshow_cmd_single_image():
|
||||
from app.video_producer import _build_slideshow_cmd
|
||||
cmd = _build_slideshow_cmd(
|
||||
image_paths=["/tmp/img0.jpg"],
|
||||
audio_path="/tmp/audio.mp3",
|
||||
output_path="/tmp/out.mp4",
|
||||
duration_per_image=30.0,
|
||||
)
|
||||
assert "ffmpeg" in cmd[0]
|
||||
assert "/tmp/out.mp4" in cmd
|
||||
assert any("copy" in str(c) for c in cmd)
|
||||
|
||||
|
||||
def test_build_slideshow_cmd_multiple_images():
|
||||
from app.video_producer import _build_slideshow_cmd
|
||||
cmd = _build_slideshow_cmd(
|
||||
image_paths=["/tmp/img0.jpg", "/tmp/img1.jpg", "/tmp/img2.jpg"],
|
||||
audio_path="/tmp/audio.mp3",
|
||||
output_path="/tmp/out.mp4",
|
||||
duration_per_image=60.0,
|
||||
)
|
||||
assert "ffmpeg" in cmd[0]
|
||||
assert any("xfade" in str(c) for c in cmd)
|
||||
assert "/tmp/out.mp4" in cmd
|
||||
|
||||
|
||||
def test_produce_video_visualizer_calls_ffmpeg(tmp_db, tmp_path):
|
||||
"""produce_video가 visualizer 포맷으로 FFmpeg를 호출하는지 확인."""
|
||||
from app.db import init_db, create_video_project
|
||||
import sqlite3
|
||||
|
||||
init_db()
|
||||
|
||||
# music_library에 직접 트랙 삽입
|
||||
import app.db as db_mod
|
||||
with db_mod._conn() as conn:
|
||||
conn.execute(
|
||||
"""INSERT INTO music_library (title, genre, audio_url, file_path, provider)
|
||||
VALUES (?, ?, ?, ?, ?)""",
|
||||
("Test Track", "lo-fi", "/media/music/test.mp3",
|
||||
str(tmp_path / "test.mp3"), "suno"),
|
||||
)
|
||||
|
||||
# 빈 mp3 파일 생성
|
||||
(tmp_path / "test.mp3").write_bytes(b"\x00" * 100)
|
||||
|
||||
create_video_project({"track_id": 1, "format": "visualizer", "target_countries": ["BR"]})
|
||||
|
||||
import app.video_producer as vp
|
||||
vp.VIDEO_DATA_DIR = str(tmp_path / "videos")
|
||||
|
||||
with patch("app.video_producer.subprocess.run") as mock_run, \
|
||||
patch("app.video_producer._generate_metadata", return_value={
|
||||
"yt_title": "Chill Beats", "yt_description": "desc", "yt_tags": ["lofi"]
|
||||
}), \
|
||||
patch("app.video_producer._download_url", return_value=False):
|
||||
mock_run.return_value = MagicMock(returncode=0)
|
||||
vp.produce_video(1)
|
||||
|
||||
from app.db import get_video_project
|
||||
proj = get_video_project(1)
|
||||
assert proj["status"] == "done"
|
||||
assert mock_run.called
|
||||
Reference in New Issue
Block a user