Generate ical files from schedule data

This commit is contained in:
Uthman Fatih 2026-10-08 23:35:24 +01:00
parent 5140730189
commit 01e0b17586
3 changed files with 48 additions and 4 deletions

1
.gitignore vendored
View File

@ -223,3 +223,4 @@ __marimo__/
airingdata.json
listdata.json
config.toml
anime.ics

View File

@ -4,6 +4,3 @@ mediaType = "ANIME"
[anical]
listNames = ["Completed", "Planning", "Watching", "Rewatching", "Paused"]
[ical]
# reserved for future use

48
main.py
View File

@ -3,6 +3,8 @@ import time
import tomllib
from os import path
import json
from icalendar import Calendar, Event
from datetime import datetime, timezone
if path.exists("config.toml"):
with open("config.toml", "rb") as f:
@ -305,6 +307,47 @@ def getAiringScheduleBatch(
return (form, False)
def createIcal(
schedules,
*,
name="Anime Airing Schedule",
duration=24 * 60
):
"""
Returns the .ics file contents (bytes) for every upcoming episode in schedules.
Takes the following arguments:
- schedules: the "response" dict from getAiringScheduleBatch (mediaId -> {"title", "schedule"})
- name: the calendar's display name (defaults to "Anime Airing Schedule")
- duration: event length in seconds (defaults to 24 minutes)
"""
cal = Calendar()
cal.add("prodid", "-//anical//AniList airing schedule//EN")
cal.add("version", "2.0")
cal.add("x-wr-calname", name) # display name in Google/Apple Calendar
now = time.time()
stamp = datetime.now(timezone.utc)
for mediaId, anime in schedules.items():
title = anime["title"].get("english") or anime["title"].get("romaji") or f"Anime {mediaId}"
for item in anime["schedule"]:
# the cache can be older than some of its episodes, so skip anything already aired
if item["airingAt"] <= now:
continue
ev = Event()
ev.add("uid", f"anilist-{item['id']}@anilist.co")
ev.add("summary", f"{title} - Episode {item['episode']}")
ev.add("dtstart", datetime.fromtimestamp(item["airingAt"], timezone.utc))
ev.add("dtend", datetime.fromtimestamp(item["airingAt"] + duration, timezone.utc))
ev.add("dtstamp", stamp)
cal.add_component(ev)
return cal.to_ical() # bytes
if __name__ == "__main__":
entries, cached = getMediaListCollection()
@ -336,4 +379,7 @@ if __name__ == "__main__":
f.write(f"{json.dumps(airing, indent=2)}")
schedules = airing["response"]
print(f"\nGot upcoming episodes for {len(schedules)} anime")
print(f"\nGot upcoming episodes for {len(schedules)} anime")
with open("anime.ics", "wb") as f:
f.write(createIcal(schedules))