import asyncio from fastapi import FastAPI, WebSocket, WebSocketDisconnect from fastapi.staticfiles import StaticFiles from models import MusicPlayer, PlayerState, WSConnectionType from services import ConnectionManager, DownloadService # Setup tags_metadata = [ {"name": "player", "description": "Interact with the Music Player"}, {"name": "experimental"}, {"name": "queue"}, ] api_app = FastAPI(openapi_tags=tags_metadata, title="Dashdio API") player = MusicPlayer() dl_service = DownloadService() ws_manager = ConnectionManager() app = FastAPI(title="Dashdio App") # Interface app.mount("/api", api_app) app.mount("/", StaticFiles(directory="ui", html=True), name="ui") @app.on_event("startup") async def start_event_loop(): asyncio.create_task(state_broadcast_loop()) asyncio.create_task(queue_broadcast_loop()) async def state_broadcast_loop(): while True: await player._state_event.wait() await ws_manager.broadcast(WSConnectionType.state, player.get_state()) player._state_event.clear() async def queue_broadcast_loop(): while True: await player._queue_event.wait() await ws_manager.broadcast(WSConnectionType.queue, player.get_queue()) player._queue_event.clear() # Status updates @api_app.websocket("/player") async def websocket_player(websocket: WebSocket): await ws_manager.connect(websocket, WSConnectionType.state) try: while True: await websocket.receive_text() await ws_manager.send(websocket, player.get_state()) except WebSocketDisconnect: ws_manager.disconnect(websocket) # Queue updates @api_app.websocket("/queue") async def websocket_queue(websocket: WebSocket): await ws_manager.connect(websocket, WSConnectionType.queue) try: while True: await websocket.receive_text() await ws_manager.send(websocket, player.get_queue()) except WebSocketDisconnect: ws_manager.disconnect(websocket) @api_app.get("/queue", tags=["queue"]) def get_queue(): return player.get_queue() @api_app.post("/queue", tags=["queue"]) async def post_to_queue(url: str): track = await dl_service.download(url) await player.add_to_queue(track) @api_app.delete("/queue/{track_id}", tags=["queue"]) def delete_from_queue(track_id: str): player.remove_from_queue_by_id(track_id) @api_app.post("/player/play", tags=["player"]) async def player_play(): await player.play() @api_app.post("/player/stop", tags=["player"]) async def player_stop(): await player.stop() @api_app.post("/player/skip", tags=["player"]) async def player_skip(): await player.next() # Player @api_app.put("/player/volume", tags=["player"]) async def set_volume(volume: float): await player.set_volume(volume) @api_app.get("/player/volume", tags=["player"]) def get_volume(): return {"volume": player.get_volume()} @api_app.get("/player", tags=["player"]) def get_player_state() -> PlayerState: return player.get_state()