Fixing Twitch’s Broken iCal Feeds
Published
This all started with Peter announcing that there will be Twitch.tv streams semiweekly1 for Lobsters office hours and development. I attended the first one for a couple hours, mostly having it on in the background, and it was a great time.
So, as one does, I added iCal feed to my calendar to stay up to date because I wanted to attend more in the future. Fast forward a week and I went to attend, realized my calendar wasn’t reflecting the correctly scheduled time, and promptly dug in to figure out why.
Initially, I thought it was on my end e.g. when importing the calendar. I quickly realized that’s not the case, and some research led me to complaints that the timezone in the iCal file was mangled and not-quite-to-spec. Even more surprising, providing iCals of stream schedules is relatively new from the past couple years.
From this, I referenced the API docs which ultimately led me to seeing what the API is returning:
BEGIN:VCALENDAR
PRODID:-//twitch.tv//StreamSchedule//1.0
VERSION:2.0
CALSCALE:GREGORIAN
REFRESH-INTERVAL;VALUE=DURATION:PT6H
X-PUBLISHED-TTL:PT6H
NAME:pushcx
X-WR-CALNAME:pushcx
BEGIN:VEVENT
UID:24a52982-3ba5-47b7-a513-72ae97b572bc
DTSTAMP:20240812T172447Z
DTSTART;TZID=/America/Chicago:20240815T090000
DTEND;TZID=/America/Chicago:20240815T120000
SUMMARY:Lobsters office hours + development
DESCRIPTION:Software and Game Development.
CATEGORIES:Software and Game Development
RRULE:FREQ=WEEKLY;BYDAY=TH
END:VEVENT
BEGIN:VEVENT
UID:6df7b8b5-ce84-4d5a-b564-b74de0501f18
DTSTAMP:20240812T172436Z
DTSTART;TZID=/America/Chicago:20240819T140000
DTEND;TZID=/America/Chicago:20240819T170000
SUMMARY:Lobsters office hours + development
DESCRIPTION:Software and Game Development.
CATEGORIES:Software and Game Development
RRULE:FREQ=WEEKLY;BYDAY=MO
END:VEVENT
END:VCALENDAR
This is done rather simply via the browser’s2 builtin view-source:
scheme:
view-source:https://api.twitch.tv/helix/schedule/icalendar?broadcaster_id=95536715
Fortunately, when viewing this the problem becomes rather obvious: TZID=
should not3 start with a /
. I verified the quickly by downloading the file, removing the prefix, and importing it into my calendar. Bless & bliss, it’s fixed.
Unfortunately, Twitch doesn’t seem to be prioritizing fixing this in the upstream API so it’s up to me to create a quick fix. As I keep doing, I reached for Val Town.
Behold, another val: https://www.val.town/v/pinjasaur/twitch
Here’s the source code in its entirety:
const getText = async url => (await fetch(url)).text();
export default async function(req: Request): Promise<Response> {
if (req.headers.get("referer")?.includes("val.")) {
return Response.json({ error: "Cannot access from val.town" }, {
status: 400,
});
}
const params = new URL(req.url).searchParams;
if (!params.has("broadcaster_id")) {
return Response.json({ error: "Missing 'broadcaster_id'" }, {
status: 400,
});
}
try {
// https://api.twitch.tv/helix/schedule/icalendar?broadcaster_id=95536715
const url = new URL("https://api.twitch.tv/helix/schedule/icalendar");
url.searchParams
.set("broadcaster_id", params.get("broadcaster_id"));
const ical = await getText(url.toString());
return new Response(
ical.replaceAll(
";TZID=/",
";TZID=",
),
{
headers: {
"content-type": params.get("raw") ? "text/plain" : "text/calendar",
},
},
);
} catch (err) {
return Response.json({ error: err.message }, {
status: 400,
});
}
}
I haven’t used the new URL()
or searchParams
APIs as much as I would have liked, so it’s always nice to have an excuse to use ’em in production. Speaking of, I’m totally using this in production and you can too.
You’ll just need the broadcaster_id
from the Twitch schedule you’re looking to subscribe to. For Lobsters, just import this URL into your calendar:
https://pinjasaur-twitch.web.val.run/?broadcaster_id=95536715
And yes, I asked what I should title this post:
cat twitch.md | qq What should I title this article?
"Fixing Twitch's Broken iCal Feeds"
Hurray for end-user programming.
I love hearing from readers so please feel free to reach out.
Reply via email • Subscribe via RSS or email
Last modified #programming #js #ux #syndication