Add global mini-player and improve configuration
- Add global activeRoom store for persistent WebSocket connection - Add MiniPlayer component for playback controls across pages - Add chunked S3 streaming with 64KB chunks and Range support - Add queue item removal button - Move DB credentials to environment variables - Update .env.example with DB configuration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import uuid
|
||||
from urllib.parse import quote
|
||||
from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File, Form, Request, Response
|
||||
from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File, Form, Request
|
||||
from fastapi.responses import StreamingResponse
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select, func
|
||||
@@ -11,7 +11,7 @@ from ..models.user import User
|
||||
from ..models.track import Track
|
||||
from ..schemas.track import TrackResponse, TrackWithUrl
|
||||
from ..services.auth import get_current_user
|
||||
from ..services.s3 import upload_file, delete_file, generate_presigned_url, can_upload_file, get_file_content
|
||||
from ..services.s3 import upload_file, delete_file, generate_presigned_url, can_upload_file, get_file_size, stream_file_chunks
|
||||
from ..config import get_settings
|
||||
|
||||
settings = get_settings()
|
||||
@@ -172,9 +172,11 @@ async def stream_track(track_id: uuid.UUID, request: Request, db: AsyncSession =
|
||||
if not track:
|
||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Track not found")
|
||||
|
||||
# Get full file content
|
||||
content = get_file_content(track.s3_key)
|
||||
file_size = len(content)
|
||||
# Get file size from S3 (without downloading)
|
||||
file_size = get_file_size(track.s3_key)
|
||||
|
||||
# Encode filename for non-ASCII characters
|
||||
encoded_filename = quote(f"{track.title}.mp3")
|
||||
|
||||
# Parse Range header
|
||||
range_header = request.headers.get("range")
|
||||
@@ -192,11 +194,8 @@ async def stream_track(track_id: uuid.UUID, request: Request, db: AsyncSession =
|
||||
end = min(end, file_size - 1)
|
||||
content_length = end - start + 1
|
||||
|
||||
# Encode filename for non-ASCII characters
|
||||
encoded_filename = quote(f"{track.title}.mp3")
|
||||
|
||||
return Response(
|
||||
content=content[start:end + 1],
|
||||
return StreamingResponse(
|
||||
stream_file_chunks(track.s3_key, start, end),
|
||||
status_code=206,
|
||||
media_type="audio/mpeg",
|
||||
headers={
|
||||
@@ -207,12 +206,9 @@ async def stream_track(track_id: uuid.UUID, request: Request, db: AsyncSession =
|
||||
}
|
||||
)
|
||||
|
||||
# Encode filename for non-ASCII characters
|
||||
encoded_filename = quote(f"{track.title}.mp3")
|
||||
|
||||
# No range - return full file
|
||||
return Response(
|
||||
content=content,
|
||||
# No range - stream full file
|
||||
return StreamingResponse(
|
||||
stream_file_chunks(track.s3_key),
|
||||
media_type="audio/mpeg",
|
||||
headers={
|
||||
"Accept-Ranges": "bytes",
|
||||
|
||||
Reference in New Issue
Block a user