From 2df62ff7143731cf1796e66ffa276826f05dd8f6 Mon Sep 17 00:00:00 2001 From: Leonardo Segala Date: Fri, 1 Aug 2025 22:07:39 +0200 Subject: [PATCH 1/2] Add queue next endpoint --- backend/requirements.txt | 1 + backend/src/app.py | 26 ++++++++++++++++++++++---- backend/src/room.py | 1 + 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/backend/requirements.txt b/backend/requirements.txt index 7623d9f..57b0b9d 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,4 +1,5 @@ Flask==3.1.0 flask-cors +flask-socketio dotenv requests \ No newline at end of file diff --git a/backend/src/app.py b/backend/src/app.py index 1abebfb..5f2b1f6 100644 --- a/backend/src/app.py +++ b/backend/src/app.py @@ -1,6 +1,8 @@ import dotenv from flask import Flask, Response, jsonify, request + from flask_cors import CORS +from flask_socketio import SocketIO, emit from .room import Room from .song import Song, init_db @@ -11,6 +13,8 @@ dotenv.load_dotenv() app = Flask(__name__) +app.config["SECRET_KEY"] = "your_secret_key" +socketio = SocketIO(app) CORS(app) @@ -24,6 +28,7 @@ ROOMS: dict[int, Room] = { {}, [], [Song(mbid="test", title="", artist="<artist placeholder>", tags=["Metal"], image_id="img-id", youtube_id="yt-id")], + playing_idx=1, ) } # { room_id: room, ... } @@ -63,13 +68,26 @@ def queue(): @app.post("/api/queue/next") -def queue_next(): ... +def queue_next(): + if (room_id := request.args.get("room")) is None: + return error("Missing room id") + if (room := ROOMS.get(int(room_id))) is None: + return error("Invalid room") -@app.post("/api/queue/renew") -def queue_renew(): ... + 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": []} + + return {"success": True, "ended": False, "index": room.playing_idx} init_db() if __name__ == "__main__": - app.run(debug=True) + socketio.run(app, debug=True) diff --git a/backend/src/room.py b/backend/src/room.py index e6ebd4b..a5e38a8 100644 --- a/backend/src/room.py +++ b/backend/src/room.py @@ -24,6 +24,7 @@ class Room: songs: dict[str, UserScoredSong] # canzoni + voto history: list[Song] # canzoni riprodotte (in ordine) playing: list[Song] # canzoni che sono i riproduzione + playing_idx: int def rank_song(self, song: Song, user_score: int) -> float: rank = 0.0 From b06d02ca624f282cefd26d43af983d668a3ec21c Mon Sep 17 00:00:00 2001 From: Simone Tesini <simozilla006@gmail.com> Date: Fri, 1 Aug 2025 22:10:59 +0200 Subject: [PATCH 2/2] add tests --- backend/src/app.py | 4 ++- backend/src/room.py | 88 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 77 insertions(+), 15 deletions(-) diff --git a/backend/src/app.py b/backend/src/app.py index 2b636c3..b99d40b 100644 --- a/backend/src/app.py +++ b/backend/src/app.py @@ -2,7 +2,7 @@ import dotenv from flask import Flask, Response, jsonify, request from flask_cors import CORS -from .room import Room +from .room import Room, test_algo from .song import init_db dotenv.load_dotenv() @@ -44,5 +44,7 @@ def join(): init_db() +test_algo() +exit() if __name__ == "__main__": app.run(debug=True) diff --git a/backend/src/room.py b/backend/src/room.py index 51b96e2..7baf617 100644 --- a/backend/src/room.py +++ b/backend/src/room.py @@ -1,3 +1,4 @@ +import random from dataclasses import dataclass from .song import Song @@ -13,6 +14,18 @@ RECENT_COUNT = 10 type UserScoredSong = tuple[Song, int] +@dataclass +class Rank: + user_score: float + tag: float + artist: float + random: float + recent_penalty: float + + def total(self) -> float: + return self.user_score + self.tag + self.artist + self.random - self.recent_penalty + + @dataclass class Room: id: int @@ -24,41 +37,88 @@ class Room: songs: dict[str, UserScoredSong] history: list[Song] - def rank_song(self, song: Song, user_score: int) -> float: - rank = 0.0 + def rank_song_from_id(self, id: str) -> Rank: + scored = self.songs[id] + return self.rank_song(scored[0], scored[1]) + + def rank_song(self, song: Song, user_score: int) -> Rank: song_items = self.songs.items() lowest_score = min(song_items, key=lambda item: item[1][1])[1][1] - highest_score = min(song_items, key=lambda item: item[1][1])[1][1] + highest_score = max(song_items, key=lambda item: item[1][1])[1][1] - rank += translate(user_score, lowest_score, highest_score, 0.0, USER_SCORE_WEIGHT) + score_rank = translate(user_score, lowest_score, highest_score, 0.0, USER_SCORE_WEIGHT) recent_songs = self.history[-RECENT_COUNT:] tag_counts = {} artist_counts = {} - for song in recent_songs: - for tag in song.tags: + for recent_song in recent_songs: + for tag in recent_song.tags: if tag not in tag_counts: tag_counts[tag] = 0 tag_counts[tag] += 1 - if song.artist not in artist_counts: - artist_counts[song.artist] = 0 - artist_counts[song.artist] += 1 + if recent_song.artist not in artist_counts: + artist_counts[recent_song.artist] = 0 + artist_counts[recent_song.artist] += 1 tag_total = 0 for tag in song.tags: if tag in tag_counts: tag_total += tag_counts[tag] - rank += translate(tag_total, 0, RECENT_COUNT, 0, TAG_WEIGHT) - rank += translate(artist_counts[song.artist], 0, RECENT_COUNT, 0, ARTIST_WEIGHT) + artist_total = artist_counts[song.artist] if song.artist in artist_counts else 0 - if song in recent_songs: - rank -= RECENT_PENALTY + tag_value = min(RECENT_COUNT, len(self.history)) - tag_total + artist_value = min(RECENT_COUNT, len(self.history)) - artist_total - return rank + tag_rank = translate(tag_value, 0, min(RECENT_COUNT, len(self.history)), 0, TAG_WEIGHT) + artist_rank = translate(artist_value, 0, min(RECENT_COUNT, len(self.history)), 0, ARTIST_WEIGHT) + + random_rank = translate(random.random(), 0, 1, 0.0, RANDOM_WEIGHT) + + recent_penalty = RECENT_PENALTY if song in recent_songs else 0 + + return Rank(score_rank, tag_rank, artist_rank, random_rank, recent_penalty) def translate(value: float, in_min: float, in_max: float, out_min: float, out_max: float): + if in_max == in_min: + return out_min return (value - in_min) / (in_max - in_min) * (out_max - out_min) + out_min + + +def test_algo(): + songs = [ + Song("paulham", "Io e i miei banchi", "Paul Ham", ["pop"], "", ""), + Song("cisco", "CiscoPT", "Cantarex", ["rap"], "", ""), + Song("vpn", "VPN", "Cantarex", ["rap"], "", ""), + Song("gang", "Gang Gang Gang", "Cantarex", ["rap"], "", ""), + Song("bertha1", "Rindondantha", "Berthanetti", ["rock"], "", ""), + Song("bertha2", "Ragatthi", "Berthanetti", ["rock"], "", ""), + Song("bertha3", "Tranthathione", "Berthanetti", ["rock"], "", ""), + Song("cexx", "Spritz", "Cex", ["kpop"], "", ""), + ] + + room = Room( + 123, + (0.0, 0.0), + "test", + None, + set(["rock", "rap"]), + { + "paulham": (songs[0], 2), + "cisco": (songs[1], 1), + "vpn": (songs[2], 5), + "gang": (songs[3], 1), + "bertha1": (songs[4], 1), + "bertha2": (songs[5], 1), + "bertha3": (songs[6], 1), + "cexx": (songs[7], -123123), + }, + [songs[4], songs[5], songs[0]], + ) + + print(room.rank_song_from_id("paulham"), room.rank_song_from_id("paulham").total()) + print(room.rank_song_from_id("vpn"), room.rank_song_from_id("vpn").total()) + print(room.rank_song_from_id("cexx"), room.rank_song_from_id("cexx").total())