Files
meijiaka-zy/python-api/app/utils/audio_utils.py
T

61 lines
1.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
音频时长探测工具
================
基于 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 | WAVE = MP3(data)
elif header[:4] == b"RIFF":
audio = WAVE(data)
else:
# fallback:先尝试 MP3(大多数 TTS 返回 mp3
audio = MP3(data)
if audio.info is None:
raise ValueError("音频信息解析失败")
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