diff --git a/README.md b/README.md index 0b68e8b1b..3153c0ba5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # Olympics/Paralympics Calendars -This repository contains scripts t -Work in progress for Milano-Cortina 2026 Olympics and Paralympics calendars. +Work in progress for Milano-Cortina 2026 Winter Olympics calendars. > [!NOTE] > Paris 2024 Olympics calendars have been archived to the [2024-paris-olympics](https://github.com/fabrice404/olympics-calendar/tree/2024-paris-olympics) branch.\ diff --git a/scraper/cache.ts b/scraper/cache.ts new file mode 100644 index 000000000..fbd397751 --- /dev/null +++ b/scraper/cache.ts @@ -0,0 +1,30 @@ +import Debug from "debug"; +import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs" + +const debug = Debug(`olympics-calendar:cache`); + +const cachePath = (key: string): string => { + return `../cache/${key}`; +} + +export const get = (key: string): string | null => { + debug(`get: key=${key}`); + const path = cachePath(key); + if (existsSync(path)) { + return readFileSync(path, "utf-8"); + } + return null; +} + +export const has = (key: string): boolean => { + debug(`has: key=${key}`); + const path = cachePath(key); + return existsSync(path); +} + +export const set = (key: string, data: string): void => { + debug(`set: key=${key}`); + const path = cachePath(key); + mkdirSync(path.split("/").slice(0, -1).join("/"), { recursive: true }); + writeFileSync(path, data); +} diff --git a/scraper/eslint.config.mjs b/scraper/eslint.config.mjs new file mode 100644 index 000000000..ddec96ac2 --- /dev/null +++ b/scraper/eslint.config.mjs @@ -0,0 +1,26 @@ +import globals from "globals"; +import pluginJs from "@eslint/js"; + + +export default [ + { + files: ["**/*.js"], + languageOptions: { + sourceType: "commonjs", + }, + }, + { + languageOptions: { + globals: globals.node, + }, + }, + pluginJs.configs.recommended, + { + rules: { + "comma-dangle": ["error", "always-multiline"], + complexity: ["error", 15], + quotes: ["error", "double"], + semi: ["error", "always"], + }, + }, +]; diff --git a/scraper/index.ts b/scraper/index.ts new file mode 100644 index 000000000..cac9b4723 --- /dev/null +++ b/scraper/index.ts @@ -0,0 +1,118 @@ +import Debug from "debug"; + +import * as cache from "./cache"; + +const baseUrl = "https://www.olympics.com"; +const basePath = "/milano-cortina-2026/schedule/overview"; + +const debug = Debug(`olympics-calendar:index`); + +const getScheduleOverview = async (language: string) => { + debug(`getScheduleOverview: language=${language}`); + + const scheduleOverviewKey = `${language}/schedule-overview`; + + if (!cache.has(scheduleOverviewKey)) { + debug(`Fetching ${baseUrl}/${language}${basePath}`); + const response = await fetch(`${baseUrl}/${language}/${basePath}`); + const page = await response.text(); + const dataMatch = page.match(/