zwiftPortalSchedule
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data β all from the browser, and deployed in milliseconds.
Fetch and parse the Zwift Climbing Portal Schedule XML from the Zwift CDN.
Example usage:
console.log(await zwiftPortalSchedule());
Expected output will look something like this:
[
{
"date": "Sun, Oct 27",
"road": "La Turbie + Col d'Eze",
"distance": "15.9km",
"elevation": "616m",
"gradient": "3.9%",
"isPortalOfMonth": false,
"world": "Watopia"
},
{
"date": "Mon, Oct 28",
"road": "Col du Galibier (Lautaret)",
"distance": "10.4km",
"elevation": "539m",
"gradient": "5.2%",
"isPortalOfMonth": false,
"world": "Watopia"
},
{
"date": "Thu, Oct 31",
"road": "Mt. Hamilton",
"distance": "31.3km",
"elevation": "1259m",
"gradient": "4.0%",
"isPortalOfMonth": true,
"world": "France"
}
]
Create a cron to send an email periodically:
import { zwiftPortalSchedule } from "https://esm.town/v/dazzag24/zwiftPortalSchedule";
import { email } from "https://esm.town/v/std/email";
export default async function sendZwiftPortalSchedule(interval: Interval) {
console.log("Parsing Zwift portal road schedule...");
const schedule = await zwiftPortalSchedule();
const content = schedule.map(event =>
`**${event.date}**\n${event.road}\nπ ${event.distance} | β°οΈ ${event.elevation} | π ${event.gradient}${
event.isPortalOfMonth ? " | π Portal of the Month" : ""
}\nπ ${event.world}\n`
).join("\n");
console.log(content);
return email({
subject: "Zwift Climbing Portal Schedule",
text: "**Upcoming Zwift Portal Roads**\n\n" + content,
});
}