From ebf3d29fa811148b7637a247fb564a4b3482e87f Mon Sep 17 00:00:00 2001 From: Leonardo Segala Date: Sat, 2 Aug 2025 07:59:50 +0200 Subject: [PATCH 01/40] Fix nasty assert --- backend/Dockerfile | 3 ++- backend/requirements.txt | 3 ++- backend/src/app.py | 14 +++++++------- backend/src/room.py | 2 +- backend/src/song.py | 2 +- backend/src/state.py | 2 +- 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index c6a1412..3390030 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -12,5 +12,6 @@ RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 5000 -CMD ["flask", "--app", "src.app", "run", "--debug", "--host=0.0.0.0"] +# CMD ["flask", "--app", "src.app", "run", "--debug", "--host=0.0.0.0"] +CMD ["python3", "src/app.py"] # flask --app src.app run --host=0.0.0.0 --port=5001 --debug diff --git a/backend/requirements.txt b/backend/requirements.txt index 5eae02e..cb18a70 100644 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -4,4 +4,5 @@ flask-socketio dotenv requests qrcode -Pillow \ No newline at end of file +Pillow +eventlet>=0.33 diff --git a/backend/src/app.py b/backend/src/app.py index c11cf37..d4b5648 100644 --- a/backend/src/app.py +++ b/backend/src/app.py @@ -5,12 +5,12 @@ from flask import Flask, Response, jsonify, request from flask_cors import CORS from flask_socketio import SocketIO, join_room, leave_room -from .state import State -from .connect import get_connection -from .room import Room -from .song import Song, init_db, get_song_by_title_artist, add_song_in_db, get_song_by_uuid -from .song_fetch import query_search, yt_get_audio_url, yt_search_song -from .qrcode_gen import generate_qr +from state import State +from connect import get_connection +from room import Room +from song import Song, init_db, get_song_by_title_artist, add_song_in_db, get_song_by_uuid +from song_fetch import query_search, yt_get_audio_url, yt_search_song +from qrcode_gen import generate_qr dotenv.load_dotenv() @@ -273,4 +273,4 @@ def get_audio_url(): if __name__ == "__main__": - socketio.run(app, debug=True) + socketio.run(app, host="0.0.0.0", port=5000, debug=True) diff --git a/backend/src/room.py b/backend/src/room.py index 5109884..519cabb 100644 --- a/backend/src/room.py +++ b/backend/src/room.py @@ -1,7 +1,7 @@ import random from dataclasses import dataclass -from .song import Song +from song import Song USER_SCORE_WEIGHT = 0.7 ARTIST_WEIGHT = 0.1 diff --git a/backend/src/song.py b/backend/src/song.py index 7409d06..f95609b 100644 --- a/backend/src/song.py +++ b/backend/src/song.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from sqlite3 import Cursor -from .connect import get_connection +from connect import get_connection def init_db(db: Cursor): diff --git a/backend/src/state.py b/backend/src/state.py index e1f3e7c..73d05d2 100644 --- a/backend/src/state.py +++ b/backend/src/state.py @@ -4,7 +4,7 @@ from sqlite3 import Cursor from flask import Flask from flask_socketio import SocketIO -from .room import Room +from room import Room @dataclass From ca0b44122995bbfca5d2e23bb6fa32105554ddb1 Mon Sep 17 00:00:00 2001 From: Leonardo Segala Date: Sat, 2 Aug 2025 08:00:06 +0200 Subject: [PATCH 02/40] Fix color --- frontend/src/lib/components/QueueSlider.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/lib/components/QueueSlider.svelte b/frontend/src/lib/components/QueueSlider.svelte index ec5a647..94430f0 100644 --- a/frontend/src/lib/components/QueueSlider.svelte +++ b/frontend/src/lib/components/QueueSlider.svelte @@ -19,7 +19,7 @@ class={`flex h-[60vw] max-h-[250px] w-[60vw] max-w-[250px] items-center justify-center ${i === 1 ? "spin-slower rounded-full border-2 border-black" : "rounded"} object-cover`} > {#if i === 1} -
+
{/if} Song cover From adc362562e68a2421b5d971cb93f72e2abce60a8 Mon Sep 17 00:00:00 2001 From: panzerotto Date: Sat, 2 Aug 2025 08:10:22 +0200 Subject: [PATCH 03/40] add deny people not in range --- backend/src/app.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backend/src/app.py b/backend/src/app.py index c11cf37..946f38f 100644 --- a/backend/src/app.py +++ b/backend/src/app.py @@ -11,6 +11,7 @@ from .room import Room from .song import Song, init_db, get_song_by_title_artist, add_song_in_db, get_song_by_uuid from .song_fetch import query_search, yt_get_audio_url, yt_search_song from .qrcode_gen import generate_qr +from .gps import is_within_range dotenv.load_dotenv() @@ -74,6 +75,7 @@ def on_leave(data): def join(): room_id = request.args.get("room") code = request.args.get("code") + user_location = request.args.get("location") if room_id is None: return error("Missing room id") @@ -84,6 +86,9 @@ def join(): if room.pin is not None and room.pin != code: return error("Invalid code") + if is_within_range(user_location, room.coord, room.range_size) is False: + return error("You are not within the room range") + return {"success": True, "ws": f"/ws/{room_id}"} From 78f03dec5daf9c5f238768ba7e08f2c75cd29f13 Mon Sep 17 00:00:00 2001 From: Leonardo Segala Date: Sat, 2 Aug 2025 08:31:31 +0200 Subject: [PATCH 04/40] Minimal aesthetic upgrades --- frontend/src/lib/components/SuggestionList.svelte | 15 ++++++++------- frontend/src/routes/+layout.svelte | 2 +- frontend/src/routes/room/[id]/+page.svelte | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/frontend/src/lib/components/SuggestionList.svelte b/frontend/src/lib/components/SuggestionList.svelte index 285d242..ffc25d6 100644 --- a/frontend/src/lib/components/SuggestionList.svelte +++ b/frontend/src/lib/components/SuggestionList.svelte @@ -1,5 +1,6 @@ -
+
{@render children()}
diff --git a/frontend/src/routes/room/[id]/+page.svelte b/frontend/src/routes/room/[id]/+page.svelte index e53cb58..6237b13 100644 --- a/frontend/src/routes/room/[id]/+page.svelte +++ b/frontend/src/routes/room/[id]/+page.svelte @@ -69,7 +69,7 @@ {#if returnError} {:else} -
+
From 4bf93b565b4f871970d39a41d45a0cfc6c2b2699 Mon Sep 17 00:00:00 2001 From: panzerotto Date: Sat, 2 Aug 2025 08:43:41 +0200 Subject: [PATCH 05/40] add filter to room list --- backend/src/app.py | 15 ++++++++++++--- backend/src/room.py | 1 + 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/backend/src/app.py b/backend/src/app.py index 946f38f..4df4376 100644 --- a/backend/src/app.py +++ b/backend/src/app.py @@ -11,7 +11,7 @@ from .room import Room from .song import Song, init_db, get_song_by_title_artist, add_song_in_db, get_song_by_uuid from .song_fetch import query_search, yt_get_audio_url, yt_search_song from .qrcode_gen import generate_qr -from .gps import is_within_range +from .gps import is_within_range, distance_between_coords, Coordinates dotenv.load_dotenv() @@ -75,7 +75,6 @@ def on_leave(data): def join(): room_id = request.args.get("room") code = request.args.get("code") - user_location = request.args.get("location") if room_id is None: return error("Missing room id") @@ -86,7 +85,7 @@ def join(): if room.pin is not None and room.pin != code: return error("Invalid code") - if is_within_range(user_location, room.coord, room.range_size) is False: + if room.distance > room.range_size: return error("You are not within the room range") return {"success": True, "ws": f"/ws/{room_id}"} @@ -164,6 +163,14 @@ def room_new(): @app.get("/api/room") def room(): + lat = request.args.get("lat") + lon = request.args.get("lon") + if lat and lon: + user_coords = Coordinates(latitude=float(lat), longitude=float(lon)) + else: + return error("Missing user coordinates") + + distance = distance_between_coords(user_coords, room.coord) return [ { "id": room.id, @@ -171,8 +178,10 @@ def room(): "private": room.pin is not None, "coords": room.coord, "range": room.range_size, + "distance": distance, } for room in state.rooms.values() + if distance <= room.range_size ] diff --git a/backend/src/room.py b/backend/src/room.py index 5109884..c986340 100644 --- a/backend/src/room.py +++ b/backend/src/room.py @@ -35,6 +35,7 @@ class Room: pin: int | None tags: set[str] range_size: int # in meters ?? + distance: float songs: dict[str, UserScoredSong] # all songs + user score (the playlist) history: list[Song] # all songs previously played From b7aebadffe409d00c3dbeaf417b7487a59680c59 Mon Sep 17 00:00:00 2001 From: Leonardo Segala Date: Sat, 2 Aug 2025 09:05:30 +0200 Subject: [PATCH 06/40] Fix gps coords --- backend/src/app.py | 14 ++++++++------ backend/src/gps.py | 2 ++ backend/src/room.py | 4 ++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/backend/src/app.py b/backend/src/app.py index d70afd4..1d304e9 100644 --- a/backend/src/app.py +++ b/backend/src/app.py @@ -85,7 +85,9 @@ def join(): if room.pin is not None and room.pin != code: return error("Invalid code") - if room.distance > room.range_size: + distance = distance_between_coords(room.coord, Coordinates(latitude=int(request.args["lat"]), longitude=int(request.args["lot"]))) + + if distance > room.range_size: return error("You are not within the room range") return {"success": True, "ws": f"/ws/{room_id}"} @@ -145,7 +147,7 @@ def room_new(): room = Room( id=max(state.rooms or [0]) + 1, # - coord=(float(lat), float(lon)), + coord=Coordinates(int(lat), int(lon)), range_size=int(room_range), name=room_name, pin=room_pin, @@ -165,12 +167,12 @@ def room_new(): def room(): lat = request.args.get("lat") lon = request.args.get("lon") + if lat and lon: - user_coords = Coordinates(latitude=float(lat), longitude=float(lon)) + user_coords = Coordinates(latitude=int(lat), longitude=int(lon)) else: return error("Missing user coordinates") - distance = distance_between_coords(user_coords, room.coord) return [ { "id": room.id, @@ -178,10 +180,10 @@ def room(): "private": room.pin is not None, "coords": room.coord, "range": room.range_size, - "distance": distance, + "distance": d, } for room in state.rooms.values() - if distance <= room.range_size + if (d := distance_between_coords(user_coords, room.coord)) <= room.range_size ] diff --git a/backend/src/gps.py b/backend/src/gps.py index 546531b..4232267 100644 --- a/backend/src/gps.py +++ b/backend/src/gps.py @@ -1,6 +1,8 @@ import math +from dataclasses import dataclass +@dataclass class Coordinates: latitude: int longitude: int diff --git a/backend/src/room.py b/backend/src/room.py index cad4020..cb775b6 100644 --- a/backend/src/room.py +++ b/backend/src/room.py @@ -1,6 +1,7 @@ import random from dataclasses import dataclass +from gps import Coordinates from song import Song USER_SCORE_WEIGHT = 0.7 @@ -30,12 +31,11 @@ class Rank: @dataclass class Room: id: int - coord: tuple[float, float] + coord: Coordinates name: str pin: int | None tags: set[str] range_size: int # in meters ?? - distance: float songs: dict[str, UserScoredSong] # all songs + user score (the playlist) history: list[Song] # all songs previously played From 3a944767a8b2ea09dacfd0cee57659a0e47cdfcc Mon Sep 17 00:00:00 2001 From: Leonardo Segala Date: Sat, 2 Aug 2025 09:07:52 +0200 Subject: [PATCH 07/40] Fix hard-coded coords --- backend/src/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/app.py b/backend/src/app.py index 1d304e9..f48ef1a 100644 --- a/backend/src/app.py +++ b/backend/src/app.py @@ -29,7 +29,7 @@ init_db(state.db) state.rooms[1000] = Room( id=1000, - coord=(1.0, 5.5), + coord=Coordinates(1, 5), name="Test Room", pin=None, tags=set(), From 6bdbae18818c38ae6f3b84f9c2c1c3ef5c4bcfe9 Mon Sep 17 00:00:00 2001 From: Leonardo Segala Date: Sat, 2 Aug 2025 09:11:39 +0200 Subject: [PATCH 08/40] Fix microsmmarcio --- backend/src/app.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/backend/src/app.py b/backend/src/app.py index f48ef1a..9835362 100644 --- a/backend/src/app.py +++ b/backend/src/app.py @@ -85,7 +85,13 @@ def join(): if room.pin is not None and room.pin != code: return error("Invalid code") - distance = distance_between_coords(room.coord, Coordinates(latitude=int(request.args["lat"]), longitude=int(request.args["lot"]))) + distance = distance_between_coords( + lhs=room.coord, + rhs=Coordinates( + latitude=int(request.args["lat"]), + longitude=int(request.args["lon"]), + ), + ) if distance > room.range_size: return error("You are not within the room range") From cd5e52cb23d61a2028e31f16264947409bf75919 Mon Sep 17 00:00:00 2001 From: Leonardo Segala Date: Sat, 2 Aug 2025 09:19:12 +0200 Subject: [PATCH 09/40] Remove dots from imports --- backend/src/app.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/backend/src/app.py b/backend/src/app.py index 9835362..a6e8e67 100644 --- a/backend/src/app.py +++ b/backend/src/app.py @@ -5,13 +5,13 @@ from flask import Flask, Response, jsonify, request from flask_cors import CORS from flask_socketio import SocketIO, join_room, leave_room -from .state import State -from .connect import get_connection -from .room import Room -from .song import Song, init_db, get_song_by_title_artist, add_song_in_db, get_song_by_uuid -from .song_fetch import query_search, yt_get_audio_url, yt_search_song -from .qrcode_gen import generate_qr -from .gps import is_within_range, distance_between_coords, Coordinates +from state import State +from connect import get_connection +from room import Room +from song import Song, init_db, get_song_by_title_artist, add_song_in_db, get_song_by_uuid +from song_fetch import query_search, yt_get_audio_url, yt_search_song +from qrcode_gen import generate_qr +from gps import is_within_range, distance_between_coords, Coordinates dotenv.load_dotenv() @@ -152,7 +152,7 @@ def room_new(): lat, lon = room_cords.split(",") room = Room( - id=max(state.rooms or [0]) + 1, # + id=max(state.rooms or [0]) + 1, coord=Coordinates(int(lat), int(lon)), range_size=int(room_range), name=room_name, From 2c1928822bebe0b0a20f44adecf84c541dbdca7c Mon Sep 17 00:00:00 2001 From: Mat12143 Date: Sat, 2 Aug 2025 09:19:39 +0200 Subject: [PATCH 10/40] feat: implemented gps location check --- frontend/src/lib/components/QueueSlider.svelte | 10 +++++----- .../src/lib/components/SuggestionInput.svelte | 18 ++++++++++++++---- frontend/src/lib/types.ts | 12 ++++++------ frontend/src/lib/utils.ts | 4 ++-- frontend/src/routes/admin/[id]/+page.svelte | 11 +++++------ frontend/src/routes/room/[id]/+page.svelte | 12 ++++++++++-- 6 files changed, 42 insertions(+), 25 deletions(-) diff --git a/frontend/src/lib/components/QueueSlider.svelte b/frontend/src/lib/components/QueueSlider.svelte index 94430f0..d20003f 100644 --- a/frontend/src/lib/components/QueueSlider.svelte +++ b/frontend/src/lib/components/QueueSlider.svelte @@ -8,6 +8,10 @@ queueSongs[playingIndex], playingIndex == queueSongs.length - 1 ? createEmptySong() : queueSongs[playingIndex + 1], ]) + + $effect(() => { + console.log(displaySongs) + })
@@ -28,11 +32,7 @@ {/if}
{:else} -
- {#if i === 1} -

No song in queue

- {/if} -
+
{/if} {/each}
diff --git a/frontend/src/lib/components/SuggestionInput.svelte b/frontend/src/lib/components/SuggestionInput.svelte index 09982fd..9659e0d 100644 --- a/frontend/src/lib/components/SuggestionInput.svelte +++ b/frontend/src/lib/components/SuggestionInput.svelte @@ -4,15 +4,25 @@ let input = $state("") async function sendSong() { - let resp = await fetch(`/api/addsong?room=${roomId}&query=${input}`, { method: "POST" }) + await fetch(`/api/addsong?room=${roomId}&query=${input}`, { method: "POST" }) input = "" } -
- +
+ { + if (e.key == "Enter") { + sendSong() + } + }} + /> diff --git a/frontend/src/lib/types.ts b/frontend/src/lib/types.ts index 0c2e8f5..db04654 100644 --- a/frontend/src/lib/types.ts +++ b/frontend/src/lib/types.ts @@ -10,19 +10,19 @@ const SongSchema = z.object({ }) export type Song = z.infer -export const parseSong = async function(song: any): Promise { +export const parseSong = async function (song: any): Promise { let resp = await SongSchema.parseAsync(song) return resp } -export const createEmptySong = function(): Song { +export const createEmptySong = function (): Song { return { uuid: "-1", title: "", artist: "", tags: [""], image_id: "", - youtube_id: 0, + youtube_id: "", } } @@ -31,7 +31,7 @@ const SuggestionSchema = SongSchema.extend({ }) export type Suggestion = z.infer -export const parseSuggestion = async function(sugg: any): Promise { +export const parseSuggestion = async function (sugg: any): Promise { let resp = await SuggestionSchema.parseAsync(sugg) return resp } @@ -41,11 +41,11 @@ const RoomSchema = z.object({ name: z.string(), private: z.boolean(), coords: z.tuple([z.number(), z.number()]), - range: z.number().int() + range: z.number().int(), }) export type Room = z.infer -export const parseRoom = async function(room: any): Promise { +export const parseRoom = async function (room: any): Promise { let resp = await RoomSchema.parseAsync(room) return resp } diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts index 1b806c5..580b638 100644 --- a/frontend/src/lib/utils.ts +++ b/frontend/src/lib/utils.ts @@ -1,7 +1,7 @@ import { parseSong, parseSuggestion, type FetchError, type Song, type Suggestion } from "./types" -export const joinRoom = async function (roomId: string): Promise<[FetchError | null, string]> { - let resp = await fetch("/api/join?room=" + roomId) +export const joinRoom = async function (roomId: string, lat: number, lon: number): Promise<[FetchError | null, string]> { + let resp = await fetch(`/api/join?room=${roomId}&lat=${lat}&lon=${lon}`) if (resp.status != 200) { return [{ code: 400, message: "Cannot join the room" }, ""] diff --git a/frontend/src/routes/admin/[id]/+page.svelte b/frontend/src/routes/admin/[id]/+page.svelte index e017cc5..c579bed 100644 --- a/frontend/src/routes/admin/[id]/+page.svelte +++ b/frontend/src/routes/admin/[id]/+page.svelte @@ -19,7 +19,7 @@ let url = await getStreamingUrl(currentPlaying.uuid) if (audioController) { audioController.src = url - audioController.play() + await audioController.play() } } @@ -29,11 +29,10 @@ queueSongs = songs playingIndex = index + }) - if (audioController) { - audioController.src = await getStreamingUrl(currentPlaying.uuid) - audioController.play() - } + $effect(() => { + playOnEnd() }) async function playNext() { @@ -53,6 +52,6 @@
- +
{/if} diff --git a/frontend/src/routes/room/[id]/+page.svelte b/frontend/src/routes/room/[id]/+page.svelte index 6237b13..95acdf5 100644 --- a/frontend/src/routes/room/[id]/+page.svelte +++ b/frontend/src/routes/room/[id]/+page.svelte @@ -8,6 +8,8 @@ import { getQueueSongs, getSuggestions, joinRoom } from "$lib/utils.js" import type { FetchError } from "$lib/types.js" import { io, Socket } from "socket.io-client" + import { get_coords } from "$lib/gps.js" + import type { Coordinates } from "$lib/gps.js" let { data } = $props() @@ -23,8 +25,14 @@ onMount(async () => { // Join the room + let { coords, error } = await get_coords() + if (error || coords == null) { + // Default to Lido + coords = { latitude: 46.6769043, longitude: 11.1851585 } + } + let sugg, queue, index - ;[returnError] = await joinRoom(data.roomId) + ;[returnError] = await joinRoom(data.roomId, coords.latitude, coords.longitude) if (returnError) { return } @@ -69,7 +77,7 @@ {#if returnError} {:else} -
+
From 244e49d3115e3f798f030564145050fe1266722d Mon Sep 17 00:00:00 2001 From: Leonardo Segala Date: Sat, 2 Aug 2025 09:22:30 +0200 Subject: [PATCH 11/40] Fix coord float --- backend/src/app.py | 8 ++++---- backend/src/gps.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/src/app.py b/backend/src/app.py index a6e8e67..0331aa6 100644 --- a/backend/src/app.py +++ b/backend/src/app.py @@ -88,8 +88,8 @@ def join(): distance = distance_between_coords( lhs=room.coord, rhs=Coordinates( - latitude=int(request.args["lat"]), - longitude=int(request.args["lon"]), + latitude=float(request.args["lat"]), + longitude=float(request.args["lon"]), ), ) @@ -153,7 +153,7 @@ def room_new(): room = Room( id=max(state.rooms or [0]) + 1, - coord=Coordinates(int(lat), int(lon)), + coord=Coordinates(float(lat), float(lon)), range_size=int(room_range), name=room_name, pin=room_pin, @@ -175,7 +175,7 @@ def room(): lon = request.args.get("lon") if lat and lon: - user_coords = Coordinates(latitude=int(lat), longitude=int(lon)) + user_coords = Coordinates(latitude=float(lat), longitude=float(lon)) else: return error("Missing user coordinates") diff --git a/backend/src/gps.py b/backend/src/gps.py index 4232267..98bda0c 100644 --- a/backend/src/gps.py +++ b/backend/src/gps.py @@ -4,8 +4,8 @@ from dataclasses import dataclass @dataclass class Coordinates: - latitude: int - longitude: int + latitude: float + longitude: float def distance_between_coords(lhs: Coordinates, rhs: Coordinates) -> float: From fe7c7405738be1a5ce22f3267552f63187abdb65 Mon Sep 17 00:00:00 2001 From: Leonardo Segala Date: Sat, 2 Aug 2025 09:24:38 +0200 Subject: [PATCH 12/40] Fix lido scena coords --- backend/src/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/app.py b/backend/src/app.py index 0331aa6..559baf1 100644 --- a/backend/src/app.py +++ b/backend/src/app.py @@ -29,7 +29,7 @@ init_db(state.db) state.rooms[1000] = Room( id=1000, - coord=Coordinates(1, 5), + coord=Coordinates(46.6769043, 11.1851585), name="Test Room", pin=None, tags=set(), From 124e426b21121d1095d0e2705c59008b2e053c61 Mon Sep 17 00:00:00 2001 From: panzerotto Date: Sat, 2 Aug 2025 09:49:52 +0200 Subject: [PATCH 13/40] mod favicon --- frontend/static/favicon.ico | Bin 0 -> 15406 bytes frontend/static/favicon.svg | 1 - 2 files changed, 1 deletion(-) create mode 100644 frontend/static/favicon.ico delete mode 100644 frontend/static/favicon.svg diff --git a/frontend/static/favicon.ico b/frontend/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..f5208bbaad196c23ce627d638f580f3b3766e042 GIT binary patch literal 15406 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 \ No newline at end of file From 396c7b0cea1037b33114acd64179b9ee23b74696 Mon Sep 17 00:00:00 2001 From: panzerotto Date: Sat, 2 Aug 2025 09:53:18 +0200 Subject: [PATCH 14/40] fix microsmarcio icon --- frontend/src/app.html | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/frontend/src/app.html b/frontend/src/app.html index 7af2f6d..344c77b 100644 --- a/frontend/src/app.html +++ b/frontend/src/app.html @@ -1,15 +1,13 @@ + + + + + %sveltekit.head% + - - - - - %sveltekit.head% - - - -
%sveltekit.body%
- - + +
%sveltekit.body%
+ From 2a8802a0b8386178380fa984b7976e2bee148b87 Mon Sep 17 00:00:00 2001 From: Leonardo Segala Date: Sat, 2 Aug 2025 09:53:24 +0200 Subject: [PATCH 15/40] Add spinner --- frontend/src/lib/components/SuggestionInput.svelte | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/frontend/src/lib/components/SuggestionInput.svelte b/frontend/src/lib/components/SuggestionInput.svelte index 9659e0d..8bbd2ff 100644 --- a/frontend/src/lib/components/SuggestionInput.svelte +++ b/frontend/src/lib/components/SuggestionInput.svelte @@ -1,11 +1,15 @@ @@ -20,7 +24,14 @@ sendSong() } }} + {disabled} /> + {#if disabled} + + + + {/if} + Date: Sat, 2 Aug 2025 10:06:31 +0200 Subject: [PATCH 16/40] add room scanner logic --- backend/src/app.py | 19 ++++--- .../src/lib/components/RoomComponent.svelte | 7 +-- frontend/src/lib/types.ts | 7 +-- frontend/src/lib/utils.ts | 19 ++++--- frontend/src/routes/+page.svelte | 49 ++++++------------- 5 files changed, 45 insertions(+), 56 deletions(-) diff --git a/backend/src/app.py b/backend/src/app.py index 0331aa6..436d5d7 100644 --- a/backend/src/app.py +++ b/backend/src/app.py @@ -1,18 +1,17 @@ import uuid from dataclasses import asdict + import dotenv +from connect import get_connection from flask import Flask, Response, jsonify, request from flask_cors import CORS from flask_socketio import SocketIO, join_room, leave_room - -from state import State -from connect import get_connection -from room import Room -from song import Song, init_db, get_song_by_title_artist, add_song_in_db, get_song_by_uuid -from song_fetch import query_search, yt_get_audio_url, yt_search_song +from gps import Coordinates, distance_between_coords from qrcode_gen import generate_qr -from gps import is_within_range, distance_between_coords, Coordinates - +from room import Room +from song import Song, add_song_in_db, get_song_by_title_artist, get_song_by_uuid, init_db +from song_fetch import query_search, yt_get_audio_url, yt_search_song +from state import State dotenv.load_dotenv() @@ -29,11 +28,11 @@ init_db(state.db) state.rooms[1000] = Room( id=1000, - coord=Coordinates(1, 5), + coord=Coordinates(46.6769043, 11.1851585), name="Test Room", pin=None, tags=set(), - range_size=100, + range_size=150, songs={}, history=[], playing=[], diff --git a/frontend/src/lib/components/RoomComponent.svelte b/frontend/src/lib/components/RoomComponent.svelte index e98e000..4e742db 100644 --- a/frontend/src/lib/components/RoomComponent.svelte +++ b/frontend/src/lib/components/RoomComponent.svelte @@ -3,8 +3,9 @@ let { room }: { room: Room } = $props() - + diff --git a/frontend/src/lib/types.ts b/frontend/src/lib/types.ts index 0c2e8f5..c0d4155 100644 --- a/frontend/src/lib/types.ts +++ b/frontend/src/lib/types.ts @@ -37,11 +37,12 @@ export const parseSuggestion = async function(sugg: any): Promise { } const RoomSchema = z.object({ - id: z.string(), + id: z.number(), name: z.string(), private: z.boolean(), - coords: z.tuple([z.number(), z.number()]), - range: z.number().int() + coords: z.object({ latitude: z.number(), longitude: z.number() }), + range: z.number().int(), + distance: z.number() }) export type Room = z.infer diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts index 1b806c5..29fc5fc 100644 --- a/frontend/src/lib/utils.ts +++ b/frontend/src/lib/utils.ts @@ -1,16 +1,21 @@ +import { get_coords } from "./gps" import { parseSong, parseSuggestion, type FetchError, type Song, type Suggestion } from "./types" -export const joinRoom = async function (roomId: string): Promise<[FetchError | null, string]> { - let resp = await fetch("/api/join?room=" + roomId) +export const joinRoom = async function(roomId: string): Promise<[FetchError | null, string]> { + let { coords, error } = await get_coords() + if (error != null) return [{ code: 400, message: "Cannot join the room due to GPS error" }, ""] + if (coords == null) return [{ code: 400, message: "Cannot join the room due to GPS error" }, ""] - if (resp.status != 200) { + let res = await fetch(`/api/join?room=${roomId}&lat=${coords.latitude}&lon=${coords.longitude}`) + + if (res.status != 200) { return [{ code: 400, message: "Cannot join the room" }, ""] } return [null, "test"] } -export const getSuggestions = async function (roomId: string): Promise<[FetchError | null, Suggestion[]]> { +export const getSuggestions = async function(roomId: string): Promise<[FetchError | null, Suggestion[]]> { let resp = await fetch("/api/room/suggestions?room=" + roomId) if (resp.status != 200) { @@ -31,7 +36,7 @@ export const getSuggestions = async function (roomId: string): Promise<[FetchErr return [null, suggestions] } -export const getQueueSongs = async function (roomId: string): Promise<[FetchError | null, Song[], number]> { +export const getQueueSongs = async function(roomId: string): Promise<[FetchError | null, Song[], number]> { let resp = await fetch("/api/queue?room=" + roomId) if (resp.status != 200) { return [{ code: 400, message: "Failed to load queue songs" }, [], 0] @@ -49,7 +54,7 @@ export const getQueueSongs = async function (roomId: string): Promise<[FetchErro return [null, songs, playingId] } -export const triggerPlayNext = async function (roomId: string): Promise<[FetchError | null, Song[], number]> { +export const triggerPlayNext = async function(roomId: string): Promise<[FetchError | null, Song[], number]> { let resp = await fetch("/api/queue/next?room=" + roomId, { method: "POST" }) if (resp.status != 200) { @@ -66,7 +71,7 @@ export const triggerPlayNext = async function (roomId: string): Promise<[FetchEr return [null, songs, json["index"]] } -export const getStreamingUrl = async function (uuid: string) { +export const getStreamingUrl = async function(uuid: string) { let resp = await fetch("/api/song/audio?song=" + uuid) let json = await resp.json() diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index 319ce8d..c110c6a 100644 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -1,9 +1,21 @@
@@ -21,37 +33,8 @@
- - - - - - - - - - - - + {#each rooms as room} + + {/each}
- - - - - - - - - - - - - - - - - - - - From 69cf4626624fccb9eb18842c8066f1a1e69e9f28 Mon Sep 17 00:00:00 2001 From: Mat12143 Date: Sat, 2 Aug 2025 10:28:11 +0200 Subject: [PATCH 17/40] custom bar --- .../src/lib/components/QueueSlider.svelte | 2 +- .../src/lib/components/SuggestionInput.svelte | 5 ++- frontend/src/routes/admin/[id]/+page.svelte | 42 ++++++++++++++++++- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/frontend/src/lib/components/QueueSlider.svelte b/frontend/src/lib/components/QueueSlider.svelte index d20003f..adbaf45 100644 --- a/frontend/src/lib/components/QueueSlider.svelte +++ b/frontend/src/lib/components/QueueSlider.svelte @@ -28,7 +28,7 @@ Song cover
{#if i === 1} -

{song.title} - {song.artist}

+

{song.title} - {song.artist}

{/if}
{:else} diff --git a/frontend/src/lib/components/SuggestionInput.svelte b/frontend/src/lib/components/SuggestionInput.svelte index 9659e0d..91053d0 100644 --- a/frontend/src/lib/components/SuggestionInput.svelte +++ b/frontend/src/lib/components/SuggestionInput.svelte @@ -2,14 +2,17 @@ let { roomId } = $props() let input = $state("") + let disabled = $state(false) async function sendSong() { + disabled = true await fetch(`/api/addsong?room=${roomId}&query=${input}`, { method: "POST" }) input = "" + disabled = false } -
+
(queueSongs[playingIndex]) let audioController = $state() + let playerInfo = $state({ + playing: false, + currentTime: 0, + duration: 0, + }) + async function playOnEnd() { let url = await getStreamingUrl(currentPlaying.uuid) if (audioController) { @@ -23,6 +29,23 @@ } } + $effect(() => { + if (audioController) { + audioController.ontimeupdate = () => { + playerInfo.currentTime = audioController?.currentTime || 0 + } + audioController.onloadedmetadata = () => { + playerInfo.duration = audioController?.duration || 0 + } + audioController.onplay = () => { + playerInfo.playing = true + } + audioController.onpause = () => { + playerInfo.playing = false + } + } + }) + onMount(async () => { let songs, index ;[returnError, songs, index] = await getQueueSongs(data.roomId) @@ -35,6 +58,12 @@ playOnEnd() }) + const formatTime = (t: number) => { + const min = Math.floor(t / 60) + const sec = Math.floor(t % 60) + return `${min}:${sec.toString().padStart(2, "0")}` + } + async function playNext() { let songs, index ;[returnError, songs, index] = await triggerPlayNext(data.roomId) @@ -51,7 +80,16 @@ {:else}
- - + + + +
+

{formatTime(playerInfo.currentTime)} - {formatTime(playerInfo.duration)}

+ +
+ + +
+
{/if} From 5632209ace0999fd13ef6a8a80b245c3ec51c045 Mon Sep 17 00:00:00 2001 From: Mat12143 Date: Sat, 2 Aug 2025 10:31:29 +0200 Subject: [PATCH 18/40] feat: fallback for gps error --- frontend/src/routes/+page.svelte | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index c110c6a..29ee432 100644 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -9,8 +9,7 @@ onMount(async () => { let { coords, error } = await get_coords() - if (error != null) return console.log(error) - if (coords == null) return + if (error != null || coords == null) coords = { latitude: 46.6769043, longitude: 11.1851585 } let res = await fetch(`/api/room?lat=${coords.latitude}&lon=${coords.longitude}`) let json = await res.json() From 795a5a3a19a1740dcc0c47a6b1f459a2d7ebb9ac Mon Sep 17 00:00:00 2001 From: Mat12143 Date: Sat, 2 Aug 2025 10:32:51 +0200 Subject: [PATCH 19/40] feat: fallback for gps error --- frontend/src/lib/utils.ts | 16 ++++++---------- frontend/src/routes/room/[id]/+page.svelte | 2 +- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts index 29fc5fc..6450247 100644 --- a/frontend/src/lib/utils.ts +++ b/frontend/src/lib/utils.ts @@ -1,11 +1,7 @@ -import { get_coords } from "./gps" +import { get_coords, type Coordinates } from "./gps" import { parseSong, parseSuggestion, type FetchError, type Song, type Suggestion } from "./types" -export const joinRoom = async function(roomId: string): Promise<[FetchError | null, string]> { - let { coords, error } = await get_coords() - if (error != null) return [{ code: 400, message: "Cannot join the room due to GPS error" }, ""] - if (coords == null) return [{ code: 400, message: "Cannot join the room due to GPS error" }, ""] - +export const joinRoom = async function (roomId: string, coords: Coordinates): Promise<[FetchError | null, string]> { let res = await fetch(`/api/join?room=${roomId}&lat=${coords.latitude}&lon=${coords.longitude}`) if (res.status != 200) { @@ -15,7 +11,7 @@ export const joinRoom = async function(roomId: string): Promise<[FetchError | nu return [null, "test"] } -export const getSuggestions = async function(roomId: string): Promise<[FetchError | null, Suggestion[]]> { +export const getSuggestions = async function (roomId: string): Promise<[FetchError | null, Suggestion[]]> { let resp = await fetch("/api/room/suggestions?room=" + roomId) if (resp.status != 200) { @@ -36,7 +32,7 @@ export const getSuggestions = async function(roomId: string): Promise<[FetchErro return [null, suggestions] } -export const getQueueSongs = async function(roomId: string): Promise<[FetchError | null, Song[], number]> { +export const getQueueSongs = async function (roomId: string): Promise<[FetchError | null, Song[], number]> { let resp = await fetch("/api/queue?room=" + roomId) if (resp.status != 200) { return [{ code: 400, message: "Failed to load queue songs" }, [], 0] @@ -54,7 +50,7 @@ export const getQueueSongs = async function(roomId: string): Promise<[FetchError return [null, songs, playingId] } -export const triggerPlayNext = async function(roomId: string): Promise<[FetchError | null, Song[], number]> { +export const triggerPlayNext = async function (roomId: string): Promise<[FetchError | null, Song[], number]> { let resp = await fetch("/api/queue/next?room=" + roomId, { method: "POST" }) if (resp.status != 200) { @@ -71,7 +67,7 @@ export const triggerPlayNext = async function(roomId: string): Promise<[FetchErr return [null, songs, json["index"]] } -export const getStreamingUrl = async function(uuid: string) { +export const getStreamingUrl = async function (uuid: string) { let resp = await fetch("/api/song/audio?song=" + uuid) let json = await resp.json() diff --git a/frontend/src/routes/room/[id]/+page.svelte b/frontend/src/routes/room/[id]/+page.svelte index 95acdf5..839d5a7 100644 --- a/frontend/src/routes/room/[id]/+page.svelte +++ b/frontend/src/routes/room/[id]/+page.svelte @@ -32,7 +32,7 @@ } let sugg, queue, index - ;[returnError] = await joinRoom(data.roomId, coords.latitude, coords.longitude) + ;[returnError] = await joinRoom(data.roomId, coords) if (returnError) { return } From a7374d6d94a521f8df4b5d87c3f1fb2f8ecaa779 Mon Sep 17 00:00:00 2001 From: Simone Tesini Date: Sat, 2 Aug 2025 10:47:49 +0200 Subject: [PATCH 20/40] add tag filtre --- backend/src/app.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/backend/src/app.py b/backend/src/app.py index 436d5d7..ac1dfaa 100644 --- a/backend/src/app.py +++ b/backend/src/app.py @@ -222,6 +222,15 @@ def add_song(): add_song_in_db(song) + if len(room.tags) > 0: + tag_ok = False + for tag in song.tags: + if tag in room.tags: + tag_ok = True + + if not tag_ok: + return error("Song genre does not belong to this room") + ## add the song in the room if does not exists if song.uuid not in room.songs: room.songs[song.uuid] = (song, 1) # start with one vote From 3ee764ad03c4913a14c504936cd8fa4a47f4a57a Mon Sep 17 00:00:00 2001 From: Mat12143 Date: Sat, 2 Aug 2025 10:50:35 +0200 Subject: [PATCH 21/40] feat: recolor ui --- .../src/lib/components/SuggestionInput.svelte | 9 +++++---- .../src/lib/components/SuggestionList.svelte | 20 ++++++++++--------- frontend/src/routes/admin/[id]/+page.svelte | 4 ++-- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/frontend/src/lib/components/SuggestionInput.svelte b/frontend/src/lib/components/SuggestionInput.svelte index 4e28cb7..8cc5a9a 100644 --- a/frontend/src/lib/components/SuggestionInput.svelte +++ b/frontend/src/lib/components/SuggestionInput.svelte @@ -13,7 +13,9 @@ } -
+
{/if} - Add
diff --git a/frontend/src/lib/components/SuggestionList.svelte b/frontend/src/lib/components/SuggestionList.svelte index ffc25d6..12f69ed 100644 --- a/frontend/src/lib/components/SuggestionList.svelte +++ b/frontend/src/lib/components/SuggestionList.svelte @@ -12,14 +12,16 @@
{#if suggestions.length == 0} -

No suggestions yet! Try to add a new one using the Add button

+

No suggestions yet! Try to add a new one using the Add button

{/if} {#each suggestions as sug, idx} -
-
+
+
Song cover -
+
{sug.title}

{sug.artist}

@@ -27,15 +29,15 @@

{sug.upvote}

diff --git a/frontend/src/routes/admin/[id]/+page.svelte b/frontend/src/routes/admin/[id]/+page.svelte index a246853..a55e6f8 100644 --- a/frontend/src/routes/admin/[id]/+page.svelte +++ b/frontend/src/routes/admin/[id]/+page.svelte @@ -87,8 +87,8 @@

{formatTime(playerInfo.currentTime)} - {formatTime(playerInfo.duration)}

- - + +
From cd9d47ad8d952a27ec593a2d276e4bfe8d07a5fe Mon Sep 17 00:00:00 2001 From: Simone Tesini Date: Sat, 2 Aug 2025 11:00:02 +0200 Subject: [PATCH 22/40] fix baco --- backend/src/song_fetch.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/backend/src/song_fetch.py b/backend/src/song_fetch.py index 665e2c9..f8cb78f 100644 --- a/backend/src/song_fetch.py +++ b/backend/src/song_fetch.py @@ -1,10 +1,11 @@ -import requests -import urllib.parse -import os.path import os +import os.path import sys +import urllib.parse from dataclasses import dataclass +import requests + sys.path.append("/yt-dlp") import yt_dlp @@ -42,11 +43,16 @@ def _lastfm_getinfo(name: str, artist: str) -> tuple[str, list[str]]: # ( image track_info = response.json()["track"] - image_url = urllib.parse.urlparse(track_info["album"]["image"][0]["#text"]) + image_id = "" + if "album" in track_info: + image_url = urllib.parse.urlparse(track_info["album"]["image"][0]["#text"]) + image_id = os.path.splitext(os.path.basename(image_url.path))[0] + else: + print("this song haas no image", flush=True) return ( # track_info["mbid"], - os.path.splitext(os.path.basename(image_url.path))[0], + image_id, [t["name"] for t in track_info["toptags"]["tag"]], ) From ec36ea3feba453c36863a9e98f76a2ed359dd874 Mon Sep 17 00:00:00 2001 From: Mat12143 Date: Sat, 2 Aug 2025 11:19:09 +0200 Subject: [PATCH 23/40] fix: pause & unpause + timeline bar + stock image as not found --- frontend/src/lib/components/QueueSlider.svelte | 8 +++++++- .../src/lib/components/SuggestionList.svelte | 8 +++++++- frontend/src/routes/admin/[id]/+page.svelte | 16 ++++++++++++++-- 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/frontend/src/lib/components/QueueSlider.svelte b/frontend/src/lib/components/QueueSlider.svelte index adbaf45..5df1e8d 100644 --- a/frontend/src/lib/components/QueueSlider.svelte +++ b/frontend/src/lib/components/QueueSlider.svelte @@ -25,7 +25,13 @@ {#if i === 1}
{/if} - Song cover + Song cover
{#if i === 1}

{song.title} - {song.artist}

diff --git a/frontend/src/lib/components/SuggestionList.svelte b/frontend/src/lib/components/SuggestionList.svelte index 12f69ed..2494254 100644 --- a/frontend/src/lib/components/SuggestionList.svelte +++ b/frontend/src/lib/components/SuggestionList.svelte @@ -20,7 +20,13 @@ class="flex h-[80px] w-full flex-row gap-2 rounded-md border-dark-pine-muted bg-light-pine-overlay p-2 shadow-md duration-100 hover:bg-dark-pine-base/20 dark:bg-dark-pine-overlay hover:dark:bg-light-pine-base/20" >
- Song cover + Song cover
{sug.title}

{sug.artist}

diff --git a/frontend/src/routes/admin/[id]/+page.svelte b/frontend/src/routes/admin/[id]/+page.svelte index a55e6f8..7041413 100644 --- a/frontend/src/routes/admin/[id]/+page.svelte +++ b/frontend/src/routes/admin/[id]/+page.svelte @@ -73,6 +73,15 @@ queueSongs = songs playingIndex = index } + + function seek(e: Event) { + const target = e.target as HTMLInputElement + const seekTime = parseFloat(target.value) + playerInfo.currentTime = seekTime + if (audioController) { + audioController.currentTime = seekTime + } + } {#if returnError} @@ -85,9 +94,12 @@

{formatTime(playerInfo.currentTime)} - {formatTime(playerInfo.duration)}

- +
- +
From 7e52746b376573b32733084522a2292fff76cbf1 Mon Sep 17 00:00:00 2001 From: Mat12143 Date: Sat, 2 Aug 2025 11:25:53 +0200 Subject: [PATCH 24/40] fix: media bar on mobile --- frontend/src/routes/admin/[id]/+page.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/routes/admin/[id]/+page.svelte b/frontend/src/routes/admin/[id]/+page.svelte index 7041413..959e1be 100644 --- a/frontend/src/routes/admin/[id]/+page.svelte +++ b/frontend/src/routes/admin/[id]/+page.svelte @@ -92,7 +92,7 @@ -
+

{formatTime(playerInfo.currentTime)} - {formatTime(playerInfo.duration)}

From cbf90d1d0a01ce2ee8728d6f0c89f7d30c8bd37a Mon Sep 17 00:00:00 2001 From: Simone Tesini Date: Sat, 2 Aug 2025 11:26:07 +0200 Subject: [PATCH 25/40] fix micro smarcio --- backend/src/app.py | 3 +++ backend/src/song_fetch.py | 17 +++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/backend/src/app.py b/backend/src/app.py index ac1dfaa..0fc9f9d 100644 --- a/backend/src/app.py +++ b/backend/src/app.py @@ -210,6 +210,9 @@ def add_song(): ## song not found, downolad from YT yt_video_id = yt_search_song(info.title, info.artist) + if yt_video_id is None: + return error("No video found on youtube") + ## add in DB song = Song( uuid=str(uuid.uuid4()), diff --git a/backend/src/song_fetch.py b/backend/src/song_fetch.py index f8cb78f..905d126 100644 --- a/backend/src/song_fetch.py +++ b/backend/src/song_fetch.py @@ -18,7 +18,7 @@ class SongInfo: tags: list[str] -def _lastfm_search(query: str) -> tuple[str, str]: +def _lastfm_search(query: str) -> tuple[str, str] | None: response = requests.get( url="https://ws.audioscrobbler.com/2.0/?method=track.search&format=json", params={"limit": 5, "track": query, "api_key": os.environ["LASTFM_API_KEY"]}, @@ -26,7 +26,10 @@ def _lastfm_search(query: str) -> tuple[str, str]: assert response.status_code == 200 - track_info = response.json()["results"]["trackmatches"]["track"][0] + tracks = response.json()["results"]["trackmatches"]["track"] + if len(tracks) == 0: + return None + track_info = tracks[0] return track_info["name"], track_info["artist"] @@ -74,14 +77,17 @@ def _yt_search(query: str) -> tuple[str, str]: def query_search(query: str) -> SongInfo | None: - name, artist = _lastfm_search(query) + res = _lastfm_search(query) + if res is None: + return None + name, artist = res img_id, tags = _lastfm_getinfo(name, artist) return SongInfo(artist=artist, title=name, img_id=img_id, tags=tags) -def yt_search_song(name: str, artist: str) -> str: # video id +def yt_search_song(name: str, artist: str) -> str | None: # video id ydl_opts = { "format": "bestaudio", "default_search": "ytsearch1", @@ -92,6 +98,9 @@ def yt_search_song(name: str, artist: str) -> str: # video id with yt_dlp.YoutubeDL(ydl_opts) as ydl: info = ydl.extract_info(f"{name!r} - {artist!r}", download=False) + if len(info["entries"]) == 0: + return None + return info["entries"][0]["id"] From 2a63a527f0a95e39902fb24412c296825f7d218d Mon Sep 17 00:00:00 2001 From: Leonardo Segala Date: Sat, 2 Aug 2025 11:47:26 +0200 Subject: [PATCH 26/40] Add room creation page --- frontend/src/routes/+page.svelte | 7 +- frontend/src/routes/room/create/+page.svelte | 92 ++++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 frontend/src/routes/room/create/+page.svelte diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index 29ee432..e8fb789 100644 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -26,7 +26,12 @@ radar Scanning for rooms near you... - diff --git a/frontend/src/routes/room/create/+page.svelte b/frontend/src/routes/room/create/+page.svelte new file mode 100644 index 0000000..c69b19e --- /dev/null +++ b/frontend/src/routes/room/create/+page.svelte @@ -0,0 +1,92 @@ + + +
+

Create Room

+ +
+ + + + +

+ Room Coordinates: + {coord.latitude},{coord.longitude} +

+ +
+ Public Room: + + {#if !privateRoom} +

The room is flagged as public, everyone can join

+ {/if} +
+ + +
+
From 350f44b19485e1ac660024dc87ab2078ea64d92e Mon Sep 17 00:00:00 2001 From: Mat12143 Date: Sat, 2 Aug 2025 11:49:49 +0200 Subject: [PATCH 27/40] feat: stop on next song + start on empty queue --- frontend/src/routes/admin/[id]/+page.svelte | 9 +++++++++ frontend/src/routes/room/[id]/+page.svelte | 1 - frontend/src/routes/room/[id]/+page.ts | 12 +++--------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/frontend/src/routes/admin/[id]/+page.svelte b/frontend/src/routes/admin/[id]/+page.svelte index 959e1be..07d6f0e 100644 --- a/frontend/src/routes/admin/[id]/+page.svelte +++ b/frontend/src/routes/admin/[id]/+page.svelte @@ -52,6 +52,10 @@ queueSongs = songs playingIndex = index + + if (queueSongs.length == 0) { + playNext() + } }) $effect(() => { @@ -72,6 +76,11 @@ queueSongs = songs playingIndex = index + + if (audioController) { + audioController.pause() + audioController.currentTime = 0 + } } function seek(e: Event) { diff --git a/frontend/src/routes/room/[id]/+page.svelte b/frontend/src/routes/room/[id]/+page.svelte index 839d5a7..76984f3 100644 --- a/frontend/src/routes/room/[id]/+page.svelte +++ b/frontend/src/routes/room/[id]/+page.svelte @@ -9,7 +9,6 @@ import type { FetchError } from "$lib/types.js" import { io, Socket } from "socket.io-client" import { get_coords } from "$lib/gps.js" - import type { Coordinates } from "$lib/gps.js" let { data } = $props() diff --git a/frontend/src/routes/room/[id]/+page.ts b/frontend/src/routes/room/[id]/+page.ts index 969ffc5..1f9f77d 100644 --- a/frontend/src/routes/room/[id]/+page.ts +++ b/frontend/src/routes/room/[id]/+page.ts @@ -1,13 +1,7 @@ -import { error, type Load, type ServerLoad } from "@sveltejs/kit" import type { PageLoad } from "./$types" -import type { FetchError } from "$lib/util" -import { parseSuggestion, type Suggestion } from "$lib/types" -export const load: PageLoad = async ({ params }) => { - if (params.id) { - return { - roomId: params.id, - } +export const load: PageLoad = ({ params, url }) => { + return { + roomId: params.id || "", } - error(400, "Please provide a room id") } From ba2b5f04c67f141a4fbade5908598e52c7f4cc83 Mon Sep 17 00:00:00 2001 From: Simone Tesini Date: Sat, 2 Aug 2025 11:51:51 +0200 Subject: [PATCH 28/40] anti vote spam system --- .../src/lib/components/SuggestionList.svelte | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/frontend/src/lib/components/SuggestionList.svelte b/frontend/src/lib/components/SuggestionList.svelte index 2494254..6f5d649 100644 --- a/frontend/src/lib/components/SuggestionList.svelte +++ b/frontend/src/lib/components/SuggestionList.svelte @@ -1,13 +1,24 @@
@@ -34,14 +45,16 @@
-

{sug.upvote}

+

{sug.upvote}

Date: Sat, 2 Aug 2025 12:34:27 +0200 Subject: [PATCH 29/40] Fix room creation href --- frontend/src/routes/+page.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index e8fb789..6299c75 100644 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -28,7 +28,7 @@

{sug.upvote}

@@ -56,7 +56,8 @@ class={!picked_suggestions.includes(sug.uuid) ? "text-light-pine-red duration-100 hover:scale-150 dark:text-dark-pine-red" : "text-light-pine-muted dark:text-dark-pine-muted"} disabled={!!picked_suggestions.includes(sug.uuid)} onclick={async () => { - await vote(idx, -1, sug.uuid) + sug.upvode += 1 + await vote(-1, sug.uuid) }}>
From efcabd2ee4d8894cac208b1203d5386392e2a709 Mon Sep 17 00:00:00 2001 From: Simone Tesini Date: Sat, 2 Aug 2025 12:51:50 +0200 Subject: [PATCH 32/40] add song cooldonw --- .../src/lib/components/SuggestionInput.svelte | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/frontend/src/lib/components/SuggestionInput.svelte b/frontend/src/lib/components/SuggestionInput.svelte index 8cc5a9a..d23b878 100644 --- a/frontend/src/lib/components/SuggestionInput.svelte +++ b/frontend/src/lib/components/SuggestionInput.svelte @@ -1,20 +1,33 @@
- {#if disabled} + {#if loading} {/if} - Add
From 1063c239b6c0aa9e22d99a749704ebe645af94c0 Mon Sep 17 00:00:00 2001 From: Mat12143 Date: Sat, 2 Aug 2025 13:00:11 +0200 Subject: [PATCH 33/40] feat: block access for pin protected rooms --- frontend/src/lib/utils.ts | 6 +++--- frontend/src/routes/room/[id]/+page.svelte | 2 +- frontend/src/routes/room/[id]/+page.ts | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts index 6450247..470da85 100644 --- a/frontend/src/lib/utils.ts +++ b/frontend/src/lib/utils.ts @@ -1,8 +1,8 @@ -import { get_coords, type Coordinates } from "./gps" +import { type Coordinates } from "./gps" import { parseSong, parseSuggestion, type FetchError, type Song, type Suggestion } from "./types" -export const joinRoom = async function (roomId: string, coords: Coordinates): Promise<[FetchError | null, string]> { - let res = await fetch(`/api/join?room=${roomId}&lat=${coords.latitude}&lon=${coords.longitude}`) +export const joinRoom = async function (roomId: string, coords: Coordinates, pin: string): Promise<[FetchError | null, string]> { + let res = await fetch(`/api/join?room=${roomId}&lat=${coords.latitude}&lon=${coords.longitude}&pin=${pin}`) if (res.status != 200) { return [{ code: 400, message: "Cannot join the room" }, ""] diff --git a/frontend/src/routes/room/[id]/+page.svelte b/frontend/src/routes/room/[id]/+page.svelte index 76984f3..84d8d67 100644 --- a/frontend/src/routes/room/[id]/+page.svelte +++ b/frontend/src/routes/room/[id]/+page.svelte @@ -31,7 +31,7 @@ } let sugg, queue, index - ;[returnError] = await joinRoom(data.roomId, coords) + ;[returnError] = await joinRoom(data.roomId, coords, data.pin) if (returnError) { return } diff --git a/frontend/src/routes/room/[id]/+page.ts b/frontend/src/routes/room/[id]/+page.ts index 1f9f77d..f3bea98 100644 --- a/frontend/src/routes/room/[id]/+page.ts +++ b/frontend/src/routes/room/[id]/+page.ts @@ -3,5 +3,6 @@ import type { PageLoad } from "./$types" export const load: PageLoad = ({ params, url }) => { return { roomId: params.id || "", + pin: url.searchParams.get("pin") || "", } } From 278a2d94a851efee1e3ee52d08da1c1567659a35 Mon Sep 17 00:00:00 2001 From: Leonardo Segala Date: Sat, 2 Aug 2025 13:10:51 +0200 Subject: [PATCH 34/40] Add custom code insertion during room creation --- frontend/src/routes/room/create/+page.svelte | 43 ++++++++------------ 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/frontend/src/routes/room/create/+page.svelte b/frontend/src/routes/room/create/+page.svelte index c69b19e..d0009f3 100644 --- a/frontend/src/routes/room/create/+page.svelte +++ b/frontend/src/routes/room/create/+page.svelte @@ -9,9 +9,7 @@ let name: string = $state() let range: number = $state() - - const privateStyle = "bg-red-500" - const publicStyle = "bg-green-500" + let pin: number = $state() async function createRoom() { if (creating) { @@ -22,16 +20,12 @@ return } - let pin - if (privateRoom) { - pin = Math.floor(Math.random() * 10000) - } else { - pin = "" - } - creating = true - const res = await fetch(`/api/room/new?name=${encodeURIComponent(name)}&coords=${coord.latitude},${coord.longitude}&range=${encodeURIComponent(range ?? "100")}&pin=${pin}`, { method: "POST" }) + const res = await fetch( + `/api/room/new?name=${encodeURIComponent(name)}&coords=${coord.latitude},${coord.longitude}&range=${encodeURIComponent(range ?? "100")}&pin=${encodeURIComponent(pin ?? "")}`, + { method: "POST" } + ) const json = await res.json() @@ -50,8 +44,10 @@
{coord.latitude},{coord.longitude}

-
- Public Room: - - {#if !privateRoom} -

The room is flagged as public, everyone can join

- {/if} -
+ @@ -56,7 +55,6 @@ class={!picked_suggestions.includes(sug.uuid) ? "text-light-pine-red duration-100 hover:scale-150 dark:text-dark-pine-red" : "text-light-pine-muted dark:text-dark-pine-muted"} disabled={!!picked_suggestions.includes(sug.uuid)} onclick={async () => { - sug.upvode += 1 await vote(-1, sug.uuid) }}> diff --git a/frontend/src/routes/admin/[id]/+page.svelte b/frontend/src/routes/admin/[id]/+page.svelte index 07d6f0e..02f5f08 100644 --- a/frontend/src/routes/admin/[id]/+page.svelte +++ b/frontend/src/routes/admin/[id]/+page.svelte @@ -112,5 +112,7 @@
+ +
{/if} From 1763a6b96f891c9578711c49b660b803cff37d3c Mon Sep 17 00:00:00 2001 From: Simone Tesini Date: Sat, 2 Aug 2025 13:19:46 +0200 Subject: [PATCH 36/40] add readme --- README.md | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 65f5fc8..84edd62 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,40 @@ -# team-1 +# ChillBox -Test +> *A project by Pausetta.org, Simone Tesini, Francesco De Carlo, Leonardo Segala, Matteo Peretto* + +**ChillBox** is a web app that lets you create a shared radio station with a democratic voting system, so everyone gets to enjoy their favorite music together. +Perfect for venues like swimming pools, cafΓ©s, or even lively parties. + +--- + +## 🎡 Voting System + +Joining a ChillBox room is easy: users can either scan the QR code displayed on the host screen or use GPS to find nearby rooms. +Hosts can set a location range, ensuring only people physically present can add or vote for songs. + +--- + +## πŸ“Š Ranking Algorithm + +ChillBox uses a smart ranking algorithm to decide what plays next. The score of each song is based on: + +* Votes from users +* How recently similar songs (same genre or artist) have been played (less = better) +* A bit of randomness to keep things interesting +* A strong penalty for songs played too recently + +--- + +## πŸ‘ Hands-Off Experience + +ChillBox is designed to be almost entirely hands-free. +Once the host sets up a room and optionally connects a screen or projector +(to show the current track, QR code, etc.), ChillBox takes care of the rest. + +ChillBox comes with built-in automatic moderation to keep the music fair and on-theme. + +* Users can’t vote for the same song multiple times. +* A cooldown prevents users from spamming song requests. +* Hosts can define preferred genres and overall mood, so no one can hijack your chill beach vibes with unexpected death metal. + +That said, hosts still have access to essential controls, like pause and skip, if needed. From 9a12f39f3e2fa046d4c11d52e9dcb855bbe13848 Mon Sep 17 00:00:00 2001 From: Simone Tesini Date: Sat, 2 Aug 2025 13:22:52 +0200 Subject: [PATCH 37/40] remove words --- frontend/src/routes/+page.svelte | 2 +- frontend/static/{smerdoradar.gif => radar.gif} | Bin .../{smerdo_radar_bonus.gif => radar_bonus.gif} | Bin 3 files changed, 1 insertion(+), 1 deletion(-) rename frontend/static/{smerdoradar.gif => radar.gif} (100%) rename frontend/static/{smerdo_radar_bonus.gif => radar_bonus.gif} (100%) diff --git a/frontend/src/routes/+page.svelte b/frontend/src/routes/+page.svelte index 6299c75..b0b35bf 100644 --- a/frontend/src/routes/+page.svelte +++ b/frontend/src/routes/+page.svelte @@ -23,7 +23,7 @@ ChillBox
- radar + radar Scanning for rooms near you... + {#if showPinModal} + + + {/if} +
From f7351aecf805cef9107a4d3efc410f25dfc556fa Mon Sep 17 00:00:00 2001 From: Leonardo Segala Date: Sat, 2 Aug 2025 13:41:53 +0200 Subject: [PATCH 39/40] Add default room for testing && show error msg --- backend/src/app.py | 6 +++--- frontend/src/lib/components/SuggestionInput.svelte | 13 ++++++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/backend/src/app.py b/backend/src/app.py index aa9d4ee..28c66e9 100644 --- a/backend/src/app.py +++ b/backend/src/app.py @@ -29,9 +29,9 @@ init_db(state.db) state.rooms[1000] = Room( id=1000, coord=Coordinates(46.6769043, 11.1851585), - name="Test Room", - pin=None, - tags=set(), + name="Lido Scena", + pin=1234, + tags=set(["chill", "raggaetton", "spanish", "latino", "mexican", "rock"]), range_size=150, songs={}, history=[], diff --git a/frontend/src/lib/components/SuggestionInput.svelte b/frontend/src/lib/components/SuggestionInput.svelte index d23b878..53a3b34 100644 --- a/frontend/src/lib/components/SuggestionInput.svelte +++ b/frontend/src/lib/components/SuggestionInput.svelte @@ -7,6 +7,7 @@ let input = $state("") let loading: boolean = $state(false) let cooldowned: boolean = $state(false) + let errorMsg: string = $state() $effect(() => { console.log("cooldowned is now", cooldowned) @@ -14,10 +15,15 @@ async function sendSong() { loading = true - await fetch(`/api/addsong?room=${roomId}&query=${input}`, { method: "POST" }) + const res = await fetch(`/api/addsong?room=${roomId}&query=${input}`, { method: "POST" }) + const json = await res.json() input = "" loading = false + if (!json.success) { + errorMsg = json.error + } + cooldowned = true setTimeout(() => { cooldowned = false @@ -35,6 +41,7 @@ class="h-[50px] w-3/4 rounded px-4 font-bold text-white outline-none" bind:value={input} onkeydown={(e) => { + errorMsg = null if (e.key == "Enter") { sendSong() } @@ -56,3 +63,7 @@ >
+ +

+ {errorMsg} +

From bf71a8103dfab8535bdc0ab562ac8e45db4bec67 Mon Sep 17 00:00:00 2001 From: Simone Tesini Date: Sat, 2 Aug 2025 13:45:27 +0200 Subject: [PATCH 40/40] rush --- SPEECH.md | 15 +++++++++++++++ .../src/lib/components/SuggestionInput.svelte | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 SPEECH.md diff --git a/SPEECH.md b/SPEECH.md new file mode 100644 index 0000000..2ab507f --- /dev/null +++ b/SPEECH.md @@ -0,0 +1,15 @@ +# speech + +## Home screen +We start here in the home page. +We can see this little radar animation, which means that the app is looking for nearby ChillBox rooms to join. +It uses GPS for this feature. + +## Join room +When we join a room, the server checks our location and checks if it's within a specified range. +That way, you must physically be in the location to actually be able to add new songs + +## Talk about the host +As you can see here (and hear) on the left, the host is already playing some music. +Now i will add a song on the client side and it will pop up in the list. + diff --git a/frontend/src/lib/components/SuggestionInput.svelte b/frontend/src/lib/components/SuggestionInput.svelte index d23b878..4e75d3c 100644 --- a/frontend/src/lib/components/SuggestionInput.svelte +++ b/frontend/src/lib/components/SuggestionInput.svelte @@ -1,7 +1,7 @@