diff --git a/README.md b/README.md deleted file mode 100644 index e469917..0000000 --- a/README.md +++ /dev/null @@ -1,11 +0,0 @@ -1. Limit manuell einstellbar ✔️ -2. Keine doppelten Songs ✔ ️ -3. songs die schon gespielt wurden nicht mehr spielen -4. songs die schon gespielt wurden nicht mehr in der Liste anzeigen -5. songs die schon gespielt wurden in einer extra Liste anzeigen -6. Um so frischer ein Song gehört worden ist desto eher soll er abgespielt werden -7. mehrere auswählbar, wenn man alle richtig hat einen extra punkt kriegen -8. verhindern dass 3 mal hinterander der gleicher owner bzw. das gleiche lied kommt -9. songs die schon gespielt wurden in extra liste anzeigen um doppelte songs zu vermeiden -(evtl. feste liste für spätere runden) -10. Schauen ob andere auch einen song in der liste haben für mehrere auswahlen \ No newline at end of file diff --git a/src/main/java/eric/Roullette/controller/GameController.java b/src/main/java/eric/Roullette/controller/GameController.java index b752532..ca15429 100644 --- a/src/main/java/eric/Roullette/controller/GameController.java +++ b/src/main/java/eric/Roullette/controller/GameController.java @@ -62,13 +62,11 @@ public class GameController { userAccessTokens.put(username, playerAccessToken); } } - - if (accessToken == null) { - ctx.status(401).result("Zugriffstoken fehlt oder ist ungültig"); + if (!userAccessTokens.containsKey(username)) { + ctx.status(401).result("Zugriffstoken für Benutzer " + username + " nicht gefunden."); return; } - - var devices = authService.getDevices(accessToken); + var devices = authService.getDevices(userAccessTokens.get(username)); ctx.json(devices); }); diff --git a/src/main/java/eric/Roullette/service/GameService.java b/src/main/java/eric/Roullette/service/GameService.java index 2161e7d..090541f 100644 --- a/src/main/java/eric/Roullette/service/GameService.java +++ b/src/main/java/eric/Roullette/service/GameService.java @@ -92,7 +92,11 @@ package eric.Roullette.service; Game g = getOrCreateGame(gameId); if (g.players().isEmpty()) throw new IllegalStateException("No players"); String owner = g.players().get(ThreadLocalRandom.current().nextInt(g.players().size())); - String song = uris.get(ThreadLocalRandom.current().nextInt(uris.size())); + List ownerTracks = g.playerTracks().getOrDefault(owner, List.of()); + if (ownerTracks.isEmpty()) throw new IllegalStateException("Owner hat keine Tracks"); + String song = ownerTracks.get(ThreadLocalRandom.current().nextInt(ownerTracks.size())); + + //String song = uris.get(ThreadLocalRandom.current().nextInt(uris.size())); Game updated = new Game(gameId, g.players(), g.scores(), owner, song, uris, g.playerTracks()); games.put(gameId, updated); return updated; diff --git a/src/main/java/eric/Roullette/service/SpotifyAuthService.java b/src/main/java/eric/Roullette/service/SpotifyAuthService.java index cb62c98..19753d9 100644 --- a/src/main/java/eric/Roullette/service/SpotifyAuthService.java +++ b/src/main/java/eric/Roullette/service/SpotifyAuthService.java @@ -51,7 +51,7 @@ public class SpotifyAuthService { return tempApi.authorizationCodeUri() .scope(scope) .state(user) // Der Benutzername wird im State mitgegeben - .show_dialog(true) + //.show_dialog(true) .build() .execute(); } @@ -85,47 +85,47 @@ public class SpotifyAuthService { SpotifyApi userApi = userApis.get(user); if (userApi == null) { - System.out.println("Kein SpotifyApi-Client für Benutzer gefunden: " + user); + System.err.println("Kein SpotifyApi-Client für Benutzer gefunden: " + user); return Collections.emptyList(); } - System.out.println("SpotifyApi-Client für Benutzer gefunden: " + user); - System.out.println("AccessToken: " + userApi.getAccessToken()); - System.out.println("RefreshToken: " + userApi.getRefreshToken()); +// System.out.println("SpotifyApi-Client für Benutzer gefunden: " + user); +// System.out.println("AccessToken: " + userApi.getAccessToken()); +// System.out.println("RefreshToken: " + userApi.getRefreshToken()); try { - System.out.println("Hole Profil für Benutzer: " + user); + //System.out.println("Hole Profil für Benutzer: " + user); // Hole das Profil des Benutzers, um den Account-Typ zu überprüfen - var profile = userApi.getCurrentUsersProfile().build().execute(); - System.out.println("Account-Typ: " + profile.getProduct()); + //var profile = userApi.getCurrentUsersProfile().build().execute(); + //System.out.println("Account-Typ: " + profile.getProduct()); - System.out.println("Erstelle Anfrage für kürzlich gespielte Tracks..."); - if (userApi.getRefreshToken() == null) { - System.out.println("Refresh Token für Benutzer " + user + " ist nicht gesetzt."); - } + //System.out.println("Erstelle Anfrage für kürzlich gespielte Tracks..."); +// if (userApi.getRefreshToken() == null) { +// System.err.println("Refresh Token für Benutzer " + user + " ist nicht gesetzt."); +// } - System.out.println("Refresh Token für Benutzer " + user + " ist gesetzt."); - if( userApi.getAccessToken() == null) { - System.out.println("Access Token für Benutzer " + user + " ist nicht gesetzt."); - return Collections.emptyList(); - } +// System.out.println("Refresh Token für Benutzer " + user + " ist gesetzt."); +// if( userApi.getAccessToken() == null) { +// System.out.println("Access Token für Benutzer " + user + " ist nicht gesetzt."); +// return Collections.emptyList(); +// } - System.out.println("Access Token für Benutzer " + user + " ist gesetzt."); +// System.out.println("Access Token für Benutzer " + user + " ist gesetzt."); GetCurrentUsersRecentlyPlayedTracksRequest request = userApi.getCurrentUsersRecentlyPlayedTracks() .limit(limit) .build(); // Führe die Anfrage aus und erhalte die Ergebnisse - System.out.println("Führe paging Anfrage aus..."); +// System.out.println("Führe paging Anfrage aus..."); PagingCursorbased history = request.execute(); - System.out.println("Paging Anfrage erfolgreich ausgeführt."); +// System.out.println("Paging Anfrage erfolgreich ausgeführt."); // Überprüfe, ob die Ergebnisse leer sind - System.out.println("Überprüfe, ob Ergebnisse vorhanden sind..."); +// System.out.println("Überprüfe, ob Ergebnisse vorhanden sind..."); if (history == null || history.getItems() == null) { return Collections.emptyList(); } - System.out.println("Verarbeite kürzlich gespielte Tracks..."); +// System.out.println("Verarbeite kürzlich gespielte Tracks..."); // Extrahiere die URIs der kürzlich gespielten Tracks List recentTracks = Arrays.stream(history.getItems()) .map(item -> item.getTrack().getUri()) @@ -134,6 +134,7 @@ public class SpotifyAuthService { System.out.println("Gefundene kürzlich gespielte Tracks: " + recentTracks.size()); if (recentTracks.size() < limit) { + int oldLimit = limit; int newLimit = limit - recentTracks.size(); // restliche songs mit kürzlich gespeicherten Tracks auffüllen List savedTracks = getSavedTracks(user, newLimit, 0); @@ -142,8 +143,9 @@ public class SpotifyAuthService { recentTracks = new java.util.ArrayList<>(recentTracks); recentTracks.addAll(savedTracks.subList(0, Math.min(newLimit, savedTracks.size()))); if(recentTracks.size() < limit){ + oldLimit = newLimit; newLimit = limit - recentTracks.size(); - List savedTracks2 = getSavedTracks(user, newLimit, 50); + List savedTracks2 = getSavedTracks(user, newLimit, oldLimit); savedTracks2.removeAll(recentTracks); recentTracks.addAll(savedTracks2.subList(0, Math.min(newLimit, savedTracks2.size()))); } diff --git a/src/main/java/eric/Roullette/websocket/GameWebSocketHandler.java b/src/main/java/eric/Roullette/websocket/GameWebSocketHandler.java index dff62d1..f8bcf1e 100644 --- a/src/main/java/eric/Roullette/websocket/GameWebSocketHandler.java +++ b/src/main/java/eric/Roullette/websocket/GameWebSocketHandler.java @@ -52,7 +52,19 @@ public class GameWebSocketHandler { // Connection geschlossen ws.onClose(ctx -> { String gameId = ctx.pathParam("gameId"); + String username = ctx.queryParam("username"); service.removeSession(gameId, ctx); + + // Spieler aus der Spielerliste entfernen + var game = service.getOrCreateGame(gameId); + if (username != null && game.players().contains(username)) { + game.players().remove(username); + game.scores().remove(username); + // Optional: auch die Tracks entfernen + game.playerTracks().remove(username); + } + service.broadcastPlayers(gameId); + }); // Eingehende Nachrichten (Guesses & Player-Requests) @@ -88,14 +100,36 @@ public class GameWebSocketHandler { .flatMap(List::stream) .toList(); System.out.println("AlltracksCache für Spiel " + gameId + " hat " + allTracks.size() + " Songs (rundenstart)"); + //Trackinfos für alle Spieler sammeln + + if(playerTrackInfoCache.containsKey(gameId)){ + // Wenn der Cache schon existiert, dann nur die Trackinfos nutzen + System.out.println("TrackInfosCache für Spiel " + gameId + " existiert bereits (rundenstart)"); + // prüfen ob ein neuer spieler dazugekommen ist + if( allPlayerTracks.size() > playerTrackInfoCache.get(gameId).size()) { + System.out.println("Neuer Spieler hinzugefügt, Trackinfos werden aktualisiert (rundenstart)"); + Map> allTrackInfos = service.getTrackInfos(allPlayerTracks); + // Cache für Trackinfos pro Spiel-ID aktualisieren + playerTrackInfoCache.put(gameId, allTrackInfos); + } else { + System.out.println("Keine neuen Spieler, Trackinfos bleiben unverändert (rundenstart)"); + } + + } else { + // Wenn der Cache nicht existiert, dann Trackinfos sammeln + System.out.println("TrackInfosCache für Spiel " + gameId + " wird erstellt (rundenstart)"); + Map> allTrackInfos = service.getTrackInfos(allPlayerTracks); +// Cache für Trackinfos pro Spiel-ID + playerTrackInfoCache.put(gameId, allTrackInfos); + } + + System.out.println("TrackInfosCache für Spiel " + gameId + " hat " + playerTrackInfoCache.get(gameId).size() + " Spieler (rundenstart)"); + + if (!allTracks.isEmpty()) { service.startRound(gameId, allTracks); } - // Trackinfos für alle Spieler sammeln - //Map> allTrackInfos = service.getTrackInfos(allPlayerTracks); - // Cache für Trackinfos pro Spiel-ID - //playerTrackInfoCache.put(gameId, allTrackInfos); - //System.out.println("TrackInfosCache für Spiel " + gameId + " hat " + allTrackInfos.size() + " Spieler (rundenstart)"); +// broadcastRoundStart(gameId); } } @@ -149,12 +183,19 @@ private void broadcastRoundResult(String gameId) { Map guesses = currentGuesses.remove(gameId); String owner = game.currentOwner(); +// System.out.println("Owner: " + owner); +// System.out.println("Guesses: " + guesses); +// System.out.println("Scores vor Auswertung: " + scores); + // Für jeden Tippenden Score anpassen for (Map.Entry entry : guesses.entrySet()) { String guesser = entry.getKey(); boolean correct = owner.equals(entry.getValue()); scores.merge(guesser, correct ? 3 : -1, Integer::sum); } +// System.out.println("Owner: " + owner); +// System.out.println("Guesses: " + guesses); +// System.out.println("Scores nach Auswertung: " + scores); String msg = JsonUtil.toJson(Map.of( "type", "round-result", @@ -165,22 +206,24 @@ private void broadcastRoundResult(String gameId) { broadcastToAll(gameId, msg); // Prüfe auf Gewinner - String winner = scores.entrySet().stream() - .filter(e -> e.getValue() >= 6) - .map(Map.Entry::getKey) - .findFirst() - .orElse(null); - if (winner != null) { - // Broadcast an alle, dass das Spiel vorbei ist - String winMsg = JsonUtil.toJson(Map.of( - "type", "game-end", - "winner", winner, - "scores", scores - )); - broadcastToAll(gameId, winMsg); - game.scores().replaceAll((user , pts) -> 0); // Reset Scores für alle Spieler + // Nur beenden, wenn EIN Spieler allein die höchste Punktzahl >= score hat + int score = 6; + int max = scores.values().stream().max(Integer::compareTo).orElse(0); + List topScorers = scores.entrySet().stream() + .filter(e -> e.getValue() == max && max >= score) + .map(Map.Entry::getKey) + .toList(); - } + if (topScorers.size() == 1) { + String winner = topScorers.get(0); + String winMsg = JsonUtil.toJson(Map.of( + "type", "game-end", + "winner", winner, + "scores", scores + )); + broadcastToAll(gameId, winMsg); + game.scores().replaceAll((user , pts) -> 0); // Reset Scores + } // else{ // // nächste Runde starten // // ... diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index cb82fcd..59a12ba 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,6 +1 @@ -spring.application.name=Roullette - -spotify: -client-id: 70c36cd6e2d54ad0ba2e60ef6334bbc8 -client-secret: 116188574dd140eab1973e75c7e5ecfe -redirect-uri: https://www.davidmagkuchen.de/spotify/callback \ No newline at end of file +spring.application.name=Roullette \ No newline at end of file diff --git a/src/main/resources/public/js/device-select.js b/src/main/resources/public/js/device-select.js index 487fe5d..5b1027a 100644 --- a/src/main/resources/public/js/device-select.js +++ b/src/main/resources/public/js/device-select.js @@ -18,6 +18,13 @@ area.appendChild(select); async function loadDevices() { select.innerHTML = ""; + + // Standardoption "Kein Gerät" + const noneOpt = document.createElement("option"); + noneOpt.value = ""; + noneOpt.textContent = "Kein Gerät"; + select.appendChild(noneOpt); + const devices = await fetchJson(`/api/spotify/devices?username=${encodeURIComponent(username)}`); if (!devices.length) { const opt = document.createElement("option"); @@ -34,6 +41,8 @@ async function loadDevices() { select.appendChild(opt); }); select.disabled = false; + select.value = ""; // "Kein Gerät" als Standard + } loadDevices(); diff --git a/src/main/resources/public/js/game.js b/src/main/resources/public/js/game.js index e8b1964..2f7ef9c 100644 --- a/src/main/resources/public/js/game.js +++ b/src/main/resources/public/js/game.js @@ -316,8 +316,9 @@ function handleGameEnd({ winner }) { // Spotify-Playback Funktion (unverändert) async function playOnSpotify(trackUri, username) { const deviceId = document.getElementById("deviceSelect")?.value; - if (!deviceId) { - alert("Bitte ein Wiedergabegerät auswählen!"); + if (deviceId === "") { + //alert("Bitte ein Wiedergabegerät auswählen!"); + //keine warnung i guess return; } try {