169 lines
6.3 KiB
JavaScript
169 lines
6.3 KiB
JavaScript
/**
|
||
* Lara Kiesewetter – Live Schachturnier
|
||
* Data fetching, PGN loading, standings, auto-refresh
|
||
*/
|
||
|
||
/* global parsePGN, filterLaraGames, getLiveGame, getTodaysGames, getLatestGame */
|
||
|
||
async function fetchRoundPGN(round) {
|
||
const res = await fetch(`https://www.deutsche-schachjugend.de/2026/odjm-d/partien/${round}.pgn?t=${Date.now()}`);
|
||
if (!res.ok) return null;
|
||
const buf = await res.arrayBuffer();
|
||
let text = new TextDecoder('utf-8').decode(buf);
|
||
if (text.includes('\uFFFD')) {
|
||
text = new TextDecoder('iso-8859-1').decode(buf);
|
||
}
|
||
return text;
|
||
}
|
||
|
||
async function loadPGN(showOverlay = true) {
|
||
const currentPollId = pollId;
|
||
if (showOverlay) showLoading(true);
|
||
hideError();
|
||
|
||
try {
|
||
if (currentRound === 0) {
|
||
if (showOverlay) showLoading(false);
|
||
return;
|
||
}
|
||
|
||
const maxRound = currentRound + 1;
|
||
const isFirstLoad = Object.keys(roundPgns).length === 0;
|
||
const startRound = isFirstLoad ? 1 : currentRound;
|
||
for (let r = startRound; r <= maxRound; r++) {
|
||
const text = await fetchRoundPGN(r);
|
||
if (currentPollId !== pollId) return;
|
||
if (text !== null) roundPgns[r] = text;
|
||
}
|
||
|
||
const combinedPgn = Object.values(roundPgns).join('\n\n');
|
||
const allGames = parsePGN(combinedPgn);
|
||
allLaraGames = filterLaraGames(allGames);
|
||
|
||
if (allLaraGames.length === 0) {
|
||
return;
|
||
}
|
||
|
||
if (!userSelectedGame) {
|
||
const liveGame = getLiveGame(allLaraGames);
|
||
const todaysGames = getTodaysGames(allLaraGames);
|
||
currentGame = liveGame || (todaysGames.length > 0 ? getLatestGame(todaysGames) : getLatestGame(allLaraGames));
|
||
}
|
||
updateBoard();
|
||
updatePlayerInfo();
|
||
updateMovesList();
|
||
updateAllGamesList();
|
||
updatePGNDisplay();
|
||
updateTimestamp();
|
||
|
||
showLoading(false);
|
||
|
||
} catch (error) {
|
||
if (currentPollId !== pollId) return;
|
||
console.error('Fehler beim Laden:', error);
|
||
showLoading(false);
|
||
}
|
||
}
|
||
|
||
async function updateStandings() {
|
||
try {
|
||
const res = await fetch(`https://www.deutsche-schachjugend.de/2026/odjm-d/tabelle/?t=${Date.now()}`);
|
||
if (!res.ok) throw new Error('Fehler beim Laden');
|
||
const html = await res.text();
|
||
|
||
const roundMatch = html.match(/Tabellenstand\s+nach\s+der\s+(\d+)\.\s*Runde/);
|
||
if (roundMatch) {
|
||
currentRound = parseInt(roundMatch[1]);
|
||
}
|
||
|
||
const rows = html.matchAll(/<tr[^>]*>(.*?)<\/tr>/gs);
|
||
for (const row of rows) {
|
||
if (!row[1].includes('Lara Kiesewetter')) continue;
|
||
|
||
const cells = row[1].matchAll(/<td[^>]*>(.*?)<\/td>/gs);
|
||
const clean = [];
|
||
for (const cell of cells) {
|
||
clean.push(cell[1].replace(/<[^>]+>/g, '').trim());
|
||
}
|
||
|
||
if (clean.length >= 9) {
|
||
const data = {
|
||
rank: clean[0],
|
||
player: 'Lara Kiesewetter',
|
||
wins: clean[5],
|
||
draws: clean[6],
|
||
losses: clean[7],
|
||
points: clean[8],
|
||
round_info: roundMatch ? `nach der ${roundMatch[1]}. Runde` : '',
|
||
round: currentRound,
|
||
};
|
||
const container = document.getElementById('standings-content');
|
||
container.innerHTML = `
|
||
<div class="standings-rank">${data.rank}.</div>
|
||
<div class="standings-rank-label"><a href="https://www.deutsche-schachjugend.de/2026/odjm-d/tabelle/" target="_blank" rel="noopener">Tabellenplatz</a></div>
|
||
<div class="standings-header">${data.round_info || 'nach Runde 1'}</div>
|
||
<div class="standings-row">
|
||
<span class="standings-label">Punkte</span>
|
||
<span class="standings-value">${data.points}</span>
|
||
</div>
|
||
<div class="standings-row">
|
||
<span class="standings-label">Siege</span>
|
||
<span class="standings-value">${data.wins}</span>
|
||
</div>
|
||
<div class="standings-row">
|
||
<span class="standings-label">Unentschieden</span>
|
||
<span class="standings-value">${data.draws}</span>
|
||
</div>
|
||
<div class="standings-row">
|
||
<span class="standings-label">Niederlagen</span>
|
||
<span class="standings-value">${data.losses}</span>
|
||
</div>
|
||
`;
|
||
return;
|
||
}
|
||
}
|
||
document.getElementById('standings-content').innerHTML = '<div class="standings-loading">Daten nicht verfügbar</div>';
|
||
} catch {
|
||
document.getElementById('standings-content').innerHTML = '<div class="standings-loading">Daten nicht verfügbar</div>';
|
||
}
|
||
}
|
||
|
||
function updateTimestamp() {
|
||
const time = new Date();
|
||
document.getElementById('last-update').textContent =
|
||
`Letztes Update: ${time.toLocaleTimeString('de-DE')}`;
|
||
}
|
||
|
||
async function startAutoRefresh() {
|
||
clearInterval(pollInterval);
|
||
clearInterval(updateTimer);
|
||
clearInterval(standingsInterval);
|
||
|
||
const myId = ++pollId;
|
||
let lastUpdate = Date.now();
|
||
|
||
document.getElementById('refresh-timer').textContent = '0s';
|
||
document.getElementById('refresh-timer').style.color = '#4ade80';
|
||
|
||
await updateStandings();
|
||
loadPGN(true);
|
||
|
||
pollInterval = setInterval(() => {
|
||
if (pollId !== myId) { clearInterval(pollInterval); clearInterval(updateTimer); clearInterval(standingsInterval); return; }
|
||
loadPGN(false);
|
||
lastUpdate = Date.now();
|
||
}, 15000);
|
||
|
||
updateTimer = setInterval(() => {
|
||
if (pollId !== myId) { clearInterval(pollInterval); clearInterval(updateTimer); clearInterval(standingsInterval); return; }
|
||
const elapsed = Date.now() - lastUpdate;
|
||
const remaining = Math.max(0, 15000 - elapsed);
|
||
const s = Math.floor(remaining / 1000);
|
||
document.getElementById('refresh-timer').textContent = `${s}s`;
|
||
}, 1000);
|
||
|
||
standingsInterval = setInterval(() => {
|
||
if (pollId !== myId) { clearInterval(pollInterval); clearInterval(updateTimer); clearInterval(standingsInterval); return; }
|
||
updateStandings();
|
||
}, 1800000);
|
||
} |