Introduce architettura multi-sport con catalogo, engine scoring e overlay.

Catalogo sport in YAML, board implicito, engine per volley/basket/timed/racket/timer/generic, regia e app Android allineate.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-09 20:11:21 +02:00
parent 53f9a6a884
commit e727069d43
56 changed files with 1783 additions and 223 deletions

View File

@@ -4,6 +4,7 @@
const cfg = {
token: root.dataset.token,
board: root.dataset.board || "volley",
statusUrl: root.dataset.statusUrl,
scoreUrl: root.dataset.scoreUrl,
pauseUrl: root.dataset.pauseUrl,
@@ -88,26 +89,52 @@
.join(" · ");
}
function formatClock(secs, countUp) {
const total = parseInt(secs, 10) || 0;
if (total <= 0 && !countUp) return "0:00";
const m = Math.floor(total / 60);
const s = total % 60;
return `${m}:${String(s).padStart(2, "0")}`;
}
function applyScorePayload(data) {
const s = data.score;
if (!s) return;
const homePts = s.home_points ?? s.homePoints;
const awayPts = s.away_points ?? s.awayPoints;
const board = s.board_type || s.boardType || cfg.board;
const homePts = s.home_points ?? s.homePoints ?? 0;
const awayPts = s.away_points ?? s.awayPoints ?? 0;
const homeSets = s.home_sets ?? s.homeSets;
const awaySets = s.away_sets ?? s.awaySets;
const currentSet = s.current_set ?? s.currentSet;
const period = s.period;
const clockSecs = s.clock_secs ?? s.clockSecs ?? s.data?.clock_secs;
const awayEl = document.getElementById("away-points");
els.homePoints.textContent = homePts;
if (awayEl) awayEl.textContent = awayPts;
els.setsLine.textContent = `Set ${currentSet} · Set vinti ${homeSets}-${awaySets}`;
els.scoreLine.textContent = `${cfg.homeName} ${homePts} - ${awayPts} ${cfg.awayName}`;
const centerHint = document.getElementById("center-hint");
const clockLine = document.getElementById("clock-line");
const partialsText = formatPartials(s.set_partials || s.setPartials);
if (partialsText) {
els.partialsLine.textContent = `Parziali: ${partialsText}`;
els.partialsLine.hidden = false;
if (els.homePoints) els.homePoints.textContent = homePts;
if (awayEl) awayEl.textContent = awayPts;
if (board === "basket" || board === "timed") {
if (els.setsLine) els.setsLine.textContent = period || "—";
if (els.scoreLine) els.scoreLine.textContent = `${cfg.homeName} ${homePts} - ${awayPts} ${cfg.awayName}`;
if (centerHint) centerHint.textContent = formatClock(clockSecs);
if (clockLine) clockLine.textContent = `Cronometro: ${formatClock(clockSecs)}`;
} else if (board === "timer") {
if (els.setsLine) els.setsLine.textContent = "Cronometro";
if (clockLine) clockLine.textContent = formatClock(clockSecs, true);
} else if (board === "generic") {
if (els.setsLine) els.setsLine.textContent = "Punteggio libero";
if (els.scoreLine) els.scoreLine.textContent = `${cfg.homeName} ${homePts} - ${awayPts} ${cfg.awayName}`;
} else {
if (els.setsLine) els.setsLine.textContent = `Set ${currentSet} · Set vinti ${homeSets}-${awaySets}`;
if (els.scoreLine) els.scoreLine.textContent = `${cfg.homeName} ${homePts} - ${awayPts} ${cfg.awayName}`;
const partialsText = formatPartials(s.set_partials || s.setPartials);
if (els.partialsLine && partialsText) {
els.partialsLine.textContent = `Parziali: ${partialsText}`;
els.partialsLine.hidden = false;
}
}
}
@@ -157,10 +184,13 @@
applyScorePayload(data);
setBadge(data);
if (data.set_won && action !== "close_set") {
const winner = data.winner === "home" ? cfg.homeName : cfg.awayName;
openModal("Set vinto", `${winner} ha vinto il set. Chiudere il set?`, () => postScore("close_set"));
} else if (data.match_won) {
if (cfg.board === "volley" || cfg.board === "racket") {
if (data.set_won && action !== "close_set") {
const winner = data.winner === "home" ? cfg.homeName : cfg.awayName;
openModal("Set vinto", `${winner} ha vinto il set. Chiudere il set?`, () => postScore("close_set"));
}
}
if (data.match_won) {
const winner = data.winner === "home" ? cfg.homeName : cfg.awayName;
openModal("Partita vinta", `${winner} ha vinto la partita. Chiudere la diretta?`, () => stopStream());
}