mirror of
https://github.com/fabrice404/olympics-calendar.git
synced 2025-12-13 06:39:47 +00:00
121 lines
3.9 KiB
TypeScript
121 lines
3.9 KiB
TypeScript
import Debug from "debug";
|
|
import { mkdirSync, writeFileSync } from "fs";
|
|
|
|
import { getFlag } from "./nocs";
|
|
import { Calendar } from "./types";
|
|
|
|
export class ICSGenerator {
|
|
private calendar: Calendar;
|
|
|
|
private debug = Debug("olympics-calendar:ics-generator");
|
|
|
|
constructor(calendar: Calendar) {
|
|
this.calendar = calendar;
|
|
}
|
|
|
|
private generateICSFile(
|
|
sportKey: string | null,
|
|
nocKey: string | null,
|
|
): void {
|
|
this.debug(
|
|
"generateICSFile",
|
|
sportKey || "all-sports",
|
|
nocKey || "all-nocs",
|
|
);
|
|
this.calendar.languages.forEach((lang) => {
|
|
const pathSportKey = sportKey ? sportKey : "all-sports";
|
|
const pathNocKey = nocKey ? nocKey : "calendar";
|
|
|
|
const filepath = `./output/${lang.code.toLowerCase()}/${pathSportKey.toLowerCase()}/${pathNocKey.toLowerCase()}.ics`;
|
|
mkdirSync(filepath.split("/").slice(0, -1).join("/"), { recursive: true });
|
|
|
|
const titleComponents = [];
|
|
if (nocKey) {
|
|
titleComponents.push(
|
|
`${this.calendar.nocs.find((n) => n.key === nocKey)!.name[lang.code]}`,
|
|
);
|
|
}
|
|
if (sportKey) {
|
|
titleComponents.push(this.calendar.sports.find((s) => s.key === sportKey)!.name[lang.code]);
|
|
}
|
|
titleComponents.push("Milano Cortina 2026");
|
|
|
|
const title = titleComponents.join(" - ");
|
|
|
|
const lines = [];
|
|
|
|
lines.push("BEGIN:VCALENDAR");
|
|
lines.push("VERSION:2.0");
|
|
lines.push(
|
|
`PRODID:-//fabrice404//olympics-calendar//${lang.code}/${pathSportKey}/${pathNocKey}`,
|
|
);
|
|
lines.push(`X-WR-CALNAME:${title}`);
|
|
lines.push(`NAME:${title}`);
|
|
|
|
this.calendar.events
|
|
.filter((event) => {
|
|
if (sportKey && event.sport !== sportKey) return false;
|
|
if (nocKey) {
|
|
if (event.match) {
|
|
const team1Key = event.match.team1.key;
|
|
const team2Key = event.match.team2.key;
|
|
if (team1Key !== nocKey && team2Key !== nocKey) {
|
|
return false;
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
})
|
|
.forEach((event) => {
|
|
lines.push("BEGIN:VEVENT");
|
|
lines.push(`UID:${event.key.replace(/--/g, "-")}`);
|
|
lines.push(`DTSTAMP:${event.start.replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z")}`);
|
|
lines.push(`DTSTART:${event.start.replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z")}`);
|
|
lines.push(`DTEND:${event.end.replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z")}`);
|
|
lines.push(`LOCATION:${event.location[lang.code] || ""}`);
|
|
|
|
const sport = this.calendar.sports.find(
|
|
(s) => s.key === event.sport,
|
|
)!;
|
|
lines.push(`DESCRIPTION:${sport.name[lang.code]} - ${event.name[lang.code] || ""}`);
|
|
const summary = `SUMMARY:${event.name[lang.code] || ""}`;
|
|
|
|
if (event.match) {
|
|
const team1Name = event.match.team1.name[lang.code] || event.match.team1.key;
|
|
const team1Flag = getFlag(event.match.team1.key);
|
|
const team2Name = event.match.team2.name[lang.code] || event.match.team2.key;
|
|
const team2Flag = getFlag(event.match.team2.key);
|
|
if (team1Name && team2Name) {
|
|
lines.push(`SUMMARY:${team1Flag} ${team1Name} - ${team2Name} ${team2Flag}`);
|
|
}
|
|
}
|
|
|
|
lines.push(summary);
|
|
lines.push("END:VEVENT");
|
|
});
|
|
|
|
lines.push("END:VCALENDAR");
|
|
|
|
writeFileSync(filepath, lines.join("\n"));
|
|
});
|
|
}
|
|
|
|
public generate(): void {
|
|
this.debug("generate");
|
|
this.generateICSFile(null, null);
|
|
|
|
this.calendar.sports.forEach((sport) => {
|
|
this.generateICSFile(sport.key, null);
|
|
this.calendar.nocs.forEach((noc) => {
|
|
this.generateICSFile(sport.key, noc.key);
|
|
});
|
|
});
|
|
|
|
this.calendar.nocs.forEach((noc) => {
|
|
this.generateICSFile(null, noc.key);
|
|
});
|
|
}
|
|
}
|