""" 音频时长探测工具 ================ 基于 mutagen,支持从内存或文件路径探测音频时长。 不依赖 ffprobe,纯 Python 实现。 """ from __future__ import annotations import io import logging import httpx from mutagen.mp3 import MP3 from mutagen.wave import WAVE logger = logging.getLogger(__name__) async def get_audio_duration(url: str, timeout: float = 10.0) -> float: """ 探测远程音频文件的时长(秒)。 下载音频到内存后,用 mutagen 读取文件头获取时长。 不写入磁盘,全部在内存中完成。 :param url: 音频文件 URL(需可访问) :param timeout: HTTP 下载超时(秒) :return: 音频时长(秒,float) :raises ValueError: 无法解析时长 """ async with httpx.AsyncClient() as client: resp = await client.get(url, timeout=timeout) resp.raise_for_status() data = io.BytesIO(resp.content) # 根据文件头判断格式 header = data.read(12) data.seek(0) try: if header[:3] == b"ID3" or header[:2] == b"\xff\xfb" or header[:2] == b"\xff\xf3": audio = MP3(data) elif header[:4] == b"RIFF": audio = WAVE(data) else: # fallback:先尝试 MP3(大多数 TTS 返回 mp3) audio = MP3(data) duration = audio.info.length if duration is None or duration <= 0: raise ValueError("音频时长解析失败") return float(duration) except Exception as e: logger.error(f"探测音频时长失败: url={url[:60]}..., error={e}") raise ValueError(f"无法解析音频时长: {e}") from e