""" Utility helpers for the improved AICoverGen. """ import os import re from typing import Any, Dict def format_time(seconds: float) -> str: """Format seconds as M:SS or H:MM:SS.""" if seconds is None or seconds < 0: return "0:00" seconds = int(seconds) hours = seconds // 3600 minutes = (seconds % 3600) // 60 secs = seconds % 60 if hours > 0: return f"{hours}:{minutes:02d}:{secs:02d}" return f"{minutes}:{secs:02d}" def get_audio_info(path: str) -> Dict[str, Any]: """Return basic info about an audio file (duration, sample rate, channels).""" info: Dict[str, Any] = { "path": path, "exists": False, "duration": 0.0, "sample_rate": 0, "channels": 0, "size_bytes": 0, } if not path or not os.path.exists(path): return info info["exists"] = True info["size_bytes"] = os.path.getsize(path) try: import soundfile as sf with sf.SoundFile(path) as f: info["duration"] = len(f) / f.samplerate info["sample_rate"] = f.samplerate info["channels"] = f.channels except Exception: try: import librosa y, sr = librosa.load(path, sr=None, mono=False) info["sample_rate"] = sr if y.ndim > 1: info["channels"] = y.shape[0] info["duration"] = y.shape[1] / sr else: info["channels"] = 1 info["duration"] = y.shape[0] / sr except Exception: pass return info def human_size(num_bytes: int) -> str: """Convert bytes to human-readable string.""" if num_bytes is None or num_bytes < 0: return "0 B" units = ["B", "KB", "MB", "GB", "TB"] size = float(num_bytes) idx = 0 while size >= 1024 and idx < len(units) - 1: size /= 1024 idx += 1 return f"{size:.1f} {units[idx]}"