Macotron

macotron.calendar

Read upcoming events from every calendar on the Mac, including iCloud, Google, and Exchange accounts added in System Settings. Each event comes with its video-call join link when it has one.

const events = await macotron.calendar.upcoming({ hours: 8 });
const next = events.find((e) => !e.allDay && e.start > Date.now());
if (next) {
  macotron.menubar.status("next-meeting", {
    title: next.title,
    onClick: () => next.url && macotron.url.open(next.url),
  });
}

Events

upcoming(opts?: { hours?: number; calendars?: string[]; from?: number }): Promise<Array<{ id, title, start, end, allDay, location, calendar, url }>>

Events that overlap a time window, soonest first. The fetch runs off the main thread.

OptionDefaultMeaning
hours24The window ends this many hours from now.
fromnowWhere the window starts, in milliseconds since 1970. Use it to also get events that are already over, such as earlier today. A time after now is treated as now.
calendarsallOnly search calendars with these names. Omit it, or pass [], to search every calendar.

A calendar's name is its title. When two accounts have a calendar with the same title, each name gets the account in parentheses, such as "Work (Google)". A bare title matches every calendar with that title. When none of the names match a calendar, the result is [].

A calendars option in macotron.plugin() shows the user a checkbox list of their calendars in Settings. Pass its value straight to upcoming(); an empty selection means every calendar.

FieldMeaning
idThe event's identifier.
titleThe event title, or "".
start, endMilliseconds since 1970.
allDayWhether it is an all-day event.
locationThe location text, or "".
calendarThe calendar's title, without the account.
urlThe join link, or "".

For url, Macotron collects every https:// link in the event's URL field, location, and notes, in that order. A Google Meet, Zoom, Microsoft Teams, or Webex link wins. Otherwise it is the first link found.

Macotron needs Calendars access. The first call asks macOS to show the permission prompt and resolves with [] while the user decides. Call again after access is granted. If access is denied, every call resolves with []; turn it on in System Settings → Privacy & Security → Calendars.

// Everything today, including meetings that are over.
const midnight = new Date();
midnight.setHours(0, 0, 0, 0);
const today = await macotron.calendar.upcoming({
  from: midnight.getTime(),
  hours: (midnight.getTime() + 86400000 - Date.now()) / 3600000,
});

See also