Files
hitstar/public/js/handlers.js
Elmar Kresse 74d9ae81e6
All checks were successful
Build and Push Docker Image / docker (push) Successful in 7s
refactor: remove debug logging from handleConnected and renderRoom functions
2025-09-05 15:26:16 +02:00

228 lines
6.5 KiB
JavaScript
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.
import {
$answerResult,
$audio,
$guessArtist,
$guessTitle,
$npArtist,
$npTitle,
$npYear,
} from './dom.js';
import { state } from './state.js';
import { cacheLastRoomId, cacheSessionId, sendMsg } from './ws.js';
import { renderRoom } from './render.js';
import { applySync } from './audio.js';
function updatePlayerIdFromRoom(r) {
try {
if (r?.players?.length === 1) {
const only = r.players[0];
if (only && only.id && only.id !== state.playerId) {
state.playerId = only.id;
try {
localStorage.setItem('playerId', only.id);
} catch {}
}
}
} catch {}
}
function shortName(id) {
if (!id) return '-';
const p = state.room?.players.find((x) => x.id === id);
return p ? p.name : id.slice(0, 4);
}
export function handleConnected(msg) {
state.playerId = msg.playerId;
try {
if (msg.playerId) localStorage.setItem('playerId', msg.playerId);
} catch {}
if (msg.sessionId) {
const existing = localStorage.getItem('sessionId');
if (!existing) cacheSessionId(msg.sessionId);
}
// lazy import to avoid cycle
import('./session.js').then(({ reusePlayerName, reconnectLastRoom }) => {
reusePlayerName();
reconnectLastRoom();
});
if (state.room) {
try {
updatePlayerIdFromRoom(state.room);
renderRoom(state.room);
} catch {}
}
}
export function handleRoomUpdate(msg) {
if (msg?.room?.id) cacheLastRoomId(msg.room.id);
const r = msg.room;
updatePlayerIdFromRoom(r);
renderRoom(r);
}
export function handlePlayTrack(msg) {
const t = msg.track;
state.lastTrack = t;
state.revealed = false;
$npTitle.textContent = '???';
$npArtist.textContent = '';
$npYear.textContent = '';
if ($guessTitle) $guessTitle.value = '';
if ($guessArtist) $guessArtist.value = '';
if ($answerResult) {
$answerResult.textContent = '';
$answerResult.className = 'mt-1 text-sm';
}
try {
$audio.preload = 'auto';
} catch {}
$audio.src = t.url;
const pf = document.getElementById('progressFill');
if (pf) pf.style.width = '0%';
const rd = document.getElementById('recordDisc');
if (rd) {
rd.classList.remove('spin-record');
rd.src = '/hitstar.png';
}
const { startAt, serverNow } = msg;
const now = Date.now();
const offsetMs = startAt - serverNow;
const localStart = now + offsetMs;
const delay = Math.max(0, localStart - now);
setTimeout(() => {
$audio.currentTime = 0;
$audio.play().catch(() => {});
const disc = document.getElementById('recordDisc');
if (disc) disc.classList.add('spin-record');
}, delay);
if (state.room) renderRoom(state.room);
}
export function handleSync(msg) {
applySync(msg.startAt, msg.serverNow);
}
export function handleControl(msg) {
const { action, startAt, serverNow } = msg;
if (action === 'pause') {
$audio.pause();
const disc = document.getElementById('recordDisc');
if (disc) disc.classList.remove('spin-record');
$audio.playbackRate = 1.0;
} else if (action === 'play') {
if (startAt && serverNow) {
const now = Date.now();
const elapsed = (now - startAt) / 1000;
$audio.currentTime = Math.max(0, elapsed);
}
$audio.play().catch(() => {});
const disc = document.getElementById('recordDisc');
if (disc) disc.classList.add('spin-record');
}
}
export function handleReveal(msg) {
const { result, track } = msg;
$npTitle.textContent = track.title || track.id || 'Track';
$npArtist.textContent = track.artist ? ` ${track.artist}` : '';
$npYear.textContent = track.year ? ` (${track.year})` : '';
state.revealed = true;
const $rb = document.getElementById('revealBanner');
if ($rb) {
if (result.correct) {
$rb.textContent = 'Richtig!';
$rb.className =
'inline-block rounded-md bg-emerald-600 text-white px-3 py-1 text-sm font-medium';
} else {
$rb.textContent = 'Falsch!';
$rb.className =
'inline-block rounded-md bg-rose-600 text-white px-3 py-1 text-sm font-medium';
}
}
const $placeArea = document.getElementById('placeArea');
if ($placeArea) $placeArea.classList.add('hidden');
const rd = document.getElementById('recordDisc');
if (rd && track?.id) {
const coverUrl = `/cover/${encodeURIComponent(track.id)}`;
const img = new Image();
img.onload = () => {
rd.src = coverUrl;
};
img.onerror = () => {
/* keep default logo */
};
img.src = `${coverUrl}?t=${Date.now()}`;
}
}
export function handleGameEnded(msg) {
alert(`Gewinner: ${shortName(msg.winner)}`);
}
export function onMessage(ev) {
const msg = JSON.parse(ev.data);
switch (msg.type) {
case 'resume_result': {
if (msg.ok) {
if (msg.playerId) {
state.playerId = msg.playerId;
try {
localStorage.setItem('playerId', msg.playerId);
} catch {}
}
const code = msg.roomId || state.room?.id || localStorage.getItem('lastRoomId');
if (code) sendMsg({ type: 'join_room', code });
if (state.room) {
try {
renderRoom(state.room);
} catch {}
}
} else {
const code = state.room?.id || localStorage.getItem('lastRoomId');
if (code) sendMsg({ type: 'join_room', code });
}
return;
}
case 'connected':
return handleConnected(msg);
case 'room_update':
return handleRoomUpdate(msg);
case 'play_track':
return handlePlayTrack(msg);
case 'sync':
return handleSync(msg);
case 'control':
return handleControl(msg);
case 'reveal':
return handleReveal(msg);
case 'game_ended':
return handleGameEnded(msg);
case 'answer_result': {
if ($answerResult) {
if (!msg.ok) {
$answerResult.textContent = '⛔ Eingabe ungültig oder gerade nicht möglich';
$answerResult.className = 'mt-1 text-sm text-rose-600';
} else {
const okBoth = !!(msg.correctTitle && msg.correctArtist);
const parts = [];
parts.push(msg.correctTitle ? 'Titel ✓' : 'Titel ✗');
parts.push(msg.correctArtist ? 'Künstler ✓' : 'Künstler ✗');
let coin = '';
if (msg.awarded) coin = ' +1 Token';
else if (msg.alreadyAwarded) coin = ' (bereits erhalten)';
$answerResult.textContent = `${parts.join(' · ')}${coin}`;
$answerResult.className = okBoth
? 'mt-1 text-sm text-emerald-600'
: 'mt-1 text-sm text-amber-600';
}
}
return;
}
default:
return;
}
}