music-app/backend/app/routers/shareplay.py
2026-07-03 01:06:35 +00:00

104 lines
3.5 KiB
Python

from fastapi import APIRouter, Depends, HTTPException
from starlette.websockets import WebSocket, WebSocketDisconnect
from sqlalchemy.orm import Session
from typing import Optional
from pydantic import BaseModel
from ..db.database import get_db
from ..models.shareplay import SharePlayRoom, SharePlayCue as SharePlayCueModel
from ..schemas.shareplay import SharePlayRoomResponse, SharePlayCommand, SharePlayCueResponse
from ..services.shareplay import SharePlayManager
class RoomIdRequest(BaseModel):
room_id: str
class ControlRequest(BaseModel):
room_id: str
type: str
payload: Optional[dict] = None
router = APIRouter(prefix="/api/shareplay", tags=["shareplay"])
manager = SharePlayManager()
@router.post("/create")
def create_room(db: Session = Depends(get_db)):
return manager.create_room(db, creator="user")
@router.post("/join")
def join_room(data: RoomIdRequest, db: Session = Depends(get_db)):
result = manager.join_room(db, data.room_id)
if not result:
raise HTTPException(status_code=404, detail="Room not found")
return result
@router.post("/leave")
def leave_room(data: RoomIdRequest, db: Session = Depends(get_db)):
success = manager.leave_room(db, data.room_id)
if not success:
raise HTTPException(status_code=404, detail="Room not found")
return {"message": "Left room"}
@router.get("/cue")
def get_cue(room_id: str, db: Session = Depends(get_db)):
items = manager.get_cue(db, room_id)
return SharePlayCueResponse(items=items, next_song=None)
@router.post("/cue")
def add_to_cue(room_id: str, song_id: str, db: Session = Depends(get_db)):
success = manager.add_to_cue(db, room_id, song_id)
if not success:
raise HTTPException(status_code=400, detail="Failed to add to cue")
return {"message": "Added to cue"}
@router.post("/control")
def send_control(data: ControlRequest, db: Session = Depends(get_db)):
state = manager.get_state(data.room_id)
if not state:
raise HTTPException(status_code=404, detail="Room not found")
if data.type == "play":
manager.update_state(data.room_id, is_playing=True)
elif data.type == "pause":
manager.update_state(data.room_id, is_playing=False)
elif data.type == "seek" and data.payload:
manager.update_state(data.room_id, position=data.payload.get("position", 0))
elif data.type == "shuffle":
current = manager.get_state(data.room_id)
manager.update_state(data.room_id, shuffle=not current.get("shuffle", False))
return {"message": f"Command '{data.type}' sent"}
# WebSocket endpoint
@router.websocket("/ws/{room_id}")
async def websocket_endpoint(websocket: WebSocket, room_id: str):
await websocket.accept()
state = manager.get_state(room_id)
if state:
await websocket.send_json({"type": "state", "data": state})
try:
while True:
data = await websocket.receive_text()
import json
message = json.loads(data)
if message.get("type") == "control":
cmd = message.get("payload", {})
state = manager.get_state(room_id)
if state and cmd.get("type") == "play":
manager.update_state(room_id, is_playing=True)
elif state and cmd.get("type") == "pause":
manager.update_state(room_id, is_playing=False)
await websocket.send_json({"type": "ack", "data": message})
except WebSocketDisconnect:
pass