from __future__ import annotations import logging import subprocess import tempfile from pathlib import Path logger = logging.getLogger(__name__) TARGET_SAMPLE_RATE = 48000 TARGET_BITRATE = "64k" TARGET_FORMAT = "ogg" TARGET_CODEC = "libopus" def check_ffmpeg_available() -> bool: try: result = subprocess.run(["ffmpeg", "-version"], capture_output=True, timeout=5) return result.returncode == 0 except (FileNotFoundError, subprocess.TimeoutExpired): return False def transcode_to_ogg_opus( input_data: bytes, input_format: str = "mp3", sample_rate: int = TARGET_SAMPLE_RATE, bitrate: str = TARGET_BITRATE, ) -> bytes | None: if not check_ffmpeg_available(): logger.warning("[FeishuAudio] FFmpeg not available, skipping transcode") return None with tempfile.NamedTemporaryFile(suffix=f".{input_format}", delete=False) as infile: infile.write(input_data) input_path = infile.name output_path = input_path + f".{TARGET_FORMAT}" try: cmd = [ "ffmpeg", "-y", "-i", input_path, "-ar", str(sample_rate), "-b:a", bitrate, "-c:a", TARGET_CODEC, output_path, ] result = subprocess.run(cmd, capture_output=True, timeout=60) if result.returncode != 0: logger.error( "[FeishuAudio] FFmpeg transcode failed: %s", result.stderr.decode(errors="replace")[:300], ) return None output_bytes = Path(output_path).read_bytes() logger.info( "[FeishuAudio] Transcode complete: %d -> %d bytes", len(input_data), len(output_bytes), ) return output_bytes except Exception as e: logger.error("[FeishuAudio] Transcode error: %s", e) return None finally: Path(input_path).unlink(missing_ok=True) Path(output_path).unlink(missing_ok=True)