Files
quizify/templates/quiz_buzzer_multiplayer.html

745 lines
28 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html>
<head>
<title>{{ translations['quiz_title'] }} Buzzer Multiplayer</title>
<script src="https://sdk.scdn.co/spotify-player.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #0a0e27 0%, #1a1f3a 50%, #0f1419 100%);
color: #e0e0e0;
min-height: 100vh;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
}
.quiz-container {
max-width: 1200px;
width: 100%;
background: rgba(25, 30, 45, 0.95);
border-radius: 20px;
padding: 40px;
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.5);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.05);
}
.scoreboard {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-bottom: 30px;
}
.player-card {
background: rgba(15, 20, 25, 0.8);
border-radius: 12px;
padding: 20px;
border: 2px solid rgba(29, 185, 84, 0.3);
transition: all 0.3s ease;
}
.player-card.active {
border-color: #1DB954;
box-shadow: 0 0 20px rgba(29, 185, 84, 0.5);
}
.player-card.buzzed {
border-color: #f44336;
box-shadow: 0 0 20px rgba(244, 67, 54, 0.5);
}
.player-name {
font-size: 1.3em;
font-weight: bold;
color: #1DB954;
margin-bottom: 10px;
}
.player-score {
font-size: 2em;
font-weight: bold;
color: #e0e0e0;
}
.buzzer-timer {
text-align: center;
font-size: 4em;
font-weight: bold;
color: #1DB954;
margin: 30px 0;
text-shadow: 0 0 20px rgba(29, 185, 84, 0.5);
}
.buzzer-timer.warning {
color: #FFA500;
animation: pulse 1s infinite;
}
.buzzer-timer.critical {
color: #f44336;
animation: pulse 0.5s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.7; transform: scale(1.05); }
}
.points-display {
text-align: center;
font-size: 2.5em;
font-weight: bold;
margin: 20px 0;
}
.points-display.high {
color: #4CAF50;
}
.points-display.medium {
color: #FFA500;
}
.points-display.low {
color: #f44336;
}
.buzzer-grid {
display: flex;
justify-content: center;
gap: 20px;
margin: 20px 0;
flex-wrap: wrap;
}
.player-buzzer {
width: 180px;
height: 180px;
font-size: 1.4em;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 2px;
background: linear-gradient(135deg, #f44336 0%, #d32f2f 100%);
color: white;
border: 3px solid rgba(244, 67, 54, 0.5);
border-radius: 50%;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 10px 40px rgba(244, 67, 54, 0.5);
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
.player-buzzer:hover:not(.disabled) {
transform: scale(1.05);
box-shadow: 0 15px 50px rgba(244, 67, 54, 0.7);
}
.player-buzzer:active:not(.disabled) {
transform: scale(0.95);
}
.player-buzzer.disabled {
background: linear-gradient(135deg, #666 0%, #444 100%);
border-color: rgba(100, 100, 100, 0.3);
cursor: not-allowed;
opacity: 0.5;
}
.player-buzzer.start {
width: 200px;
height: 200px;
background: linear-gradient(135deg, #1DB954 0%, #1ed760 100%);
border-color: rgba(29, 185, 84, 0.3);
box-shadow: 0 10px 40px rgba(29, 185, 84, 0.5);
}
.player-buzzer.start:hover {
box-shadow: 0 15px 50px rgba(29, 185, 84, 0.7);
}
.answer-section {
display: none;
text-align: center;
margin-top: 30px;
}
.answer-section.active {
display: block;
animation: slideIn 0.3s ease;
}
@keyframes slideIn {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
.btn {
padding: 12px 24px;
margin: 5px;
background: linear-gradient(135deg, #1DB954 0%, #1ed760 100%);
color: white;
border: none;
border-radius: 25px;
cursor: pointer;
font-size: 1em;
font-weight: 600;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(29, 185, 84, 0.3);
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(29, 185, 84, 0.5);
}
.btn-secondary {
background: linear-gradient(135deg, #535353 0%, #6b6b6b 100%);
box-shadow: 0 4px 15px rgba(83, 83, 83, 0.3);
}
.btn-danger {
background: linear-gradient(135deg, #f44336 0%, #e57373 100%);
}
input[type="text"] {
padding: 14px 20px;
width: 100%;
max-width: 400px;
border: 2px solid rgba(29, 185, 84, 0.3);
background: rgba(15, 20, 35, 0.6);
color: #e0e0e0;
border-radius: 25px;
font-size: 16px;
transition: all 0.3s ease;
outline: none;
}
input[type="text"]:focus {
border-color: #1DB954;
box-shadow: 0 0 15px rgba(29, 185, 84, 0.4);
}
.result-container {
margin: 25px 0;
padding: 20px;
border-radius: 15px;
}
.search-results {
position: relative;
max-width: 400px;
margin: 10px auto;
background: rgba(15, 20, 35, 0.95);
border-radius: 12px;
max-height: 300px;
overflow-y: auto;
display: none;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4);
}
.search-item {
padding: 12px 20px;
cursor: pointer;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
transition: background 0.2s;
}
.search-item:hover {
background: rgba(29, 185, 84, 0.2);
}
.search-item:last-child {
border-bottom: none;
}
.current-player {
text-align: center;
font-size: 1.5em;
color: #1DB954;
margin: 20px 0;
font-weight: bold;
}
</style>
<script>
let allTracks = {{ all_tracks|tojson }};
let currentGameMode = "{{ game_mode }}";
let correctAnswer = "";
const i18n = {{ translations|tojson }};
let buzzTimer = null;
let startTime = null;
let buzzTime = null;
let maxPoints = parseInt(localStorage.getItem('buzzer_max_points')) || 1000;
let gracePeriod = parseInt(localStorage.getItem('buzzer_grace_period')) || 5;
let decayRate = parseInt(localStorage.getItem('buzzer_decay_rate')) || 50;
let gameStarted = false;
let currentBuzzer = null;
let buzzedPlayers = []; // Liste der Spieler die schon gebuzzert haben
let canBuzz = false; // Kann man buzzern?
let pendingPoints = 0; // Punkte die noch nicht gezählt wurden
// Lade Team-Namen und Anzahl
const teamCount = parseInt(localStorage.getItem('team_count')) || 4;
const teamNames = JSON.parse(localStorage.getItem('team_names') || '["Spieler 1", "Spieler 2", "Spieler 3", "Spieler 4"]');
// Spieler-Daten
let players = [
{ id: 1, name: teamNames[0] || 'Spieler 1', score: {{ player_scores[0] if player_scores else 0 }} },
{ id: 2, name: teamNames[1] || 'Spieler 2', score: {{ player_scores[1] if player_scores else 0 }} },
{ id: 3, name: teamNames[2] || 'Spieler 3', score: {{ player_scores[2] if player_scores else 0 }} },
{ id: 4, name: teamNames[3] || 'Spieler 4', score: {{ player_scores[3] if player_scores else 0 }} }
];
// Leertaste zum Buzzern
document.addEventListener('keydown', function(e) {
if (e.code === 'Space' && canBuzz && !currentBuzzer) {
e.preventDefault();
triggerBuzz();
}
});
window.onSpotifyWebPlaybackSDKReady = () => {
const token = '{{ access_token }}';
const player = new Spotify.Player({
name: 'Musik Quiz Buzzer Multiplayer',
getOAuthToken: cb => { cb(token); },
volume: 0.5
});
player.addListener('initialization_error', ({ message }) => { console.error(message); });
player.addListener('authentication_error', ({ message }) => { console.error(message); });
player.addListener('account_error', ({ message }) => { console.error(message); });
player.addListener('playback_error', ({ message }) => { console.error(message); });
player.addListener('ready', ({ device_id }) => {
console.log('Ready with Device ID', device_id);
document.getElementById('device_id').value = device_id;
window.deviceId = device_id;
setCorrectAnswer();
initializePlayers();
updateScoreboard();
});
player.addListener('player_state_changed', state => {
if (!state) return;
if (!state.paused && gameStarted && !startTime) {
console.log('Music started playing, starting timer in 1 second');
setTimeout(() => {
startBuzzerTimer();
}, 1000);
}
});
player.addListener('not_ready', ({ device_id }) => {
console.log('Device ID has gone offline', device_id);
});
player.connect();
window.spotifyPlayer = player;
};
function initializePlayers() {
// Update Spieler-Namen und verstecke inaktive Spieler
for (let i = 1; i <= 4; i++) {
const card = document.getElementById(`player${i}`);
const selectBtn = document.getElementById(`selectPlayer${i}`);
if (i <= teamCount) {
card.querySelector('.player-name').textContent = players[i - 1].name;
card.style.display = 'block';
if (selectBtn) {
selectBtn.textContent = players[i - 1].name;
selectBtn.style.display = 'block';
}
} else {
card.style.display = 'none';
if (selectBtn) {
selectBtn.style.display = 'none';
}
}
}
}
function updateScoreboard() {
players.forEach((player, index) => {
const card = document.getElementById(`player${player.id}`);
if (card) {
card.querySelector('.player-score').textContent = player.score;
}
});
}
function startGame() {
if (gameStarted) return;
gameStarted = true;
document.getElementById('startButton').classList.add('disabled');
document.getElementById('startButton').style.cursor = 'wait';
document.getElementById('buzzerHint').style.display = 'block';
const device_id = window.deviceId;
const startPosition = getOption('startPosition', 'start');
let position_ms = 0;
if (startPosition === 'random') {
const duration = {{ track.duration_ms if track.duration_ms else 180000 }};
position_ms = Math.floor(Math.random() * (duration - 30000));
}
fetch(`/play_track?device_id=${device_id}&track_uri={{ track.uri }}&position_ms=${position_ms}`, { method: 'POST' })
.then(response => response.json())
.then(() => {
console.log('Play command sent');
document.getElementById('startButton').style.display = 'none';
canBuzz = true;
})
.catch(error => console.error('Error starting playback:', error));
}
function startBuzzerTimer() {
startTime = Date.now();
canBuzz = true;
updateTimer();
}
function updateTimer() {
if (!canBuzz && currentBuzzer) return;
const elapsed = (Date.now() - startTime) / 1000;
const timerDisplay = document.getElementById('buzzerTimer');
const pointsDisplay = document.getElementById('pointsDisplay');
timerDisplay.textContent = elapsed.toFixed(2) + 's';
const currentPoints = calculatePoints(elapsed);
pointsDisplay.textContent = currentPoints + ' Punkte';
timerDisplay.className = 'buzzer-timer';
pointsDisplay.className = 'points-display';
if (elapsed > gracePeriod + 10) {
timerDisplay.classList.add('critical');
pointsDisplay.classList.add('low');
} else if (elapsed > gracePeriod) {
timerDisplay.classList.add('warning');
pointsDisplay.classList.add('medium');
} else {
pointsDisplay.classList.add('high');
}
buzzTimer = requestAnimationFrame(updateTimer);
}
function calculatePoints(elapsed) {
if (elapsed <= gracePeriod) {
return maxPoints;
}
const overtime = elapsed - gracePeriod;
const points = Math.max(0, maxPoints - Math.floor(overtime * decayRate));
return points;
}
function triggerBuzz() {
if (currentBuzzer !== null) return;
if (!canBuzz) return;
canBuzz = false; // Verhindere weitere Buzzes
buzzTime = Date.now();
const elapsed = (buzzTime - startTime) / 1000;
// Stoppe Timer-Updates
cancelAnimationFrame(buzzTimer);
// Friere Timer-Anzeige ein
const timerDisplay = document.getElementById('buzzerTimer');
const pointsDisplay = document.getElementById('pointsDisplay');
timerDisplay.textContent = elapsed.toFixed(2) + 's';
const points = calculatePoints(elapsed);
pointsDisplay.textContent = points + ' Punkte';
if (window.spotifyPlayer) {
window.spotifyPlayer.pause();
}
// Zeige Spielerauswahl
document.getElementById('playerSelection').style.display = 'block';
document.getElementById('currentPlayer').textContent = 'Wer hat gebuzzert?';
pendingPoints = points;
}
function selectPlayer(playerId) {
if (buzzedPlayers.includes(playerId)) {
alert('Dieser Spieler hat bereits gebuzzert!');
return;
}
currentBuzzer = playerId;
buzzedPlayers.push(playerId);
// Markiere Spieler
document.getElementById(`player${playerId}`).classList.add('buzzed');
document.getElementById('currentPlayer').textContent = `${players[playerId - 1].name} antwortet...`;
// Verstecke Spielerauswahl, zeige Antwortfeld
document.getElementById('playerSelection').style.display = 'none';
document.getElementById('answerSection').classList.add('active');
window.earnedPoints = pendingPoints;
}
function buzz(playerId) {
selectPlayer(playerId);
}
function setCorrectAnswer() {
if (currentGameMode === 'artist') {
correctAnswer = "{{ track.artists[0].name | clean }}";
document.getElementById('question-text').innerText = i18n.question_artist || 'Guess the artist!';
document.getElementById('answerInput').placeholder = i18n.input_artist || 'Artist name';
} else if (currentGameMode === 'title') {
correctAnswer = "{{ track.name | clean }}";
document.getElementById('question-text').innerText = i18n.question_title || 'Guess the title!';
document.getElementById('answerInput').placeholder = i18n.input_title || 'Song title';
} else if (currentGameMode === 'year') {
correctAnswer = "{{ track.album.release_date[:4] }}";
document.getElementById('question-text').innerText = i18n.question_year || 'Guess the year!';
document.getElementById('answerInput').placeholder = i18n.input_year || 'Year';
document.getElementById('answerInput').type = "number";
}
}
function searchTracks() {
const query = document.getElementById('answerInput').value;
if (query.length < 2) {
document.getElementById('searchResults').style.display = 'none';
return;
}
fetch('/search_track', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
query: query,
all_tracks: allTracks
})
})
.then(response => response.json())
.then(data => {
const resultsContainer = document.getElementById('searchResults');
resultsContainer.innerHTML = '';
if (data.results.length === 0) {
resultsContainer.style.display = 'none';
return;
}
data.results.forEach(result => {
const item = document.createElement('div');
item.className = 'search-item';
item.innerHTML = `<strong>${result.name}</strong> - ${result.artist}`;
item.onclick = function() {
document.getElementById('answerInput').value =
currentGameMode === 'artist' ? result.artist : result.name;
resultsContainer.style.display = 'none';
};
resultsContainer.appendChild(item);
});
resultsContainer.style.display = 'block';
})
.catch(error => {
console.error('Error searching tracks:', error);
});
}
function checkAnswer() {
const guess = document.getElementById('answerInput').value;
if (!guess) return;
// Disable input während Prüfung
document.getElementById('answerInput').disabled = true;
document.querySelector('button[onclick="checkAnswer()"]').disabled = true;
fetch('/check_answer_buzzer', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
guess: guess,
correct_answer: correctAnswer,
game_mode: currentGameMode,
playlist_id: '{{ playlist_id }}',
earned_points: window.earnedPoints,
player_id: currentBuzzer,
apply_points: false // Punkte NICHT sofort anwenden
})
})
.then(response => response.json())
.then(data => {
const resultContainer = document.getElementById('resultContainer');
if (data.correct) {
// Speichere Punkte, aber wende sie noch NICHT an
pendingPoints = window.earnedPoints;
resultContainer.innerHTML = `
<div style="background:linear-gradient(135deg, rgba(76, 175, 80, 0.2) 0%, rgba(56, 142, 60, 0.2) 100%); padding:20px; border-radius:12px; border:2px solid #4CAF50;">
<h3 style="color:#4CAF50; margin-bottom:10px;">✅ ${i18n.correct || 'Richtig'}</h3>
<p style="font-size:1.5em; margin:10px 0;"><strong style="color:#1DB954;">+${window.earnedPoints}</strong> Punkte für ${players[currentBuzzer - 1].name}!</p>
<div style="margin-top:20px; padding:20px; background:rgba(15,20,25,0.8); border-radius:12px;">
<h4 style="color:#1DB954; margin-bottom:15px;">Song Info:</h4>
<p style="margin:8px 0;"><strong style="color:#1DB954;">Titel:</strong> <span style="color:#e0e0e0;">{{ track.name | clean }}</span></p>
<p style="margin:8px 0;"><strong style="color:#1DB954;">Künstler:</strong> <span style="color:#e0e0e0;">{{ track.artists[0].name | clean }}</span></p>
<p style="margin:8px 0;"><strong style="color:#1DB954;">Album:</strong> <span style="color:#e0e0e0;">{{ track.album.name | clean }}</span></p>
<a href="{{ track.external_urls.spotify }}" target="_blank" style="display:inline-block; margin-top:10px; padding:8px 16px; background:linear-gradient(135deg, #1DB954 0%, #1ed760 100%); color:#fff; text-decoration:none; border-radius:20px; font-weight:600;">Auf Spotify öffnen</a>
</div>
</div>
`;
document.getElementById('nextQuestionBtn').style.display = 'inline-block';
document.getElementById('nextQuestionBtn').onclick = function() {
// Wende Punkte beim Klick auf "Nächster Song" an
players[currentBuzzer - 1].score += pendingPoints;
updateScoreboard();
window.location.href = '/quiz/{{ playlist_id }}?mode={{ game_mode }}&buzzer=1&local_multiplayer=1';
};
} else {
// Minuspunkte: 25% der möglichen Punkte
const minusPoints = Math.floor(window.earnedPoints * 0.25);
pendingPoints = -minusPoints;
resultContainer.innerHTML = `
<div style="background:linear-gradient(135deg, rgba(244, 67, 54, 0.2) 0%, rgba(211, 47, 47, 0.2) 100%); padding:20px; border-radius:12px; border:2px solid #f44336;">
<h3 style="color:#f44336; margin-bottom:10px;">❌ Falsch</h3>
<p style="font-size:1.1em; margin:10px 0;">Deine Antwort: <strong style="color:#f44336;">${guess}</strong></p>
<p style="font-size:1.1em; margin:10px 0;"><strong style="color:#f44336;">-${minusPoints}</strong> Punkte für ${players[currentBuzzer - 1].name}</p>
<div style="margin-top:20px;">
<button class="btn" onclick="continueGame()" style="background:linear-gradient(135deg, #FFA500 0%, #FF8C00 100%);">🔄 Weiterbuzzern</button>
<button class="btn" onclick="showSolution()" style="background:linear-gradient(135deg, #1DB954 0%, #1ed760 100%);">📝 Lösung anzeigen</button>
</div>
</div>
`;
}
})
.catch(error => {
console.error('Error checking answer:', error);
});
}
function continueGame() {
// Wende Minuspunkte an
players[currentBuzzer - 1].score += pendingPoints;
updateScoreboard();
// Reset für nächsten Buzzer
document.getElementById('answerSection').classList.remove('active');
document.getElementById('answerInput').value = '';
document.getElementById('answerInput').disabled = false;
document.querySelector('button[onclick="checkAnswer()"]').disabled = false;
document.getElementById('resultContainer').innerHTML = '';
document.getElementById(`player${currentBuzzer}`).classList.remove('buzzed');
currentBuzzer = null;
canBuzz = true;
// Musik weiterspielen
if (window.spotifyPlayer) {
window.spotifyPlayer.resume();
}
// Timer weiterlaufen lassen (von der aktuellen Zeit)
// Keine Anpassung der startTime nötig, da die Zeit einfach weiterläuft
buzzTimer = requestAnimationFrame(updateTimer);
}
function showSolution() {
// Wende Minuspunkte an
players[currentBuzzer - 1].score += pendingPoints;
updateScoreboard();
const resultContainer = document.getElementById('resultContainer');
resultContainer.innerHTML = `
<div style="margin-top:20px; padding:20px; background:rgba(15,20,25,0.8); border-radius:12px; border:2px solid #1DB954;">
<h4 style="color:#1DB954; margin-bottom:15px;">Lösung:</h4>
<p style="margin:8px 0;"><strong style="color:#1DB954;">Titel:</strong> <span style="color:#e0e0e0;">{{ track.name | clean }}</span></p>
<p style="margin:8px 0;"><strong style="color:#1DB954;">Künstler:</strong> <span style="color:#e0e0e0;">{{ track.artists[0].name | clean }}</span></p>
<p style="margin:8px 0;"><strong style="color:#1DB954;">Album:</strong> <span style="color:#e0e0e0;">{{ track.album.name | clean }}</span></p>
<a href="{{ track.external_urls.spotify }}" target="_blank" style="display:inline-block; margin-top:10px; padding:8px 16px; background:linear-gradient(135deg, #1DB954 0%, #1ed760 100%); color:#fff; text-decoration:none; border-radius:20px; font-weight:600;">Auf Spotify öffnen</a>
</div>
`;
document.getElementById('nextQuestionBtn').style.display = 'inline-block';
}
function switchGameMode(mode) {
window.location.href = `/reset_quiz/{{ playlist_id }}?next_mode=${mode}&buzzer=1&local_multiplayer=1`;
}
function getOption(key, defaultValue) {
return localStorage.getItem(key) || defaultValue;
}
window.onload = function() {
document.getElementById('startPosition').value = getOption('startPosition', 'start');
maxPoints = parseInt(localStorage.getItem('buzzer_max_points')) || 1000;
gracePeriod = parseInt(localStorage.getItem('buzzer_grace_period')) || 5;
decayRate = parseInt(localStorage.getItem('buzzer_decay_rate')) || 50;
document.getElementById('pointsDisplay').textContent = maxPoints + ' Punkte';
};
</script>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div class="quiz-container">
<!-- Scoreboard -->
<div class="scoreboard">
<div class="player-card" id="player1">
<div class="player-name">Spieler 1</div>
<div class="player-score">0</div>
</div>
<div class="player-card" id="player2">
<div class="player-name">Spieler 2</div>
<div class="player-score">0</div>
</div>
<div class="player-card" id="player3">
<div class="player-name">Spieler 3</div>
<div class="player-score">0</div>
</div>
<div class="player-card" id="player4">
<div class="player-name">Spieler 4</div>
<div class="player-score">0</div>
</div>
</div>
<input type="hidden" id="device_id" value="">
<h2 id="question-text" style="text-align:center; margin:20px 0;">{{ translations['question_title'] }}</h2>
<!-- Timer & Points Display -->
<div class="buzzer-timer" id="buzzerTimer">0.00s</div>
<div class="points-display high" id="pointsDisplay">1000 Punkte</div>
<div class="current-player" id="currentPlayer">Drücke START um zu beginnen</div>
<!-- Buzzer Hint -->
<div id="buzzerHint" style="text-align:center; font-size:1.5em; color:#1DB954; margin:20px 0; display:none;">
⌨️ Drücke LEERTASTE zum Buzzern!
</div>
<!-- Player Selection (versteckt bis gebuzzert) -->
<div id="playerSelection" style="display:none; text-align:center; margin:30px 0;">
<h3 style="margin-bottom:20px; color:#1DB954;">Wer hat gebuzzert?</h3>
<div class="buzzer-grid">
<button class="player-buzzer" id="selectPlayer1" onclick="selectPlayer(1)">Spieler 1</button>
<button class="player-buzzer" id="selectPlayer2" onclick="selectPlayer(2)">Spieler 2</button>
<button class="player-buzzer" id="selectPlayer3" onclick="selectPlayer(3)">Spieler 3</button>
<button class="player-buzzer" id="selectPlayer4" onclick="selectPlayer(4)">Spieler 4</button>
</div>
</div>
<!-- START Button -->
<div style="text-align:center; margin:30px 0;">
<button class="player-buzzer start" id="startButton" onclick="startGame()">
▶️<br>START
</button>
</div>
<!-- Answer Section -->
<div class="answer-section" id="answerSection">
<h3 style="margin-bottom:15px;">{{ translations['enter_answer'] if translations.get('enter_answer') else 'Enter your answer' }}:</h3>
<input type="text" id="answerInput" placeholder="{{ translations['input_title'] }}" oninput="searchTracks()">
<button class="btn" onclick="checkAnswer()">{{ translations['answer_button'] if translations.get('answer_button') else 'Submit' }}</button>
<div id="searchResults" class="search-results"></div>
<div id="resultContainer" class="result-container"></div>
<a id="nextQuestionBtn" href="/quiz/{{ playlist_id }}?mode={{ game_mode }}&buzzer=1&local_multiplayer=1" class="btn" style="display: none; margin-top:15px;">{{ translations['next_question'] if translations.get('next_question') else 'Next Question' }}</a>
</div>
<!-- Game Mode Switcher -->
<div style="text-align:center; margin-top:30px;">
<button class="btn {{ 'btn-success' if game_mode == 'artist' else 'btn-secondary' }}" onclick="switchGameMode('artist')">{{ translations['guess_artist'] }}</button>
<button class="btn {{ 'btn-success' if game_mode == 'title' else 'btn-secondary' }}" onclick="switchGameMode('title')">{{ translations['guess_title'] }}</button>
<button class="btn {{ 'btn-success' if game_mode == 'year' else 'btn-secondary' }}" onclick="switchGameMode('year')">{{ translations['guess_year'] }}</button>
</div>
<!-- Navigation -->
<div style="text-align:center; margin-top:30px;">
<a href="/reset_scores/{{ playlist_id }}?mode={{ game_mode }}&buzzer=1&local_multiplayer=1" class="btn" style="background:linear-gradient(135deg, #FFA500 0%, #FF8C00 100%);" onclick="return confirm('Alle Punkte zurücksetzen?')">🔄 Punkte zurücksetzen</a>
<a href="/reset_quiz/{{ playlist_id }}?buzzer=1&local_multiplayer=1" class="btn btn-danger">{{ translations['end_quiz'] if translations.get('end_quiz') else '🏁 End Quiz' }}</a>
<a href="/playlists" class="btn btn-secondary">{{ translations['back_to_playlists'] if translations.get('back_to_playlists') else '⬅️ Back' }}</a>
</div>
</div>
</body>
</html>