Skip to content

Commit 528add5

Browse files
perf(calendar): pre-filter ICS data before parsing
1 parent b9be026 commit 528add5

4 files changed

Lines changed: 34 additions & 2 deletions

File tree

cspell.config.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,7 @@
257257
"pubdate",
258258
"radokristof",
259259
"rajniszp",
260+
"RDATE",
260261
"rebuilded",
261262
"Reis",
262263
"rejas",
@@ -364,7 +365,8 @@
364365
"xxxe",
365366
"Ybbet",
366367
"yearmatch",
367-
"yearmatchgroup"
368+
"yearmatchgroup",
369+
"YYYYMMDDTHHMMSSZ"
368370
],
369371
"ignorePaths": [
370372
"css/roboto.css",

defaultmodules/calendar/calendarfetcher.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
const ical = require("node-ical");
2+
const moment = require("moment-timezone");
23
const Log = require("logger");
34
const CalendarFetcherUtils = require("./calendarfetcherutils");
45
const HTTPFetcher = require("#http_fetcher");
@@ -59,7 +60,13 @@ class CalendarFetcher {
5960
}
6061

6162
const responseData = await response.text();
62-
const parsed = await ical.async.parseICS(responseData);
63+
64+
// ics-filter is ESM-only, so we import it dynamically from this CommonJS file.
65+
const { icsFilter } = await import("ics-filter");
66+
const [windowStart, windowEnd] = this.#filterWindow();
67+
const filteredData = icsFilter(responseData, windowStart, windowEnd);
68+
69+
const parsed = await ical.async.parseICS(filteredData);
6370

6471
Log.debug(`Parsed iCal data from ${this.url} with ${Object.keys(parsed).length} entries.`);
6572

@@ -94,6 +101,21 @@ class CalendarFetcher {
94101
this.httpFetcher.startPeriodicFetch();
95102
}
96103

104+
/**
105+
* Time window of events to keep, as [start, end].
106+
* Without includePastEvents the window starts now; otherwise it also
107+
* reaches maximumNumberOfDays into the past.
108+
* @returns {[Date, Date]} The inclusive start and end of the window.
109+
*/
110+
#filterWindow () {
111+
const today = moment().startOf("day");
112+
const start = this.includePastEvents
113+
? today.clone().subtract(this.maximumNumberOfDays, "days").toDate()
114+
: new Date();
115+
const end = today.clone().add(this.maximumNumberOfDays, "days").toDate();
116+
return [start, end];
117+
}
118+
97119
/**
98120
* Check if enough time has passed since the last fetch to warrant a new one.
99121
* Uses reloadInterval as the threshold to respect user's configured fetchInterval.

package-lock.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
"helmet": "^8.2.0",
9494
"html-to-text": "^10.0.0",
9595
"iconv-lite": "^0.7.2",
96+
"ics-filter": "^1.0.2",
9697
"ipaddr.js": "^2.4.0",
9798
"moment": "^2.30.1",
9899
"moment-timezone": "^0.6.2",

0 commit comments

Comments
 (0)