mirror of
https://github.com/clarencechaan/ufc-cal.git
synced 2026-10-19 08:38:30 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
087de8de41 | ||
|
|
6b3b55efdb | ||
|
|
a2ec15795d | ||
|
|
2f5a30fadf | ||
|
|
18aa02a074 | ||
|
|
cb8e32be66 | ||
|
|
426097ec7d | ||
|
|
f299b1ff44 | ||
|
|
0abdf42280 |
No files matched your search
@@ -0,0 +1,158 @@
|
|||||||
|
import { writeFile, readFile } from "fs/promises";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the details of a UFC event given its event ID and using the UFC API
|
||||||
|
*
|
||||||
|
* @param {number} eventId - The ID of a UFC event
|
||||||
|
* @returns {Promise<object>} - A Promise that resolves with the details of
|
||||||
|
* a UFC event
|
||||||
|
*/
|
||||||
|
async function fetchEvent(eventId) {
|
||||||
|
try {
|
||||||
|
const url =
|
||||||
|
"https://d29dxerjsp82wz.cloudfront.net/api/v3/event/live/" +
|
||||||
|
eventId +
|
||||||
|
".json";
|
||||||
|
const response = await fetch(url);
|
||||||
|
const event = await response.json();
|
||||||
|
return event;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Using the UFC API, search for the latest event ID, then request each event
|
||||||
|
* preceding it until we reach an event that occurred 90 days before now, then
|
||||||
|
* create events.json containing these events.
|
||||||
|
* Finally return an array of these events
|
||||||
|
*
|
||||||
|
* @returns {Promise<Array<object>>} - A Promise that resolves with the array
|
||||||
|
* of details of recent and upcoming UFC events
|
||||||
|
*/
|
||||||
|
async function initializeEvents() {
|
||||||
|
// Binary search for the event with the highest valid event ID
|
||||||
|
let min = 1180;
|
||||||
|
let max = 2000; // Values should be updated when we reach UFC event ID 2000
|
||||||
|
let mid = Math.ceil((min + max) / 2);
|
||||||
|
|
||||||
|
console.log("Intializing events.json");
|
||||||
|
console.log("Finding latest event ID...");
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (min < max) {
|
||||||
|
const event = await fetchEvent(mid);
|
||||||
|
if (event.LiveEventDetail.EventId) min = mid;
|
||||||
|
else max = mid - 1;
|
||||||
|
mid = Math.ceil((min + max) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Fetching recent and upcoming events:");
|
||||||
|
|
||||||
|
// Fetch all events starting from the latest event ID, moving backwards
|
||||||
|
// until we reach an event that occured 90 days before now
|
||||||
|
let eventId = mid;
|
||||||
|
let fetchedEvents = [];
|
||||||
|
let event;
|
||||||
|
|
||||||
|
do {
|
||||||
|
console.log("Event ID:", eventId);
|
||||||
|
|
||||||
|
event = await fetchEvent(eventId);
|
||||||
|
|
||||||
|
// Only filter in UFC events
|
||||||
|
if (event.LiveEventDetail.Organization.OrganizationId === 1)
|
||||||
|
fetchedEvents.push(event);
|
||||||
|
|
||||||
|
eventId--;
|
||||||
|
} while (
|
||||||
|
new Date(event.LiveEventDetail.StartTime) >
|
||||||
|
Date.now() - 1000 * 60 * 60 * 24 * 90
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log("Creating events.json");
|
||||||
|
|
||||||
|
// Write the fetched events to events.json
|
||||||
|
const json = JSON.stringify(fetchedEvents, null, 2);
|
||||||
|
writeFile("./events.json", json);
|
||||||
|
|
||||||
|
return fetchedEvents;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update upcoming events in events.json, and add newly found events to events.json
|
||||||
|
* Return an array of these events
|
||||||
|
*
|
||||||
|
* @returns {Promise<Array<object>>} - A Promise that resolves with the array
|
||||||
|
* of details of recent and upcoming UFC events
|
||||||
|
*/
|
||||||
|
async function updateEventsFile() {
|
||||||
|
try {
|
||||||
|
let events = JSON.parse(await readFile("./events.json"));
|
||||||
|
|
||||||
|
// Update upcoming events
|
||||||
|
for (let i = 0; i < events.length; i++) {
|
||||||
|
// Skip past events
|
||||||
|
if (events[i].LiveEventDetail.Status === "Final") continue;
|
||||||
|
|
||||||
|
console.log("Updating event", events[i].LiveEventDetail.EventId);
|
||||||
|
events[i] = fetchEvent(events[i].LiveEventDetail.EventId);
|
||||||
|
}
|
||||||
|
|
||||||
|
events = await Promise.all(events);
|
||||||
|
|
||||||
|
// Starting from the latest event ID previously found, find and add any
|
||||||
|
// new events
|
||||||
|
let eventId = events[0].LiveEventDetail.EventId;
|
||||||
|
let event;
|
||||||
|
do {
|
||||||
|
eventId++;
|
||||||
|
|
||||||
|
event = await fetchEvent(eventId);
|
||||||
|
|
||||||
|
// Only filter in UFC events
|
||||||
|
if (
|
||||||
|
event.LiveEventDetail.EventId &&
|
||||||
|
event.LiveEventDetail.Organization.OrganizationId === 1
|
||||||
|
) {
|
||||||
|
console.log("Found new event", event.LiveEventDetail.EventId);
|
||||||
|
events.unshift(event);
|
||||||
|
}
|
||||||
|
} while (event?.LiveEventDetail.EventId);
|
||||||
|
|
||||||
|
console.log("Updating events.json");
|
||||||
|
|
||||||
|
// Write the newly added and updated events to events.json
|
||||||
|
const json = JSON.stringify(events, null, 2);
|
||||||
|
writeFile("./events.json", json);
|
||||||
|
|
||||||
|
return events;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create events.json if it does not exist, otherwise update events.json.
|
||||||
|
* Return an array of recent and upcoming events
|
||||||
|
*
|
||||||
|
* @returns {Promise<Array<object>>} - A Promise that resolves with the array
|
||||||
|
* of details of recent and upcoming UFC events
|
||||||
|
*/
|
||||||
|
async function getEvents() {
|
||||||
|
let events;
|
||||||
|
|
||||||
|
try {
|
||||||
|
events = await updateEventsFile();
|
||||||
|
if (!events) events = await initializeEvents();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { getEvents };
|
||||||
@@ -1,14 +1,18 @@
|
|||||||
import { getAllDetailedEvents } from "./scrape.js";
|
import { getAllDetailedEvents } from "./scrape.js";
|
||||||
import { writeFileSync } from "fs";
|
import { getEvents } from "./api.js";
|
||||||
|
import { writeFile } from "fs/promises";
|
||||||
import { createEvents } from "ics";
|
import { createEvents } from "ics";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts the details of recent and near-future UFC events, then creates an
|
* Extracts the details of recent and upcoming UFC events by scraping the
|
||||||
* ICS file named "UFC.ics" in the current directory containing these events
|
* UFC website, then creates an ICS file named "UFC.ics" in the current
|
||||||
|
* directory containing these events
|
||||||
*
|
*
|
||||||
* @returns {Promise<void>} - A Promise that resolves when the ICS file is created
|
* @returns {Promise<void>} - A Promise that resolves when the ICS file is created
|
||||||
*/
|
*/
|
||||||
async function createICS() {
|
async function createICSFromScrape() {
|
||||||
|
// Creating ICS by scraping the UFC website
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let events = await getAllDetailedEvents();
|
let events = await getAllDetailedEvents();
|
||||||
if (!events.length) throw new Error("No events retrieved");
|
if (!events.length) throw new Error("No events retrieved");
|
||||||
@@ -71,10 +75,125 @@ async function createICS() {
|
|||||||
console.log(events);
|
console.log(events);
|
||||||
|
|
||||||
// Create UFC.ics
|
// Create UFC.ics
|
||||||
writeFileSync(`UFC.ics`, createEvents(events).value);
|
writeFile(`UFC.ics`, createEvents(events).value);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createICS();
|
/**
|
||||||
|
* Fetch the details of recent and upcoming UFC events by using the UFC API,
|
||||||
|
* then creates an ICS file named "UFC.ics" in the current directory containing
|
||||||
|
* these events
|
||||||
|
*
|
||||||
|
* @returns {Promise<void>} - A Promise that resolves when the ICS file is created
|
||||||
|
*/
|
||||||
|
async function createICSFromAPI() {
|
||||||
|
// Creating ICS by using the UFC API
|
||||||
|
|
||||||
|
let events;
|
||||||
|
try {
|
||||||
|
events = await getEvents();
|
||||||
|
if (!events.length) throw new Error("No events retrieved");
|
||||||
|
|
||||||
|
// Get current date and time to communicate to the user how up-to-date
|
||||||
|
// the event details are
|
||||||
|
let currentDateTime = new Date();
|
||||||
|
let dateTimestr = currentDateTime.toLocaleString("en-US", {
|
||||||
|
month: "short",
|
||||||
|
day: "numeric",
|
||||||
|
hour: "numeric",
|
||||||
|
minute: "numeric",
|
||||||
|
timeZone: "America/Toronto",
|
||||||
|
timeZoneName: "short",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert event details in the format in accordance with the ICS generator
|
||||||
|
events = events.map((event) => {
|
||||||
|
let date = new Date(
|
||||||
|
event.LiveEventDetail.FightCard[0].CardSegmentStartTime ||
|
||||||
|
event.LiveEventDetail.StartTime
|
||||||
|
);
|
||||||
|
let start = [
|
||||||
|
date.getFullYear(),
|
||||||
|
date.getMonth() + 1,
|
||||||
|
date.getDate(),
|
||||||
|
date.getHours(),
|
||||||
|
date.getMinutes(),
|
||||||
|
];
|
||||||
|
let duration = { hours: 3 };
|
||||||
|
let title = event.LiveEventDetail.Name;
|
||||||
|
let description = "";
|
||||||
|
|
||||||
|
let mainCard = [];
|
||||||
|
let prelims = [];
|
||||||
|
let fightCard = [];
|
||||||
|
|
||||||
|
// Helper function to convert fight to a string line to be displayed
|
||||||
|
// in the calendar
|
||||||
|
function fightToStr(fight) {
|
||||||
|
return (
|
||||||
|
"• " +
|
||||||
|
fight.Fighters[0].Name.FirstName +
|
||||||
|
" " +
|
||||||
|
fight.Fighters[0].Name.LastName +
|
||||||
|
" vs. " +
|
||||||
|
fight.Fighters[1].Name.FirstName +
|
||||||
|
" " +
|
||||||
|
fight.Fighters[1].Name.LastName +
|
||||||
|
" @" +
|
||||||
|
(fight.WeightClass.CatchWeight || fight.WeightClass.Weight.slice(-3))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.LiveEventDetail.FightCard.every((fight) => fight.CardSegment)) {
|
||||||
|
for (const fight of event.LiveEventDetail.FightCard)
|
||||||
|
if (fight.CardSegment === "Main") mainCard.push(fightToStr(fight));
|
||||||
|
else prelims.push(fightToStr(fight));
|
||||||
|
} else {
|
||||||
|
for (const fight of event.LiveEventDetail.FightCard)
|
||||||
|
fightCard.push(fightToStr(fight));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Distinguish between main card and prelims if this information has been
|
||||||
|
// announced by the UFC, otherwise list all fights without categorizing
|
||||||
|
if (fightCard.length) description += fightCard.join("\n") + "\n";
|
||||||
|
if (mainCard.length)
|
||||||
|
description += "Main Card\n----------\n" + mainCard.join("\n") + "\n";
|
||||||
|
if (prelims.length)
|
||||||
|
description += "\nPrelims\n----------\n" + prelims.join("\n") + "\n";
|
||||||
|
|
||||||
|
description +=
|
||||||
|
"\nhttps://www.google.com/search?q=" + title.replaceAll(" ", "+");
|
||||||
|
description += "\n\nAccurate as of " + dateTimestr;
|
||||||
|
|
||||||
|
let location =
|
||||||
|
event.LiveEventDetail.Location.Venue +
|
||||||
|
", " +
|
||||||
|
event.LiveEventDetail.Location.City +
|
||||||
|
", " +
|
||||||
|
event.LiveEventDetail.Location.Country;
|
||||||
|
let uid = "ufc-id-" + event.LiveEventDetail.EventId;
|
||||||
|
let calName = "UFC";
|
||||||
|
return {
|
||||||
|
start,
|
||||||
|
duration,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
location,
|
||||||
|
uid,
|
||||||
|
calName,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("\nDetailed events:");
|
||||||
|
console.log(events);
|
||||||
|
|
||||||
|
// Create UFC.ics
|
||||||
|
writeFile(`UFC.ics`, createEvents(events).value);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createICSFromAPI();
|
||||||
Reference in new issue
Block a user