GUI #41
|
|
@ -23,6 +23,7 @@ package eric.Roullette.controller;
|
|||
import java.util.Map;
|
||||
// import java.util.Objects;
|
||||
// import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
// import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
|
@ -32,6 +33,8 @@ public class GameController {
|
|||
private final GameWebSocketHandler webSocketHandler;
|
||||
private final OkHttpClient httpClient = new OkHttpClient();
|
||||
private String accessToken = "";
|
||||
private Map<String, String> userAccessTokens = new ConcurrentHashMap<>();
|
||||
// Map<username, accessToken>
|
||||
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(GameController.class);
|
||||
|
||||
public GameController(Javalin app, GameService gs, SpotifyAuthService sas, GameWebSocketHandler wsHandler) {
|
||||
|
|
@ -50,21 +53,28 @@ public class GameController {
|
|||
ctx.status(400).result("username fehlt");
|
||||
return;
|
||||
}
|
||||
var accessToken = authService.getAccessTokenForUser(username);
|
||||
// spieler in map hinzufügen
|
||||
|
||||
String playerAccessToken = null;
|
||||
if(!userAccessTokens.containsKey(username)) {
|
||||
playerAccessToken = authService.getAccessTokenForUser(username);
|
||||
if (playerAccessToken != null) {
|
||||
userAccessTokens.put(username, playerAccessToken);
|
||||
}
|
||||
}
|
||||
|
||||
if (accessToken == null) {
|
||||
ctx.status(401).result("Zugriffstoken fehlt oder ist ungültig");
|
||||
return;
|
||||
}
|
||||
setToken(accessToken);
|
||||
|
||||
var devices = authService.getDevices(accessToken);
|
||||
ctx.json(devices);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private void setToken(String accessToken) {
|
||||
this.accessToken = accessToken;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void createGame(Context ctx) throws InterruptedException {
|
||||
Map<String, Object> body = (Map<String, Object>) ctx.bodyAsClass(Map.class);
|
||||
|
|
@ -144,6 +154,7 @@ public class GameController {
|
|||
|
||||
try {
|
||||
//String accessToken = authService.getAccessTokenForUser(username);
|
||||
String accessToken = userAccessTokens.get(username);
|
||||
OkHttpClient client = httpClient;
|
||||
String trackId = trackUri.split(":")[2];
|
||||
Request getTrack = new Request.Builder()
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import java.net.URI;
|
|||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import static com.neovisionaries.i18n.CountryCode.DE;
|
||||
//import static com.neovisionaries.i18n.CountryCode.DE;
|
||||
|
||||
public class SpotifyAuthService {
|
||||
private final String clientId;
|
||||
|
|
@ -38,18 +38,27 @@ public class SpotifyAuthService {
|
|||
public URI getAuthorizationUri(String user) {
|
||||
System.out.println("Erstelle Auth-URL für Benutzer: " + user);
|
||||
// Temporäre API-Instanz nur für die Erstellung der Auth-URL
|
||||
String scope = "user-read-recently-played user-library-read user-modify-playback-state user-read-playback-state streaming user-read-private";
|
||||
//
|
||||
|
||||
SpotifyApi tempApi = new SpotifyApi.Builder()
|
||||
.setClientId(clientId)
|
||||
.setClientSecret(clientSecret)
|
||||
.setRedirectUri(redirectUri)
|
||||
.build();
|
||||
|
||||
//überprüfe, ob der nutzer ein Premium-User ist
|
||||
return tempApi.authorizationCodeUri()
|
||||
.scope("user-read-recently-played user-library-read user-read-playback-state user-modify-playback-state streaming")
|
||||
.scope(scope)
|
||||
.state(user) // Der Benutzername wird im State mitgegeben
|
||||
.show_dialog(true)
|
||||
.build()
|
||||
.execute();
|
||||
}
|
||||
// public boolean isPremiumUser(SpotifyApi api) throws IOException, SpotifyWebApiException, ParseException {
|
||||
// var user = api.getCurrentUsersProfile().build().execute();
|
||||
// return "premium".equalsIgnoreCase(String.valueOf(user.getProduct()));
|
||||
// }
|
||||
|
||||
public void exchangeCode(String code, String user) throws IOException, ParseException, SpotifyWebApiException {
|
||||
// Erstellt eine neue, dedizierte API-Instanz für diesen Benutzer
|
||||
|
|
@ -63,6 +72,8 @@ public class SpotifyAuthService {
|
|||
AuthorizationCodeCredentials creds = userApi.authorizationCode(code).build().execute();
|
||||
userApi.setAccessToken(creds.getAccessToken());
|
||||
userApi.setRefreshToken(creds.getRefreshToken());
|
||||
System.out.println("Granted scopes: " + creds.getScope()); // wichtig fürs Debugging
|
||||
|
||||
|
||||
// Speichert die fertig konfigurierte API-Instanz für den Benutzer
|
||||
userApis.put(user, userApi);
|
||||
|
|
@ -70,26 +81,57 @@ public class SpotifyAuthService {
|
|||
|
||||
public List<String> getRecentTracks(String user) {
|
||||
System.out.println("Hole kürzlich gespielte Tracks für Benutzer: " + user);
|
||||
int limit = 2;
|
||||
int limit = 50;
|
||||
SpotifyApi userApi = userApis.get(user);
|
||||
|
||||
if (userApi == null) {
|
||||
System.err.println("Kein SpotifyApi-Client für Benutzer gefunden: " + user);
|
||||
System.out.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());
|
||||
|
||||
|
||||
try {
|
||||
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());
|
||||
|
||||
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("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();
|
||||
}
|
||||
|
||||
try {
|
||||
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...");
|
||||
PagingCursorbased<PlayHistory> history = request.execute();
|
||||
System.out.println("Paging Anfrage erfolgreich ausgeführt.");
|
||||
// Überprüfe, ob die Ergebnisse leer 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...");
|
||||
// Extrahiere die URIs der kürzlich gespielten Tracks
|
||||
List<String> recentTracks = Arrays.stream(history.getItems())
|
||||
.map(item -> item.getTrack().getUri())
|
||||
.distinct()
|
||||
.toList();
|
||||
System.out.println("Gefundene kürzlich gespielte Tracks: " + recentTracks.size());
|
||||
|
||||
if (recentTracks.size() < limit) {
|
||||
int newLimit = limit - recentTracks.size();
|
||||
|
|
@ -106,7 +148,14 @@ public class SpotifyAuthService {
|
|||
recentTracks.addAll(savedTracks2.subList(0, Math.min(newLimit, savedTracks2.size())));
|
||||
}
|
||||
}
|
||||
System.out.println("Endgültige Anzahl kürzlich gespielter Tracks: " + recentTracks.size());
|
||||
return recentTracks.subList(0, Math.min(limit, recentTracks.size()));
|
||||
// } catch (se.michaelthelin.spotify.exceptions.detailed.ForbiddenException e) {
|
||||
// System.out.println("ForbiddenException: " + e.getMessage());
|
||||
// System.out.println("Möglicherweise hat der Benutzer keine Berechtigung, kürzlich gespielte Tracks abzurufen.");
|
||||
//
|
||||
//
|
||||
// return Collections.emptyList();
|
||||
} catch (IOException | SpotifyWebApiException | ParseException e) {
|
||||
e.printStackTrace();
|
||||
return Collections.emptyList();
|
||||
|
|
@ -197,6 +246,7 @@ public class SpotifyAuthService {
|
|||
.build();
|
||||
try (Response resp = client.newCall(req).execute()) {
|
||||
if (!resp.isSuccessful()) return List.of();
|
||||
assert resp.body() != null;
|
||||
String body = resp.body().string();
|
||||
// Parsen, z.B. mit Jackson
|
||||
var node = new ObjectMapper().readTree(body);
|
||||
|
|
|
|||
|
|
@ -22,10 +22,10 @@ public class GameWebSocketHandler {
|
|||
// Spiel-ID → (Username → deren Guess)
|
||||
private final Map<String, Map<String, String>> currentGuesses = new ConcurrentHashMap<>();
|
||||
|
||||
private final Map<String, List<String>> trackInfoCache = new ConcurrentHashMap<>();
|
||||
private final Map<String, List<String>> allTracksCache = new ConcurrentHashMap<>();
|
||||
// private final Map<String, List<String>> trackInfoCache = new ConcurrentHashMap<>();
|
||||
// private final Map<String, List<String>> allTracksCache = new ConcurrentHashMap<>();
|
||||
//Map<gameId, Map<player, List<String>>
|
||||
private Map<String, Map<String, List<String>>> playerTracksCache = new ConcurrentHashMap<>();
|
||||
//private Map<String, Map<String, List<String>>> playerTracksCache = new ConcurrentHashMap<>();
|
||||
private Map<String, Map<String, List<String>>> playerTrackInfoCache = new ConcurrentHashMap<>();
|
||||
|
||||
public GameWebSocketHandler(GameService gameService) {
|
||||
|
|
@ -77,9 +77,7 @@ public class GameWebSocketHandler {
|
|||
}
|
||||
case "requestPlayers" -> service.broadcastPlayers(gameId);
|
||||
|
||||
case "next-round" -> {
|
||||
nextround(gameId);
|
||||
}
|
||||
case "next-round" -> nextround(gameId);
|
||||
case "start-round" -> {
|
||||
var currentGame = service.getOrCreateGame(gameId);
|
||||
if (currentGame.players().isEmpty()) return;
|
||||
|
|
@ -94,10 +92,10 @@ public class GameWebSocketHandler {
|
|||
service.startRound(gameId, allTracks);
|
||||
}
|
||||
// Trackinfos für alle Spieler sammeln
|
||||
Map<String, List<String>> allTrackInfos = service.getTrackInfos(allPlayerTracks);
|
||||
//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)");
|
||||
//playerTrackInfoCache.put(gameId, allTrackInfos);
|
||||
//System.out.println("TrackInfosCache für Spiel " + gameId + " hat " + allTrackInfos.size() + " Spieler (rundenstart)");
|
||||
broadcastRoundStart(gameId);
|
||||
}
|
||||
}
|
||||
|
|
@ -168,7 +166,7 @@ private void broadcastRoundResult(String gameId) {
|
|||
|
||||
// Prüfe auf Gewinner
|
||||
String winner = scores.entrySet().stream()
|
||||
.filter(e -> e.getValue() >= 30)
|
||||
.filter(e -> e.getValue() >= 6)
|
||||
.map(Map.Entry::getKey)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
|
@ -182,14 +180,15 @@ private void broadcastRoundResult(String gameId) {
|
|||
broadcastToAll(gameId, winMsg);
|
||||
game.scores().replaceAll((user , pts) -> 0); // Reset Scores für alle Spieler
|
||||
|
||||
}else{
|
||||
// nächste Runde starten
|
||||
// ...
|
||||
// new Thread(() -> {
|
||||
// try { Thread.sleep(2000); } catch (InterruptedException ignored) {}
|
||||
// nextround(gameId);
|
||||
// }).start();
|
||||
}
|
||||
// else{
|
||||
// // nächste Runde starten
|
||||
// // ...
|
||||
//// new Thread(() -> {
|
||||
//// try { Thread.sleep(2000); } catch (InterruptedException ignored) {}
|
||||
//// nextround(gameId);
|
||||
//// }).start();
|
||||
// }
|
||||
}
|
||||
|
||||
/** Hilfsmethode: Sendet eine Nachricht an alle WebSocket-Sessions eines Spiels. */
|
||||
|
|
|
|||
|
|
@ -189,7 +189,6 @@
|
|||
<section class="card">
|
||||
<div class="card-hd">
|
||||
<h2 style="margin:0">Teilnehmer</h2>
|
||||
<button id="refreshPlayers" class="btn btn-ghost">Aktualisieren</button>
|
||||
</div>
|
||||
<div class="card-bd">
|
||||
<ul id="playersList"></ul>
|
||||
|
|
|
|||
|
|
@ -301,7 +301,10 @@ function handleRoundResult({ scores, guesses, owner }) {
|
|||
|
||||
// 8) Spielende -> Start-Button zurück
|
||||
function handleGameEnd({ winner }) {
|
||||
const nextBtn = document.getElementById("nextRound");
|
||||
resultP.textContent = `🎉 ${winner} hat gewonnen!`;
|
||||
nextBtn.hidden = true;
|
||||
nextBtn.disabled = true;
|
||||
setTimeout(() => {
|
||||
startBtn.hidden = false;
|
||||
startBtn.disabled = false;
|
||||
|
|
|
|||
Loading…
Reference in New Issue