Sports: per-league fetch windows (sportsball parity), drop daysAhead
2d5ec4c83c25b0c36c8e2fcbae52bf9a482a81dc
humdrum <me@humdrum.me> · 2026-07-08 16:05
parent 59a52605
2 files changed
lib/schemas/sources/sports.ts +0 −2
@@ -12,8 +12,6 @@ leagues: z.array(z.string()).default(["basketball/nba"]),
// Favorite teams — only these teams' games are added, even from leagues not
// listed above. So you can keep all of one league + single teams from others.
teams: z.array(SportsTeam).default([]),
- // How many days ahead to fetch schedules (0 = today only).
- daysAhead: z.number().int().min(0).max(14).default(7),
});
export type SportsConfig = z.infer<typeof SportsConfig>;
lib/sources/modules/sports.ts +28 −10
@@ -21,6 +21,32 @@ }
const gameKey = (g: Game) => `${g.league}|${g.away}|${g.home}|${g.startTime ?? ""}`;
+// Per-league fetch windows (days back / forward), mirrored from the sportsball TUI's
+// league catalog (~/Developer/Home/sportsball internal/model/league.go). Tuned to each
+// sport's cadence so the last result and the next game both surface. Unknown leagues use
+// a modest default.
+const LEAGUE_WINDOWS: Record<string, { back: number; forward: number }> = {
+ "soccer/fifa.world": { back: 7, forward: 7 },
+ "baseball/mlb": { back: 2, forward: 3 },
+ "basketball/nba": { back: 3, forward: 4 },
+ "basketball/wnba": { back: 3, forward: 4 },
+ "hockey/nhl": { back: 3, forward: 4 },
+ "football/nfl": { back: 8, forward: 8 },
+};
+const DEFAULT_WINDOW = { back: 1, forward: 7 };
+
+// YYYYMMDD strings spanning one league's window, oldest first.
+function windowDates(league: string): string[] {
+ const w = LEAGUE_WINDOWS[league] ?? DEFAULT_WINDOW;
+ const out: string[] = [];
+ for (let off = -w.back; off <= w.forward; off++) {
+ const d = new Date();
+ d.setDate(d.getDate() + off);
+ out.push(d.toISOString().slice(0, 10).replace(/-/g, ""));
+ }
+ return out;
+}
+
export const sportsModule: SourceModule<Config, Payload> = {
kind: "sports",
label: "Scores",
@@ -33,14 +59,6 @@ isConfigured: (config) => config.leagues.length > 0 || config.teams.length > 0,
async fetch({ config, signal }) {
const collected = new Map<string, Game>();
-
- // Build YYYYMMDD strings for today + daysAhead days.
- function dateStr(offsetDays: number): string {
- const d = new Date();
- d.setDate(d.getDate() + offsetDays);
- return d.toISOString().slice(0, 10).replace(/-/g, "");
- }
- const dates = Array.from({ length: (config.daysAhead ?? 7) + 1 }, (_, i) => dateStr(i));
// Fetch one league's scoreboard for a given date. If teamFilter is given,
// keep only games whose home/away matches one of those team substrings.
@@ -84,8 +102,8 @@ byLeague.set(league, [...(byLeague.get(league) ?? []), team]);
}
await Promise.all([
- ...config.leagues.flatMap((l) => dates.map((d) => collect(l, d))),
- ...[...byLeague].flatMap(([l, teams]) => dates.map((d) => collect(l, d, teams))),
+ ...config.leagues.flatMap((l) => windowDates(l).map((d) => collect(l, d))),
+ ...[...byLeague].flatMap(([l, teams]) => windowDates(l).map((d) => collect(l, d, teams))),
]);
const games = [...collected.values()].sort(