Why
A very common self-hosted use case for a TRMNL/BYOS screen is showing an upcoming-events
calendar (iCloud, Google, Nextcloud, Outlook — all publish .ics feeds). Today Terminus
can poll JSON/CSV/XML/plain/image sources, but not an ICS feed, so users have to run a
separate side-car service that converts text/calendar → JSON just to feed a Poll extension.
Native ICS support would remove that side-car entirely and make "calendar on a TRMNL" a
first-class, no-extra-container setup.
Current behavior
The fetcher client only recognizes a fixed set of MIME types and rejects everything else:
app/aspects/extensions/fetchers/client.rb
def parse type, body
case type
when %r(application/([[:alnum:]][\w!#&\-^$]*\+)?json) then source.from_json body
when %r(image/.+) then source.from_image body
when "text/csv" then source.from_csv body
when "text/plain" then source.from_text body
when "text/xml", "application/xml", "application/rss+xml", "application/atom+xml"
source.from_xml body
else Failure "Unknown MIME Type: #{type}." # <-- text/calendar lands here
end
end
And the Source module has no calendar decoder:
app/aspects/extensions/source.rb
module Source
def from_csv body ... end
def from_image(body) ... end
def from_json body ... end
def from_text body ... end
def from_xml body ... end
# no from_ical
end
So a Poll extension pointed at an .ics URL (served as text/calendar) fails with
Unknown MIME Type: text/calendar.
Proposed change
- Add a
from_ical decoder to Source that parses the ICS body and returns an array of
event hashes (mirroring how from_csv returns an array of row hashes), so existing
Liquid templates can iterate events the same way they iterate CSV rows. Suggested per-event
shape: { summary:, description:, location:, starts_at:, ends_at:, all_day:, url: }, with
times normalized to ISO-8601. Recurrence expansion (RRULE) into a bounded future window is
desirable but could be a follow-up.
- Register
text/calendar in Client#parse.
A well-maintained gem such as icalendar handles the
parsing (VEVENT, DTSTART/DTEND, all-day vs timed, TZID). Failure cases return Failure like the
other decoders.
Prior art / duplication check
I searched the full issue history (open + closed) — there is no existing issue or PR about
calendar / ICS / iCal support. Discussions are disabled on the repo, so an issue is the right
place to gauge interest.
Offer
Happy to implement this as a PR (decoder + MIME registration + specs) if the direction is
welcome. Would you prefer the event array shape above, or a different normalized schema?
Why
A very common self-hosted use case for a TRMNL/BYOS screen is showing an upcoming-events
calendar (iCloud, Google, Nextcloud, Outlook — all publish
.icsfeeds). Today Terminuscan poll JSON/CSV/XML/plain/image sources, but not an ICS feed, so users have to run a
separate side-car service that converts
text/calendar→ JSON just to feed a Poll extension.Native ICS support would remove that side-car entirely and make "calendar on a TRMNL" a
first-class, no-extra-container setup.
Current behavior
The fetcher client only recognizes a fixed set of MIME types and rejects everything else:
app/aspects/extensions/fetchers/client.rbAnd the
Sourcemodule has no calendar decoder:app/aspects/extensions/source.rbSo a Poll extension pointed at an
.icsURL (served astext/calendar) fails withUnknown MIME Type: text/calendar.Proposed change
from_icaldecoder toSourcethat parses the ICS body and returns an array ofevent hashes (mirroring how
from_csvreturns an array of row hashes), so existingLiquid templates can iterate events the same way they iterate CSV rows. Suggested per-event
shape:
{ summary:, description:, location:, starts_at:, ends_at:, all_day:, url: }, withtimes normalized to ISO-8601. Recurrence expansion (
RRULE) into a bounded future window isdesirable but could be a follow-up.
text/calendarinClient#parse.A well-maintained gem such as
icalendarhandles theparsing (VEVENT, DTSTART/DTEND, all-day vs timed, TZID). Failure cases return
Failurelike theother decoders.
Prior art / duplication check
I searched the full issue history (open + closed) — there is no existing issue or PR about
calendar / ICS / iCal support. Discussions are disabled on the repo, so an issue is the right
place to gauge interest.
Offer
Happy to implement this as a PR (decoder + MIME registration + specs) if the direction is
welcome. Would you prefer the event array shape above, or a different normalized schema?