Improve mini-player and add periodic sync
- Redesign mini-player: progress bar on top, centered controls - Add vertical volume slider with popup on hover - Add volume percentage display - Add custom speaker SVG icons - Add periodic sync every 10 seconds for playback synchronization - Broadcast user_joined when connecting via WebSocket - Disable nginx proxy buffering for streaming - Allow extra env variables in pydantic settings 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,69 @@
|
||||
import asyncio
|
||||
from contextlib import asynccontextmanager
|
||||
from datetime import datetime
|
||||
from fastapi import FastAPI
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from sqlalchemy import select
|
||||
from .routers import auth, rooms, tracks, websocket, messages
|
||||
from .database import async_session
|
||||
from .models.room import Room
|
||||
from .services.sync import manager
|
||||
|
||||
app = FastAPI(title="EnigFM", description="Listen to music together with friends")
|
||||
|
||||
async def periodic_sync():
|
||||
"""Send sync updates to all rooms every 10 seconds"""
|
||||
while True:
|
||||
await asyncio.sleep(10)
|
||||
|
||||
# Get all active rooms
|
||||
for room_id in list(manager.active_connections.keys()):
|
||||
try:
|
||||
async with async_session() as db:
|
||||
result = await db.execute(select(Room).where(Room.id == room_id))
|
||||
room = result.scalar_one_or_none()
|
||||
|
||||
if not room or not room.is_playing:
|
||||
continue
|
||||
|
||||
# Calculate current position
|
||||
current_position = room.playback_position or 0
|
||||
if room.playback_started_at:
|
||||
elapsed = (datetime.utcnow() - room.playback_started_at).total_seconds() * 1000
|
||||
current_position = int((room.playback_position or 0) + elapsed)
|
||||
|
||||
track_url = None
|
||||
if room.current_track_id:
|
||||
track_url = f"/api/tracks/{room.current_track_id}/stream"
|
||||
|
||||
await manager.broadcast_to_room(
|
||||
room_id,
|
||||
{
|
||||
"type": "sync_state",
|
||||
"is_playing": room.is_playing,
|
||||
"position": current_position,
|
||||
"current_track_id": str(room.current_track_id) if room.current_track_id else None,
|
||||
"track_url": track_url,
|
||||
"server_time": datetime.utcnow().isoformat(),
|
||||
},
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
# Start background sync task
|
||||
sync_task = asyncio.create_task(periodic_sync())
|
||||
yield
|
||||
# Cleanup
|
||||
sync_task.cancel()
|
||||
try:
|
||||
await sync_task
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
|
||||
|
||||
app = FastAPI(title="EnigFM", description="Listen to music together with friends", lifespan=lifespan)
|
||||
|
||||
# CORS
|
||||
app.add_middleware(
|
||||
|
||||
Reference in New Issue
Block a user