Optimierungen #48

Merged
3014947 merged 10 commits from Optimierungen into main 2025-08-12 03:09:10 +02:00
8 changed files with 109 additions and 68 deletions

View File

@ -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

View File

@ -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);
});

View File

@ -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<String> 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;

View File

@ -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<PlayHistory> 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<String> 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<String> 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<String> savedTracks2 = getSavedTracks(user, newLimit, 50);
List<String> savedTracks2 = getSavedTracks(user, newLimit, oldLimit);
savedTracks2.removeAll(recentTracks);
recentTracks.addAll(savedTracks2.subList(0, Math.min(newLimit, savedTracks2.size())));
}

View File

@ -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<String, List<String>> 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<String, List<String>> 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<String, List<String>> 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<String,String> 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<String, String> 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<String> 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
// // ...

View File

@ -1,6 +1 @@
spring.application.name=Roullette
spotify:
client-id: 70c36cd6e2d54ad0ba2e60ef6334bbc8
client-secret: 116188574dd140eab1973e75c7e5ecfe
redirect-uri: https://www.davidmagkuchen.de/spotify/callback
spring.application.name=Roullette

View File

@ -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();

View File

@ -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 {