From c23cb63817c0b30417418fcff95899ef164d64bf Mon Sep 17 00:00:00 2001 From: Mark Hoekveen Date: Wed, 20 Aug 2025 21:51:51 +0200 Subject: [PATCH] game on --- backend/voting/consumers.py | 17 +++++-- frontend/src/app/lobby/page.tsx | 90 ++++++++++++++++++++++++++------- 2 files changed, 86 insertions(+), 21 deletions(-) diff --git a/backend/voting/consumers.py b/backend/voting/consumers.py index ae98505..2f0a38f 100644 --- a/backend/voting/consumers.py +++ b/backend/voting/consumers.py @@ -83,15 +83,24 @@ class SessionConsumer(WebsocketConsumer): for track in tracks: if next: session.current_track = track + next = False break if session.current_track == track: next = True + if next: + # We didnt get a next track, so it must have been the last one + session.current_track = None else: session.current_track = tracks.first() session.save() - async_to_sync(self.channel_layer.group_send)( - self.session_name, {"type": "announce.track"} - ) + if session.current_track is None: + async_to_sync(self.channel_layer.group_send)( + self.session_name, {"type": "announce.done"} + ) + else: + async_to_sync(self.channel_layer.group_send)( + self.session_name, {"type": "announce.track"} + ) def announce(self, event): @@ -100,6 +109,8 @@ class SessionConsumer(WebsocketConsumer): def announce_track(self, event): self.send(text_data=json.dumps({"track": {}})) + def announce_done(self, event): + self.send(text_data=json.dumps({"done": {}})) def voted(self, event): user = event["user"] diff --git a/frontend/src/app/lobby/page.tsx b/frontend/src/app/lobby/page.tsx index 2b1e506..ed911d5 100644 --- a/frontend/src/app/lobby/page.tsx +++ b/frontend/src/app/lobby/page.tsx @@ -1,6 +1,7 @@ "use client"; import { useState, useEffect } from "react"; import { Markazi_Text, Nunito } from "next/font/google"; +import { useRouter } from "next/navigation"; import Image from "next/image"; import Link from "next/link"; import { useAuth } from "react-oidc-context"; @@ -28,8 +29,12 @@ export default function Lobby() { const [spotifyId, setSpotifyId] = useState(null); const auth = useAuth(); const user = getUser(); + const router = useRouter(); const controller = useSpotifyIframe(); const [revealed, setRevealed] = useState(false); + const [playingPercentage, setPlayingPercentage] = useState(0); + const [secondsLeft, setSecondsLeft] = useState(30); + const [state, setState] = useState("lobby"); // lobby, playing, waiting, loading // Main message handler and dispatcher function onMessage(e) { @@ -42,6 +47,8 @@ export default function Lobby() { getTrack(); } else if (key == "voted") { voteUser(data[key]); + } else if (key == "done") { + router.push("/post-game"); } } console.log(data); @@ -78,6 +85,7 @@ export default function Lobby() { function startSession() { setSessionState("voting"); + setState("loading"); getTrack(); } @@ -152,6 +160,7 @@ export default function Lobby() { async function getTrack() { setSongLoading(true); + setState("loading"); setUserList((prevUserList) => { return prevUserList.map((user) => { return { ...user, hidden: false }; @@ -174,6 +183,9 @@ export default function Lobby() { } async function nextTrack() { + console.log("nextTrack"); + setState("loading"); + setRevealed(false); setSongLoading(true); sessionSocket.send( JSON.stringify({ @@ -183,19 +195,64 @@ export default function Lobby() { ); } + async function endPlay() { + controller?.seek(100); + } + // Spotify Player stuff useEffect(() => { if (controller) { console.log("Loaded track:", spotifyId); controller.loadUri(`spotify:track:${spotifyId}`); controller.play(); + // Note: do not set playing state here, but later when its actually playing. + console.log(controller._listeners); + if (controller._listeners["playback_update"].length === 0) { + controller.addListener("playback_update", (e) => { + updatePlayback(e); + }); + } } else { console.log("Spotify player not initialized"); } }, [controller, spotifyId]); + function updatePlayback(e) { + let duration = e.data.duration; + let playingPosition = e.data.position; + const playingSeconds = Math.floor((duration - playingPosition) / 1000); + setPlayingPercentage((playingPosition / duration) * 100); + setSecondsLeft((s) => { + setState((state) => { + if (playingSeconds >= 1) { + return "playing"; + } + if (state == "playing" && s <= 0) { + console.log("track ended"); + return "waiting"; + } + return state; + }); + return playingSeconds; + }); + } async function playTrack() { controller.play(); } + async function pauseTrack() { + controller.togglePlay(); + } + + useEffect(() => { + console.log("useEffect state:", state); + if (state == "waiting") { + setRevealed(true); + setTimeout(() => { + setState("next"); + }, 5000); + } else if (state == "next") { + nextTrack(); + } + }, [state]); if (sessionState == "lobby") { return ( @@ -218,7 +275,8 @@ export default function Lobby() { @@ -265,21 +323,17 @@ export default function Lobby() { return (
-
- {" "} - -
+
-
-
- + {(state == "playing" || state == "waiting") && ( +
+
+ {secondsLeft} +
-
+ )}
@@ -289,15 +343,15 @@ export default function Lobby() { > PLAY - PAUSE - + -- 2.52.0