feat: enforce playlist selection before starting the game and update playlist handling
All checks were successful
Build and Push Docker Image / docker (push) Successful in 6s

This commit is contained in:
2025-10-12 22:55:03 +02:00
parent 17faca1f46
commit 0e51e233c3
5 changed files with 51 additions and 14 deletions

View File

@@ -107,8 +107,9 @@ export function renderRoom(room) {
const isHost = state.playerId === room.hostId; const isHost = state.playerId === room.hostId;
const activePlayers = room.players.filter((p) => !p.spectator && p.connected); const activePlayers = room.players.filter((p) => !p.spectator && p.connected);
const allReady = activePlayers.length > 0 && activePlayers.every((p) => p.ready); const allReady = activePlayers.length > 0 && activePlayers.every((p) => p.ready);
const hasPlaylist = !!room.state.playlist;
const canStart = room.state.status === 'lobby' && isHost && allReady; const canStart = room.state.status === 'lobby' && isHost && allReady && hasPlaylist;
if ($startGame) $startGame.classList.toggle('hidden', !canStart); if ($startGame) $startGame.classList.toggle('hidden', !canStart);
@@ -121,18 +122,52 @@ export function renderRoom(room) {
$playlistSection.classList.toggle('hidden', room.state.status !== 'lobby' || !isHost); $playlistSection.classList.toggle('hidden', room.state.status !== 'lobby' || !isHost);
} }
if ($playlistSelect && state.playlists && state.playlists.length > 0) { if ($playlistSelect && state.playlists && state.playlists.length > 0) {
// Populate playlist dropdown if not already populated // Populate playlist dropdown if not already populated with actual playlists
if ($playlistSelect.options.length === 1 && $playlistSelect.options[0].value === 'default') { const needsPopulation =
$playlistSelect.options.length === 0 ||
($playlistSelect.options.length === 1 && $playlistSelect.options[0].value === 'default');
if (needsPopulation) {
$playlistSelect.innerHTML = ''; $playlistSelect.innerHTML = '';
// Add a placeholder option
const placeholderOption = document.createElement('option');
placeholderOption.value = '';
placeholderOption.textContent = '-- Bitte Playlist auswählen --';
placeholderOption.disabled = true;
placeholderOption.selected = true; // Make it selected by default
$playlistSelect.appendChild(placeholderOption);
state.playlists.forEach((playlist) => { state.playlists.forEach((playlist) => {
const option = document.createElement('option'); const option = document.createElement('option');
option.value = playlist.id; option.value = playlist.id;
option.textContent = `${playlist.name} (${playlist.trackCount} Tracks)`; option.textContent = `${playlist.name} (${playlist.trackCount} Tracks)`;
$playlistSelect.appendChild(option); $playlistSelect.appendChild(option);
}); });
// Mark that we've populated the dropdown
state.playlistsPopulated = true;
// Auto-select first playlist if host and in lobby (only on first population)
if (
!room.state.playlist &&
isHost &&
room.state.status === 'lobby' &&
state.playlists.length > 0
) {
// Use setTimeout to ensure the change event is properly triggered after render
setTimeout(() => {
const firstPlaylistId = state.playlists[0].id;
$playlistSelect.value = firstPlaylistId;
// Trigger the change event to send to server
$playlistSelect.dispatchEvent(new Event('change'));
}, 100);
}
}
// Set selected playlist based on room state
if (room.state.playlist) {
$playlistSelect.value = room.state.playlist;
} }
// Set selected playlist
$playlistSelect.value = room.state.playlist || 'default';
} }
if ($currentPlaylist) { if ($currentPlaylist) {
$currentPlaylist.textContent = room.state.playlist || 'default'; $currentPlaylist.textContent = room.state.playlist || 'default';

View File

@@ -121,7 +121,14 @@ export function wireUi() {
$room.classList.add('hidden'); $room.classList.add('hidden');
}); });
wire($startGame, 'click', () => sendMsg({ type: 'start_game' })); wire($startGame, 'click', () => {
// Validate playlist selection before starting
if (!state.room?.state?.playlist) {
showToast('⚠️ Bitte wähle zuerst eine Playlist aus!');
return;
}
sendMsg({ type: 'start_game' });
});
wire($readyChk, 'change', (e) => { wire($readyChk, 'change', (e) => {
const val = !!e.target.checked; const val = !!e.target.checked;

View File

@@ -298,6 +298,8 @@ export function setupWebSocket(server) {
const room = rooms.get(player.roomId); const room = rooms.get(player.roomId);
if (!room) return; if (!room) return;
if (room.hostId !== player.id) return send('error', { message: 'Only host can start' }); if (room.hostId !== player.id) return send('error', { message: 'Only host can start' });
if (!room.state.playlist)
return send('error', { message: 'Please select a playlist first' });
const active = [...room.players.values()].filter( const active = [...room.players.values()].filter(
(p) => !room.state.spectators?.[p.id] && p.connected (p) => !room.state.spectators?.[p.id] && p.connected
); );

View File

@@ -108,13 +108,6 @@ export async function loadDeck(playlistId = 'default') {
}) })
); );
tracks.push(...batchTracks); tracks.push(...batchTracks);
// Optional: Log progress for large playlists
if (files.length > 100 && (i + BATCH_SIZE) % 100 === 0) {
console.log(
`Loading playlist ${playlistId}: ${Math.min(i + BATCH_SIZE, files.length)}/${files.length} tracks processed`
);
}
} }
console.log(`Loaded ${tracks.length} tracks from playlist: ${playlistId}`); console.log(`Loaded ${tracks.length} tracks from playlist: ${playlistId}`);

View File

@@ -42,7 +42,7 @@ export function createRoom(name, host) {
paused: false, paused: false,
pausedPosSec: 0, pausedPosSec: 0,
goal: 10, goal: 10,
playlist: 'default', // Selected playlist for this room playlist: null, // Selected playlist for this room (must be chosen by host)
}, },
}; };
rooms.set(id, room); rooms.set(id, room);