Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,26 @@ See [advanced Templated usage example](https://github.com/cloud-atlas-ai/obsidia

You can see the available fields an the [Event interface](https://github.com/cloud-atlas-ai/obsidian-ics/blob/master/src/IEvent.ts).

### Full Calendar

```javascript
const { renderCalendar } = app.plugins.getPlugin("obsidian-full-calendar");
const thisWeek = Array.from({length: 7}).map((_, weekday) => moment().set({weekday}).format("YYYY-MM-DD"))
const icsPlugin = app.plugins.getPlugin('ics')
const events = (await icsPlugin.getEvents(...thisWeek))
.map(event => {
const start = moment.unix(event.utime)
const [endHours, endMinutes] = event.endTime.split(":")
return {
start: start.toDate(),
end: start.set({hour: endHours, minute: endMinutes}).toDate(),
title: event.summary,
}
}
)
renderCalendar(this.container, {events}).render()
```

## Support

If you want to support my work, you can [buy me a coffee](https://www.buymeacoffee.com/muness)
Expand Down
25 changes: 13 additions & 12 deletions src/icalUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ function isExcluded(recurrenceDate: moment.Moment, exdateArray: moment.Moment[])
return exdateArray.some(exDate => exDate.isSame(recurrenceDate, 'day'));
}

function processRecurrenceOverrides(event: any, dayToMatch: string, excludedDates: moment.Moment[], matchingEvents: any[]) {
function processRecurrenceOverrides(event: any, sortedDaysToMatch: string[], excludedDates: moment.Moment[], matchingEvents: any[]) {
for (const date in event.recurrences) {
const recurrence = event.recurrences[date];
const recurrenceMoment = moment(date).startOf('day');
Expand All @@ -56,20 +56,20 @@ function processRecurrenceOverrides(event: any, dayToMatch: string, excludedDate
recurrence.recurrent = true;

// Check if this override matches the dayToMatch
if (moment(recurrence.start).isSame(dayToMatch, "day")) {
if (moment(recurrence.start).isBetween(sortedDaysToMatch.first(), sortedDaysToMatch.last(), "day", "[]")) {
console.debug(`Adding recurring event with override: ${recurrence.summary} on ${recurrenceMoment.format('YYYY-MM-DD')}`);
recurrence.eventType = "recurring override";
matchingEvents.push(recurrence);
}
}
}

function processRecurringRules(event: any, dayToMatch: string, excludedDates: moment.Moment[], matchingEvents: any[]) {
const localStartOfYesterday = moment(dayToMatch).subtract(1, 'day').startOf('day').toDate();
const localEndOfTomorrow = moment(dayToMatch).add(1, 'day').endOf('day').toDate();
function processRecurringRules(event: any, sortedDaysToMatch: string[], excludedDates: moment.Moment[], matchingEvents: any[]) {
const localStartOfRange = moment(sortedDaysToMatch.first()).subtract(1, 'day').startOf('day').toDate();
const localEndOfRange = moment(sortedDaysToMatch.last()).add(1, 'day').endOf('day').toDate();

// Get recurrence dates within the range
const recurrenceDates = event.rrule.between(localStartOfYesterday, localEndOfTomorrow, true);
const recurrenceDates = event.rrule.between(localStartOfRange, localEndOfRange, true);

recurrenceDates.forEach(recurrenceDate => {
const recurrenceMoment = tz(recurrenceDate, event.rrule.origOptions.tzid || 'UTC');
Expand All @@ -87,7 +87,7 @@ function processRecurringRules(event: any, dayToMatch: string, excludedDates: mo
delete clonedEvent.rrule;
clonedEvent.recurrent = true;

if (moment(clonedEvent.start).isSame(dayToMatch, 'day')) {
if (moment(clonedEvent.start).isBetween(sortedDaysToMatch.first(), sortedDaysToMatch.last(), 'day', '[]')) {
console.debug(`Adding recurring event: ${clonedEvent.summary} ${clonedEvent.start} - ${clonedEvent.end}`);
console.debug("Excluded dates:", excludedDates.map(date => date.format('YYYY-MM-DD')));

Expand All @@ -102,7 +102,8 @@ function shouldIncludeOngoing(event: any, dayToMatch: string): boolean {
return moment(dayToMatch).isBetween(moment(event.start), moment(event.end), "day");
}

export function filterMatchingEvents(icsArray: any[], dayToMatch: string, showOngoing: boolean) {
export function filterMatchingEvents(icsArray: any[], daysToMatch: string[], showOngoing: boolean) {
const sortedDaysToMatch = [...daysToMatch].sort();
return icsArray.reduce((matchingEvents, event) => {
// Skip canceled parent events
if (event.status && event.status.toUpperCase() === "CANCELLED") {
Expand All @@ -127,16 +128,16 @@ export function filterMatchingEvents(icsArray: any[], dayToMatch: string, showOn

// Process recurrence overrides to populate matching events and excluded dates
if (event.recurrences) {
processRecurrenceOverrides(event, dayToMatch, excludedDates, matchingEvents);
processRecurrenceOverrides(event, sortedDaysToMatch, excludedDates, matchingEvents);
}

// Process recurring rules, skipping overridden dates
if (event.rrule) {
processRecurringRules(event, dayToMatch, excludedDates, matchingEvents);
processRecurringRules(event, sortedDaysToMatch, excludedDates, matchingEvents)
}

// Process non-recurring events
if (!event.recurrences && !event.rrule && moment(event.start).isSame(dayToMatch, "day")) {
if (!event.recurrences && !event.rrule && moment(event.start).isBetween(sortedDaysToMatch.first(), sortedDaysToMatch.last(), "day", "[]")) {
console.debug("Adding one-off event:", {
summary: event.summary,
start: event.start,
Expand All @@ -149,7 +150,7 @@ export function filterMatchingEvents(icsArray: any[], dayToMatch: string, showOn
}

// Include ongoing events
if (showOngoing && shouldIncludeOngoing(event, dayToMatch)) {
if (showOngoing && daysToMatch.some(dayToMatch => shouldIncludeOngoing(event, dayToMatch))) {
matchingEvents.push(event);
}

Expand Down
4 changes: 2 additions & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default class ICSPlugin extends Plugin {
}


async getEvents(date: string): Promise<IEvent[]> {
async getEvents(...dates: string[]): Promise<IEvent[]> {
let events: IEvent[] = [];
let errorMessages: string[] = []; // To store error messages

Expand Down Expand Up @@ -97,7 +97,7 @@ export default class ICSPlugin extends Plugin {

// Exception handling for parsing and filtering
try {
dateEvents = dateEvents = filterMatchingEvents(icsArray, date, calendarSetting.format.showOngoing)
dateEvents = dateEvents = filterMatchingEvents(icsArray, dates, calendarSetting.format.showOngoing)
.filter(e => this.excludeTransparentEvents(e, calendarSetting))
.filter(e => this.excludeDeclinedEvents(e, calendarSetting));

Expand Down