"""Hintergrundmusik-Mixing und Audio-Logik.""" from __future__ import annotations import random import subprocess from pathlib import Path from .config import MUSIC_EXTENSIONS, get_music_files def _run(cmd: list[str]) -> subprocess.CompletedProcess: return subprocess.run(cmd, capture_output=True, text=True, check=False) def pick_music_file( music_files: list[Path], mode: str = "random", ) -> Path: """Musikdatei nach Modus auswählen.""" if not music_files: raise FileNotFoundError("Keine Musikdateien gefunden.") if mode == "random": return random.choice(music_files) elif mode in ("alphabetical", "loop"): return sorted(music_files)[0] else: raise ValueError(f"Unbekannter Musik-Modus: {mode}") def mix_music( video_path: Path, output_path: Path, music_file: Path, volume_original: float = 1.0, volume_music: float = 0.3, ) -> Path: """Hintergrundmusik in Video mixen.""" output_path.parent.mkdir(parents=True, exist_ok=True) # Prüfen ob Video Audio-Stream hat probe_cmd = [ "ffprobe", "-v", "error", "-select_streams", "a", "-show_entries", "stream=codec_type", "-of", "default=noprint_wrappers=1:nokey=1", str(video_path), ] probe = _run(probe_cmd) has_audio = bool(probe.stdout.strip()) if has_audio: filter_complex = ( f"[0:a]volume={volume_original}[v1];" f"[1:a]volume={volume_music}[v2];" f"[v1][v2]amix=inputs=2:duration=first[a]" ) cmd = [ "ffmpeg", "-y", "-i", str(video_path), "-stream_loop", "-1", "-i", str(music_file), "-filter_complex", filter_complex, "-c:v", "copy", "-c:a", "aac", "-map", "0:v:0", "-map", "[a]", "-shortest", str(output_path), ] else: # Kein Original-Audio → Musik direkt als Track cmd = [ "ffmpeg", "-y", "-i", str(video_path), "-stream_loop", "-1", "-i", str(music_file), "-filter_complex", f"[1:a]volume={volume_music}[a]", "-c:v", "copy", "-c:a", "aac", "-map", "0:v:0", "-map", "[a]", "-shortest", str(output_path), ] result = _run(cmd) if result.returncode != 0: raise RuntimeError(f"ffmpeg Fehler beim Musik-Mixing: {result.stderr}") return output_path def add_music_from_config( video_path: Path, output_path: Path, config: dict, ) -> Path: """Musik aus Konfiguration auswählen und mixen.""" music_files = get_music_files(config) if not music_files: raise FileNotFoundError( f"Keine Musikdateien in: {config['resources']['folder']}/music/" ) mode = config["music"]["mode"] music_file = pick_music_file(music_files, mode) return mix_music( video_path=video_path, output_path=output_path, music_file=music_file, volume_original=config["music"]["volume_original"], volume_music=config["music"]["volume_music"], )