import os import asyncio import uuid import shutil from pathlib import Path from typing import Optional from ..config import get_settings HLS_SEGMENT_DURATION = 10 # Sekunden pro Segment async def create_hls_session( session_id: str, audio_files: list[str], start_time: float = 0.0, ) -> str: """ Erstellt HLS-Segmente via FFmpeg für die gegebenen Audio-Dateien. Gibt den Pfad zum HLS-Verzeichnis zurück. """ settings = get_settings() session_dir = os.path.join(settings.hls_cache_dir, session_id) os.makedirs(session_dir, exist_ok=True) playlist_path = os.path.join(session_dir, "output.m3u8") if len(audio_files) == 1: input_path = audio_files[0] else: # Mehrere Dateien: Concat-Liste erstellen concat_file = os.path.join(session_dir, "concat.txt") with open(concat_file, "w", encoding="utf-8") as f: for af in audio_files: safe_path = af.replace("\\", "/") f.write(f"file '{safe_path}'\n") input_path = concat_file if len(audio_files) == 1: cmd = [ "ffmpeg", "-y", "-ss", str(start_time), "-i", input_path, "-c:a", "aac", "-b:a", "192k", "-ac", "2", "-hls_time", str(HLS_SEGMENT_DURATION), "-hls_list_size", "0", "-hls_segment_filename", os.path.join(session_dir, "seg%05d.ts"), "-hls_flags", "independent_segments", playlist_path, ] else: cmd = [ "ffmpeg", "-y", "-f", "concat", "-safe", "0", "-i", input_path, "-ss", str(start_time), "-c:a", "aac", "-b:a", "192k", "-ac", "2", "-hls_time", str(HLS_SEGMENT_DURATION), "-hls_list_size", "0", "-hls_segment_filename", os.path.join(session_dir, "seg%05d.ts"), "-hls_flags", "independent_segments", playlist_path, ] proc = await asyncio.create_subprocess_exec( *cmd, stdout=asyncio.subprocess.DEVNULL, stderr=asyncio.subprocess.PIPE, ) _, stderr = await proc.communicate() if proc.returncode != 0: error_msg = stderr.decode(errors="replace") if stderr else "unknown error" raise RuntimeError(f"FFmpeg fehler: {error_msg}") return session_dir def cleanup_hls_session(session_id: str): settings = get_settings() session_dir = os.path.join(settings.hls_cache_dir, session_id) if os.path.exists(session_dir): shutil.rmtree(session_dir, ignore_errors=True) def get_hls_session_path(session_id: str) -> Optional[str]: settings = get_settings() session_dir = os.path.join(settings.hls_cache_dir, session_id) playlist = os.path.join(session_dir, "output.m3u8") return session_dir if os.path.exists(playlist) else None def parse_m3u8_duration(playlist_path: str) -> float: """Berechnet Gesamtdauer aus M3U8-Playlist.""" total = 0.0 try: with open(playlist_path, "r") as f: for line in f: if line.startswith("#EXTINF:"): duration_str = line.split(":")[1].split(",")[0] total += float(duration_str) except Exception: pass return total