main #49
16
README.md
16
README.md
|
|
@ -1,11 +1,5 @@
|
|||
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
|
||||
Setup:
|
||||
|
||||
- Spotify developer app öffnen (free)
|
||||
- in user management jeden mitspieler mit email und username (anmeldename bei spotify) eintragen, geht seit mai nurnoch manuell da extended quota mode nurnoch für firmen ist
|
||||
- maven projekt compilieren, ClientID, redirectURL und Clientsecret auf server eintragen und Website als service ausführen
|
||||
|
|
@ -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);
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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())));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
// // ...
|
||||
|
|
|
|||
|
|
@ -1,6 +1 @@
|
|||
spring.application.name=Roullette
|
||||
|
||||
spotify:
|
||||
client-id: 70c36cd6e2d54ad0ba2e60ef6334bbc8
|
||||
client-secret: 116188574dd140eab1973e75c7e5ecfe
|
||||
redirect-uri: https://www.davidmagkuchen.de/spotify/callback
|
||||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in New Issue