mirror of
https://github.com/jamiepine/voicebox.git
synced 2026-09-16 13:20:39 -07:00
fix(audio): serve real Content-Type so imports decode in WaveSurfer
/audio/{id} and /audio/version/{id} hardcoded media_type="audio/wav" on
the FileResponse. That was a no-op when every generation came out of
TTS (everything on disk was a .wav anyway), but imported audio keeps
its source format — .mp3 / .m4a / .ogg — and the WaveSurfer MediaElement
backend uses an <audio> tag that checks Content-Type before letting the
clip play, so an MP3 announced as audio/wav silently failed to load.
Both endpoints now derive the type via mimetypes.guess_type and fall
back to audio/wav for unknown suffixes. Download filenames also keep
the real extension instead of always saying ".wav".
This commit is contained in:
+17
-4
@@ -1,5 +1,8 @@
|
||||
"""Audio file serving endpoints."""
|
||||
|
||||
import mimetypes
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from fastapi.responses import FileResponse
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -11,6 +14,16 @@ from ..database import get_db
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
def _audio_media_type(path: Path) -> str:
|
||||
"""Derive the Content-Type from the file extension.
|
||||
|
||||
Imported audio retains its source format (.mp3, .m4a, .ogg, …) so a
|
||||
blanket ``audio/wav`` would mislead strict clients trying to decode
|
||||
via the response header instead of sniffing the bytes."""
|
||||
guessed, _ = mimetypes.guess_type(path.name)
|
||||
return guessed or "audio/wav"
|
||||
|
||||
|
||||
@router.get("/audio/version/{version_id}")
|
||||
async def get_version_audio(version_id: str, db: Session = Depends(get_db)):
|
||||
"""Serve audio for a specific version."""
|
||||
@@ -26,8 +39,8 @@ async def get_version_audio(version_id: str, db: Session = Depends(get_db)):
|
||||
|
||||
return FileResponse(
|
||||
audio_path,
|
||||
media_type="audio/wav",
|
||||
filename=f"generation_{version.generation_id}_{version.label}.wav",
|
||||
media_type=_audio_media_type(audio_path),
|
||||
filename=f"generation_{version.generation_id}_{version.label}{audio_path.suffix}",
|
||||
)
|
||||
|
||||
|
||||
@@ -44,8 +57,8 @@ async def get_audio(generation_id: str, db: Session = Depends(get_db)):
|
||||
|
||||
return FileResponse(
|
||||
audio_path,
|
||||
media_type="audio/wav",
|
||||
filename=f"generation_{generation_id}.wav",
|
||||
media_type=_audio_media_type(audio_path),
|
||||
filename=f"generation_{generation_id}{audio_path.suffix}",
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user