4ade6939b6
The audio stream endpoint was unauthenticated. Add a get_streaming_user dependency that accepts the access token either as a ?token= query param (the browser <audio> element can't send an Authorization header) or a bearer header for native clients. Update streaming tests accordingly and add a test asserting unauthenticated requests are rejected with 401. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
40 lines
1.0 KiB
Python
40 lines
1.0 KiB
Python
"""Audio streaming endpoint — direct stream with Range support."""
|
|
|
|
import uuid
|
|
from typing import Annotated
|
|
|
|
from fastapi import APIRouter, Header
|
|
from fastapi.responses import StreamingResponse
|
|
|
|
from app.api.deps import StreamingServiceDep, StreamUser
|
|
|
|
router = APIRouter(prefix="/stream", tags=["streaming"])
|
|
|
|
|
|
@router.get("/{track_id}")
|
|
async def stream_track(
|
|
track_id: uuid.UUID,
|
|
service: StreamingServiceDep,
|
|
_user: StreamUser,
|
|
range_header: Annotated[str | None, Header(alias="Range")] = None,
|
|
) -> StreamingResponse:
|
|
result = await service.open_stream(track_id, range_header)
|
|
|
|
headers = {
|
|
"Accept-Ranges": "bytes",
|
|
"Content-Length": str(result.content_length),
|
|
}
|
|
|
|
if result.is_partial:
|
|
headers["Content-Range"] = f"bytes {result.start}-{result.end}/{result.total_size}"
|
|
status_code = 206
|
|
else:
|
|
status_code = 200
|
|
|
|
return StreamingResponse(
|
|
result.stream,
|
|
status_code=status_code,
|
|
headers=headers,
|
|
media_type=result.content_type,
|
|
)
|