From 867d3c96b1e08307bc900d1a0400542363bdaa59 Mon Sep 17 00:00:00 2001 From: Andreas Knuth Date: Sat, 4 Jul 2026 10:17:41 -0500 Subject: [PATCH] goals --- lib/feeds.ts | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/feeds.ts b/lib/feeds.ts index abf9e81..6e06134 100644 --- a/lib/feeds.ts +++ b/lib/feeds.ts @@ -670,18 +670,11 @@ function normMinuteStr(min: string | null | undefined): string { return (min ?? "").replace(/'/g, "").replace(/\s+/g, "").trim(); } -const RECENT_FINISHED_MS = 60 * 60 * 1000; // 60 Minuten -const MATCH_DURATION_ESTIMATE = 2.5 * 60 * 60 * 1000; // 2.5h Puffer für Spiel + Pause + Nachspielzeit - -function isRecentlyFinished(m: Match): boolean { - if (m.status !== "FINISHED") return false; - const kickoff = new Date(m.utcDate).getTime(); - if (isNaN(kickoff)) return false; - return kickoff + MATCH_DURATION_ESTIMATE > Date.now() - RECENT_FINISHED_MS; -} - -async function fetchFifaGoals(idStage: string, idMatch: string, locale: string = "de"): Promise { - return cached(`fifa:detail:${locale}:${idMatch}`, 60_000, async () => { +async function fetchFifaGoals( + idStage: string, idMatch: string, locale: string = "de", + ttlMs: number = 60_000, +): Promise { + return cached(`fifa:detail:${locale}:${idMatch}`, ttlMs, async () => { const lang = locale === "en" ? "en" : "de"; const url = `${FIFA_BASE}/live/football/17/${FIFA_SEASON}/${idStage}/${idMatch}?language=${lang}`; const res = await fetch(url, { @@ -724,16 +717,16 @@ async function fetchFifaGoals(idStage: string, idMatch: string, locale: string = }); } -// Lädt Tor-Details für laufende oder kürzlich beendete Spiele mit Toren. -// FINISHED-Matches werden nur innerhalb eines 60-Minuten-Fensters berücksichtigt, -// um die Request-Zahl bei 79+ Spielen im Turnierverlauf drastisch zu reduzieren. +// Lädt Tor-Details für laufende und alle beendeten Spiele mit Toren. +// Beendete Spiele werden über langlebiges Caching (24h) gespart, nicht über Ausschluss. +// Tore eines beendeten Spiels ändern sich nie mehr → einmal fetchen genügt. export async function attachFifaGoals( matches: Match[], fifaData: { scores: Map; fifaIdToAppCode: Map }, locale: string = "de", ): Promise { const targets = matches.filter(m => - ((m.status === "LIVE" || m.status === "IN_PLAY" || m.status === "PAUSED") || isRecentlyFinished(m)) && + (m.status === "LIVE" || m.status === "IN_PLAY" || m.status === "PAUSED" || m.status === "FINISHED") && ((m.homeScore ?? 0) + (m.awayScore ?? 0)) > 0, ); if (targets.length === 0) return matches; @@ -742,7 +735,9 @@ export async function attachFifaGoals( const results = await Promise.allSettled(targets.map(async (m) => { const fs = fifaData.scores.get(m.matchNumber); if (!fs?.idMatch || !fs?.idStage) return; - const goals = await fetchFifaGoals(fs.idStage, fs.idMatch, locale); + const isFinished = m.status === "FINISHED"; + const ttl = isFinished ? 24 * 60 * 60 * 1000 : 60_000; + const goals = await fetchFifaGoals(fs.idStage, fs.idMatch, locale, ttl); if (goals.length) goalsByMatchId.set(m.id, goals); })); @@ -787,11 +782,14 @@ export async function attachFifaLiveData( // --- Step 2: Scores auf Matches anwenden --- const updated = applyFifaScores(matches, teams, fifaData); - // --- Step 3: Goal-Details nur für live + kürzlich beendete Matches mit Toren --- + // --- Step 3: Goal-Details für alle Spiele mit Toren (live + beendet) --- + // Requests werden durch differenzierte Cache-TTL gespart: + // beendete Spiele → 24h (Tore ändern sich nie) + // laufende Spiele → 60s (neue Tore erscheinen) const targets = updated.filter(m => { const fs = fifaData.scores.get(m.matchNumber); return ( - ((m.status === "LIVE" || m.status === "IN_PLAY" || m.status === "PAUSED") || isRecentlyFinished(m)) && + (m.status === "LIVE" || m.status === "IN_PLAY" || m.status === "PAUSED" || m.status === "FINISHED") && ((m.homeScore ?? 0) + (m.awayScore ?? 0)) > 0 && fs?.idMatch != null && fs?.idStage != null @@ -810,8 +808,10 @@ export async function attachFifaLiveData( for (const m of targets) { const fs = fifaData.scores.get(m.matchNumber)!; if (!fs.idMatch || !fs.idStage) continue; + const isFinished = m.status === "FINISHED"; + const ttl = isFinished ? 24 * 60 * 60 * 1000 : 60_000; // beendet: 24h, live: 60s try { - const goals = await fetchFifaGoals(fs.idStage, fs.idMatch, locale); + const goals = await fetchFifaGoals(fs.idStage, fs.idMatch, locale, ttl); fetched++; if (goals.length) goalsByMatchId.set(m.id, goals); } catch {