mirror of
https://github.com/fabrice404/olympics-calendar.git
synced 2025-12-15 15:49:45 +00:00
wip milano-cortina 2026
This commit is contained in:
@ -4,7 +4,7 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs"
|
||||
const debug = Debug(`olympics-calendar:cache`);
|
||||
|
||||
const cachePath = (key: string): string => {
|
||||
return `../cache/${key}`;
|
||||
return `../cache/${key}.cached`;
|
||||
}
|
||||
|
||||
export const get = (key: string): string | null => {
|
||||
|
||||
150
scraper/ics.ts
Normal file
150
scraper/ics.ts
Normal file
@ -0,0 +1,150 @@
|
||||
// BEGIN:VCALENDAR
|
||||
// VERSION:2.0
|
||||
// PRODID:-//fabrice404//olympics-calendar//archery/AUS//EN
|
||||
// X-WR-CALNAME:🇦🇺 Australia Archery | Paris 2024
|
||||
// NAME:🇦🇺 Australia Archery | Paris 2024
|
||||
// BEGIN:VEVENT
|
||||
// UID:20240725T073000Z-archery-WOMENS-INDIVIDUAL-RANKING-ROUND
|
||||
// DTSTAMP:20240725T073000Z
|
||||
// DTSTART:20240725T073000Z
|
||||
// DTEND:20240725T103000Z
|
||||
// DESCRIPTION:Archery - Women's Individual Ranking Round\n🇨🇳 AN
|
||||
// Qixuan\n🇲🇽 Alejandra VALENCIA\n🇲🇩 Alexandra MIRCA\n🇵🇷 Alondra
|
||||
// RIVERA\n🇫🇷 Amelie CORDEAU\n🇧🇷 Ana Luiza SLIACHTICAS CAETANO\n🇨🇴 Ana
|
||||
// RENDON MARTINEZ\n🇲🇽 Ana VAZQUEZ\n🇲🇽 Angela RUIZ\n🇮🇳 Ankita
|
||||
// BHAKAT\n🇲🇾 Ariana Nur Dania MOHAMAD ZAIRI\n🇮🇳 Bhajan KAUR\n🇬🇧
|
||||
// Bryony PITMAN\n🇹🇼 CHIU Yi-Ching\n🇫🇷 Caroline LOPEZ\n🇺🇸 Casey
|
||||
// KAUFHOLD\n🇺🇸 Catalina GNORIEGA\n🇩🇪 Charline SCHWARZ\n🇮🇹 Chiara
|
||||
// REBAGLIATI\n🇮🇳 Deepika KUMARI\n🇸🇰 Denisa BARANKOVA\n🇮🇩 Diananda
|
||||
// CHOIRUNISA\n🇪🇸 Elia CANALES\n🇹🇷 Elif Berra GOKKIR\n🇦🇹 Elisabeth
|
||||
// STRAKA\n🇬🇳 Fatoumata SYLLA\n🇳🇱 Gaby SCHLOESSER\n🇸🇲 Giorgia
|
||||
// CESARINI\n🇰🇷 JEON Hunyoung\n🇪🇬 Jana ALI\n🇺🇸 Jennifer MUCINO\n🇩🇪
|
||||
// Katharina BAUER\n🇩🇰 Kirstine DANSTRUP ANDERSEN\n🇹🇼 LEI
|
||||
// Chien-Ying\n🇨🇳 LI Jiaman\n🇹🇼 LI Tsai-Chi\n🇰🇷 LIM Sihyeon\n🇦🇺
|
||||
// Laura PAEGLIS\n🇳🇱 Laura van der WINKEL\n🇫🇷 Lisa BARBELIN\n🇷🇴
|
||||
// Madalina AMAISTROAIE\n🇨🇿 Marie HORACKOVA\n🇬🇧 Megs HAVERS\n🇩🇪
|
||||
// Michelle KROPPEN\n🇮🇱 Mikaella MOSHE\n🇮🇷 Mobina FALLAH\n🇰🇷 NAM
|
||||
// Suhyeon\n🇯🇵 NODA Satsuki\n🇲🇾 Nurul Azreena MOHAMAD FAZIL\n🇬🇧 Penny
|
||||
// HEALEY\n🇳🇱 Quinty ROEFFEN\n🇪🇪 Reena PARNAT\n🇮🇩 Rezza OCTAVIA\n🇹🇳
|
||||
// Rihab ELWALID\n🇲🇾 Syaqiera MASHAYIKH\n🇮🇩 Syifa Nurafifah KAMAL\n🇻🇳
|
||||
// Thi Anh Nguyet DO\n🇺🇦 Veronika MARCHENKO\n🇨🇦 Virginie CHENIER\n🇵🇱
|
||||
// Wioleta MYSZOR\n🇨🇳 YANG Xiaolei\n🇦🇿 Yaylagul RAMAZANOVA\n🇸🇮 Zana
|
||||
// PINTARIC\n🇺🇿 Ziyodakhon ABDUSATTOROVA
|
||||
// SUMMARY:🏹 Women's Individual Ranking Round
|
||||
// LOCATION:Invalides
|
||||
// END:VEVENT
|
||||
|
||||
import { mkdirSync, writeFileSync } from "fs";
|
||||
import { Calendar } from "./types";
|
||||
import { getFlag } from "./nocs";
|
||||
|
||||
|
||||
// BEGIN:VCALENDAR
|
||||
// VERSION:2.0
|
||||
// PRODID:-//fabrice404//olympics-calendar//3x3-basketball/AUS//EN
|
||||
// X-WR-CALNAME:🇦🇺 Australia 3x3 Basketball | Paris 2024
|
||||
// NAME:🇦🇺 Australia 3x3 Basketball | Paris 2024
|
||||
// BEGIN:VEVENT
|
||||
// UID:20240730T160000Z-3x3-basketball-WOMENS-POOL-ROUND-AUS-CAN
|
||||
// DTSTAMP:20240730T160000Z
|
||||
// DTSTART:20240730T160000Z
|
||||
// DTEND:20240730T162500Z
|
||||
// DESCRIPTION:3x3 Basketball - Women's Pool Round
|
||||
// SUMMARY:🏀 AUS 🇦🇺 - 🇨🇦 CAN
|
||||
// LOCATION:La Concorde 1
|
||||
// END:VEVENT
|
||||
|
||||
// END:VCALENDAR
|
||||
|
||||
export const generateICSFiles = (calendar: Calendar): void => {
|
||||
|
||||
generateICSFile(calendar, null, null);
|
||||
|
||||
calendar.sports.forEach((sport) => {
|
||||
generateICSFile(calendar, sport.key, null);
|
||||
calendar.nocs.forEach((noc) => {
|
||||
generateICSFile(calendar, sport.key, noc.key);
|
||||
});
|
||||
});
|
||||
|
||||
calendar.nocs.forEach((noc) => {
|
||||
generateICSFile(calendar, null, noc.key);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
export const generateICSFile = (calendar: Calendar, sportKey: string | null, nocKey: string | null): void => {
|
||||
calendar.languages.forEach((lang) => {
|
||||
const pathSportKey = sportKey ? sportKey : "all-sports";
|
||||
const pathNocKey = nocKey ? nocKey : "calendar"
|
||||
|
||||
const filepath = `../ui/public/data/${lang.code.toLowerCase()}/${pathSportKey.toLowerCase()}/${pathNocKey.toLowerCase()}.ics`;
|
||||
mkdirSync(filepath.split('/').slice(0, -1).join('/'), { recursive: true });
|
||||
|
||||
const titleComponents = [];
|
||||
if (nocKey) {
|
||||
titleComponents.push(`${calendar.nocs.find(n => n.key === nocKey)!.name[lang.code]}`);
|
||||
}
|
||||
if (sportKey) {
|
||||
titleComponents.push(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}`);
|
||||
|
||||
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 = calendar.sports.find(s => s.key === event.sport)!;
|
||||
lines.push(`DESCRIPTION:${sport.name[lang.code]} - ${event.name[lang.code] || ''}`);
|
||||
let 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'));
|
||||
});
|
||||
};
|
||||
@ -1,12 +1,16 @@
|
||||
import Debug from "debug";
|
||||
|
||||
import * as cache from "./cache";
|
||||
import { mkdirSync, writeFileSync } from "fs";
|
||||
import { Calendar, Event, Sport, Team } from "./types";
|
||||
import { generateICSFiles } from "./ics";
|
||||
|
||||
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}`);
|
||||
|
||||
@ -48,7 +52,7 @@ const getScheduleSport = async (language: string, sportCode: string) => {
|
||||
|
||||
const scheduleSport = JSON.parse(cache.get(scheduleSportKey)!);
|
||||
return scheduleSport;
|
||||
}
|
||||
};
|
||||
|
||||
const main = async () => {
|
||||
const overview = await getScheduleOverview("en");
|
||||
@ -59,9 +63,9 @@ const main = async () => {
|
||||
name: lang.label,
|
||||
}))
|
||||
|
||||
const sports: any = [];
|
||||
const events: any[] = [];
|
||||
let nocs: any[] = [];
|
||||
const sports: Sport[] = [];
|
||||
const events: Event[] = [];
|
||||
let nocs: Team[] = [];
|
||||
|
||||
for (const lang of languages) {
|
||||
const scheduleOverview = await getScheduleOverview(lang.code);
|
||||
@ -76,7 +80,7 @@ const main = async () => {
|
||||
if (sports.find((s: any) => s.key === key) == null) {
|
||||
sports.push({ key, name: {}, order: -1 })
|
||||
}
|
||||
const sport = sports.find((s: any) => s.key === key)
|
||||
const sport = sports.find((s: any) => s.key === key)!;
|
||||
sport.name[lang.code] = discipline.description;
|
||||
sport.order = discipline.order;
|
||||
|
||||
@ -93,10 +97,12 @@ const main = async () => {
|
||||
isTraining: scheduleListElement.isTraining,
|
||||
medal: scheduleListElement.medal,
|
||||
name: {},
|
||||
location: {},
|
||||
})
|
||||
}
|
||||
const event = events.find(e => e.key === scheduleListElement.unitCode);
|
||||
const event = events.find(e => e.key === scheduleListElement.unitCode)!;
|
||||
event.name[lang.code] = scheduleListElement.description;
|
||||
event.location[lang.code] = scheduleListElement.venue?.description || ''
|
||||
|
||||
if (scheduleListElement.match) {
|
||||
if (event.match == null) {
|
||||
@ -114,7 +120,7 @@ const main = async () => {
|
||||
if (nocs.find(n => n.key === nocKey) == null) {
|
||||
nocs.push({ key: nocKey, name: {} });
|
||||
}
|
||||
const noc = nocs.find(n => n.key === nocKey);
|
||||
const noc = nocs.find(n => n.key === nocKey)!;
|
||||
noc.name[lang.code] = (team.description || '').replace(/\,/gi, '');
|
||||
}
|
||||
}
|
||||
@ -125,7 +131,11 @@ const main = async () => {
|
||||
|
||||
nocs = nocs.filter((noc) => noc.key !== noc.name.en);
|
||||
|
||||
cache.set('calendar.json', JSON.stringify({ languages, sports, nocs, events }));
|
||||
const dataFolder = "../ui/public/data";
|
||||
mkdirSync(dataFolder, { recursive: true });
|
||||
const calendar: Calendar = { languages, sports, nocs, events };
|
||||
writeFileSync(`${dataFolder}/calendar.json`, JSON.stringify(calendar));
|
||||
generateICSFiles(calendar);
|
||||
};
|
||||
|
||||
main();
|
||||
|
||||
212
scraper/nocs.ts
Normal file
212
scraper/nocs.ts
Normal file
@ -0,0 +1,212 @@
|
||||
export const flags: { [key: string]: string } = {
|
||||
AFG: "🇦🇫",
|
||||
ALB: "🇦🇱",
|
||||
ALG: "🇩🇿",
|
||||
AIN: "🇦🇸",
|
||||
AND: "🇦🇩",
|
||||
ANG: "🇦🇴",
|
||||
ANT: "🇦🇬",
|
||||
ARG: "🇦🇷",
|
||||
ARM: "🇦🇲",
|
||||
ARU: "🇦🇼",
|
||||
ASA: "🇦🇸",
|
||||
AUS: "🇦🇺",
|
||||
AUT: "🇦🇹",
|
||||
AZE: "🇦🇿",
|
||||
BAH: "🇧🇸",
|
||||
BAN: "🇧🇩",
|
||||
BAR: "🇧🇧",
|
||||
BDI: "🇧🇮",
|
||||
BEL: "🇧🇪",
|
||||
BEN: "🇧🇯",
|
||||
BER: "🇧🇲",
|
||||
BHU: "🇧🇹",
|
||||
BIH: "🇧🇦",
|
||||
BIZ: "🇧🇿",
|
||||
BOL: "🇧🇴",
|
||||
BOT: "🇧🇼",
|
||||
BRA: "🇧🇷",
|
||||
BRN: "🇧🇭",
|
||||
BRU: "🇧🇳",
|
||||
BUL: "🇧🇬",
|
||||
BUR: "🇧🇫",
|
||||
CAF: "🇨🇫",
|
||||
CAM: "🇰🇭",
|
||||
CAN: "🇨🇦",
|
||||
CAY: "🇰🇾",
|
||||
CGO: "🇨🇬",
|
||||
CHA: "🇹🇩",
|
||||
CHI: "🇨🇱",
|
||||
CHN: "🇨🇳",
|
||||
CIV: "🇨🇮",
|
||||
CMR: "🇨🇲",
|
||||
COD: "🇨🇩",
|
||||
COK: "🇨🇰",
|
||||
COL: "🇨🇴",
|
||||
COM: "🇰🇲",
|
||||
CPV: "🇨🇻",
|
||||
CRC: "🇨🇷",
|
||||
CRO: "🇭🇷",
|
||||
CUB: "🇨🇺",
|
||||
CYP: "🇨🇾",
|
||||
CZE: "🇨🇿",
|
||||
DEN: "🇩🇰",
|
||||
DJI: "🇩🇯",
|
||||
DMA: "🇩🇲",
|
||||
DOM: "🇩🇴",
|
||||
ECU: "🇪🇨",
|
||||
EGY: "🇪🇬",
|
||||
EOR: "🏳️",
|
||||
ERI: "🇪🇷",
|
||||
ESA: "🇸🇻",
|
||||
ESP: "🇪🇸",
|
||||
EST: "🇪🇪",
|
||||
ETH: "🇪🇹",
|
||||
FIJ: "🇫🇯",
|
||||
FIN: "🇫🇮",
|
||||
FRA: "🇫🇷",
|
||||
FSM: "🇫🇲",
|
||||
GAB: "🇬🇦",
|
||||
GAM: "🇬🇲",
|
||||
GBR: "🇬🇧",
|
||||
GBS: "🇬🇼",
|
||||
GEO: "🇬🇪",
|
||||
GEQ: "🇬🇶",
|
||||
GER: "🇩🇪",
|
||||
GHA: "🇬🇭",
|
||||
GRE: "🇬🇷",
|
||||
GRN: "🇬🇩",
|
||||
GUA: "🇬🇹",
|
||||
GUI: "🇬🇳",
|
||||
GUM: "🇬🇺",
|
||||
GUY: "🇬🇾",
|
||||
HAI: "🇭🇹",
|
||||
HKG: "🇭🇰",
|
||||
HON: "🇭🇳",
|
||||
HUN: "🇭🇺",
|
||||
INA: "🇮🇩",
|
||||
IND: "🇮🇳",
|
||||
IRI: "🇮🇷",
|
||||
IRL: "🇮🇪",
|
||||
IRQ: "🇮🇶",
|
||||
ISL: "🇮🇸",
|
||||
ISR: "🇮🇱",
|
||||
ISV: "🇻🇮",
|
||||
ITA: "🇮🇹",
|
||||
IVB: "🇻🇬",
|
||||
JAM: "🇯🇲",
|
||||
JOR: "🇯🇴",
|
||||
JPN: "🇯🇵",
|
||||
KAZ: "🇰🇿",
|
||||
KEN: "🇰🇪",
|
||||
KGZ: "🇰🇬",
|
||||
KIR: "🇰🇮",
|
||||
KOR: "🇰🇷",
|
||||
KOS: "🇽🇰",
|
||||
KSA: "🇸🇦",
|
||||
KUW: "🇰🇼",
|
||||
LAO: "🇱🇦",
|
||||
LAT: "🇱🇻",
|
||||
LBA: "🇱🇾",
|
||||
LBN: "🇱🇧",
|
||||
LBR: "🇱🇷",
|
||||
LCA: "🇱🇨",
|
||||
LES: "🇱🇸",
|
||||
LIE: "🇱🇮",
|
||||
LTU: "🇱🇹",
|
||||
LUX: "🇱🇺",
|
||||
MAD: "🇲🇬",
|
||||
MAR: "🇲🇦",
|
||||
MAS: "🇲🇾",
|
||||
MAW: "🇲🇼",
|
||||
MDA: "🇲🇩",
|
||||
MDV: "🇲🇻",
|
||||
MEX: "🇲🇽",
|
||||
MGL: "🇲🇳",
|
||||
MHL: "🇲🇭",
|
||||
MKD: "🇲🇰",
|
||||
MLI: "🇲🇱",
|
||||
MLT: "🇲🇹",
|
||||
MNE: "🇲🇪",
|
||||
MON: "🇲🇨",
|
||||
MOZ: "🇲🇿",
|
||||
MRI: "🇲🇺",
|
||||
MTN: "🇲🇷",
|
||||
MYA: "🇲🇲",
|
||||
NAM: "🇳🇦",
|
||||
NCA: "🇳🇮",
|
||||
NED: "🇳🇱",
|
||||
NEP: "🇳🇵",
|
||||
NGR: "🇳🇬",
|
||||
NIG: "🇳🇪",
|
||||
NOR: "🇳🇴",
|
||||
NRU: "🇳🇷",
|
||||
NZL: "🇳🇿",
|
||||
OMA: "🇴🇲",
|
||||
PAK: "🇵🇰",
|
||||
PAN: "🇵🇦",
|
||||
PAR: "🇵🇾",
|
||||
PER: "🇵🇪",
|
||||
PHI: "🇵🇭",
|
||||
PLE: "🇵🇸",
|
||||
PLW: "🇵🇼",
|
||||
PNG: "🇵🇬",
|
||||
POL: "🇵🇱",
|
||||
POR: "🇵🇹",
|
||||
PRK: "🇰🇵",
|
||||
PUR: "🇵🇷",
|
||||
QAT: "🇶🇦",
|
||||
ROU: "🇷🇴",
|
||||
RSA: "🇿🇦",
|
||||
RWA: "🇷🇼",
|
||||
SAM: "🇼🇸",
|
||||
SEN: "🇸🇳",
|
||||
SEY: "🇸🇨",
|
||||
SGP: "🇸🇬",
|
||||
SKN: "🇰🇳",
|
||||
SLE: "🇸🇱",
|
||||
SLO: "🇸🇮",
|
||||
SMR: "🇸🇲",
|
||||
SOL: "🇸🇧",
|
||||
SOM: "🇸🇴",
|
||||
SRB: "🇷🇸",
|
||||
SRI: "🇱🇰",
|
||||
SSD: "🇸🇸",
|
||||
STP: "🇸🇹",
|
||||
SUD: "🇸🇩",
|
||||
SUI: "🇨🇭",
|
||||
SUR: "🇸🇷",
|
||||
SVK: "🇸🇰",
|
||||
SWE: "🇸🇪",
|
||||
SWZ: "🇸🇿",
|
||||
SYR: "🇸🇾",
|
||||
TAN: "🇹🇿",
|
||||
TGA: "🇹🇴",
|
||||
THA: "🇹🇭",
|
||||
TJK: "🇹🇯",
|
||||
TKM: "🇹🇲",
|
||||
TLS: "🇹🇱",
|
||||
TOG: "🇹🇬",
|
||||
TPE: "🇹🇼",
|
||||
TTO: "🇹🇹",
|
||||
TUN: "🇹🇳",
|
||||
TUR: "🇹🇷",
|
||||
TUV: "🇹🇻",
|
||||
UAE: "🇦🇪",
|
||||
UGA: "🇺🇬",
|
||||
UKR: "🇺🇦",
|
||||
URU: "🇺🇾",
|
||||
USA: "🇺🇸",
|
||||
UZB: "🇺🇿",
|
||||
VAN: "🇻🇺",
|
||||
VEN: "🇻🇪",
|
||||
VIE: "🇻🇳",
|
||||
VIN: "🇻🇨",
|
||||
YEM: "🇾🇪",
|
||||
ZAM: "🇿🇲",
|
||||
ZIM: "🇿🇼",
|
||||
};
|
||||
|
||||
export const getFlag = (nocKey: string): string => {
|
||||
return flags[nocKey.toUpperCase()] || "🏳️";
|
||||
}
|
||||
@ -7,7 +7,9 @@
|
||||
"type": "commonjs",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"dev": "DEBUG=olympics-calendar* nodemon index.ts"
|
||||
"start": "find ./cache/**/*.cached -mmin +10 -exec rm -f {} \\; | DEBUG=olympics-calendar* ts-node index.ts",
|
||||
"dev": "DEBUG=olympics-calendar* nodemon index.ts",
|
||||
"lint": "eslint . --ext .ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": "^4.4.3",
|
||||
|
||||
44
scraper/types.d.ts
vendored
Normal file
44
scraper/types.d.ts
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
export interface MultilingualString {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export interface Language {
|
||||
code: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface Sport {
|
||||
key: string;
|
||||
name: MultilingualString;
|
||||
order: number;
|
||||
}
|
||||
|
||||
export interface Team {
|
||||
key: string;
|
||||
name: MultilingualString;
|
||||
}
|
||||
|
||||
export interface Match {
|
||||
team1: Team;
|
||||
team2: Team;
|
||||
}
|
||||
|
||||
export interface Event {
|
||||
key: string;
|
||||
start: string;
|
||||
end: string;
|
||||
sport: string;
|
||||
isTraining: boolean;
|
||||
medal: '0' | '1' | '3';
|
||||
name: MultilingualString;
|
||||
location: MultilingualString;
|
||||
match?: Match;
|
||||
}
|
||||
|
||||
export interface Calendar {
|
||||
languages: Language[];
|
||||
sports: Sport[];
|
||||
events: Event[];
|
||||
nocs: Team[];
|
||||
}
|
||||
Reference in New Issue
Block a user