from typing import Any import dotenv from flask import Flask, Response, jsonify, request from flask_cors import CORS from flask_socketio import SocketIO, emit from .connect import get_connection from .room import Room from .song import Song, init_db, get_song_by_title_artist, add_song_in_db from .song_fetch import lastfm_query_search, download_song_mp3 from .qrcode_gen import generate_qr from typing import Any dotenv.load_dotenv() app = Flask(__name__) app.config["SECRET_KEY"] = "your_secret_key" socketio = SocketIO(app) CORS(app) db_conn = get_connection() state = State(app, socketio, db_conn.cursor()) init_db(state.db) state.rooms[1000] = Room( id=1000, coord=(1.0, 5.5), name="Test Room", pin=None, tags=set(), songs={}, history=[], playing=[Song(uuid="", title="", artist="<artist>", tags=[], image_id="<img>", youtube_id="<yt>")], playing_idx=0, ) def error(msg: str, status: int = 400) -> Response: res = jsonify({"success": False, "error": msg}) res.status_code = status return res def ws_broadcast(event: str, *, room_id: int | None = None, data: Any) -> None: final = {} if room_id is not None: final["room_id"] = room_id final["data"] = data emit(event, final, broadcast=True, namespace="/") @app.get("/api/join") def join(): room_id = request.args.get("room") code = request.args.get("code") if room_id is None: return error("Missing room id") if (room := state.rooms.get(int(room_id))) is None: return error("Invalid room") if room.pin is not None and room.pin != code: return error("Invalid code") return {"success": True, "ws": f"/ws/{room_id}"} @app.get("/api/queue") def queue(): if (room_id := request.args.get("room")) is None: return error("Missing room id") if (room := state.rooms.get(int(room_id))) is None: return error("Invalid room") return {"success": True, "queue": room.playing, "index": room.playing_idx} @app.post("/api/queue/next") def queue_next(): if (room_id := request.args.get("room")) is None: return error("Missing room id") if (room := state.rooms.get(int(room_id))) is None: return error("Invalid room") room.playing_idx += 1 if room.playing_idx >= len(room.playing): ## queue ended # room.renew_queue() emit("update_songs", {"songs": [1, 2, 3]}, broadcast=True, namespace="/") return {"success": True, "ended": True, "index": room.playing_idx, "queue": room.playing} return {"success": True, "ended": False, "index": room.playing_idx} @app.post("/api/room/new") def room_new(): if (room_name := request.args.get("name")) is None: return error("Missing room name") if (room_cords := request.args.get("coords")) is None: return error("Missing room coords") if room_pin := request.args.get("pin"): room_pin = int(room_pin) else: room_pin = None lat, lon = room_cords.split(",") room = Room( id=max(state.rooms or [0]) + 1, # coord=(float(lat), float(lon)), name=room_name, pin=room_pin, tags=set([tag for tag in request.args.get("tags", "").split(",") if tag]), songs={}, history=[], playing=[], playing_idx=-1, ) state.rooms[room.id] = room return {"success": True, "room_id": room.id} @app.get("/api/room") def room(): return [ { "id": room.id, "name": room.name, "private": room.pin is not None, "coords": room.coord, } for room in state.rooms.values() ] @app.post("/api/addsong") def add_song(): if (room_id := request.args.get("room")) is None: return error("Missing room id") if (room := state.rooms.get(int(room_id))) is None: return error("Invalid room") if (query := request.args.get("query")) is None: return error("Missing query") info = lastfm_query_search(query) if (song := get_song_by_title_artist(info.title, info.artist)) is None: res = download_song_mp3(info.title, info.artist) if res is None: return error("Cannot get info from YT") yt_id, _ = res ## song not found, downolad from YT ## add in DB add_song_in_db(info.artist, info.title, info.tags, info.img_id, yt_id) ## HERE: add song in the room list return {"artist": info.artist, "title": info.title, "tags": info.tags, "image_id": info.img_id} @app.get("/api/room/qrcode") def room_qrcode(): if (room_id := request.args.get("room")) is None: return error("Missing room id") if (pin := request.args.get("pin")) is not None: pin = int(pin) stream = generate_qr( base_uri="https://chillbox.leoinvents.com", room_id=int(room_id), pin=pin, ) return Response(stream, content_type="image/jpeg") if __name__ == "__main__": socketio.run(app, debug=True)