Files
MagicMirror/defaultmodules/calendar/calendarfetcherutils.js

277 lines
9.1 KiB
JavaScript
Raw Permalink Normal View History

Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
/**
* @external Moment
*/
const moment = require("moment-timezone");
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
const ical = require("node-ical");
Release 2.26.0 (#3319) ## [2.26.0] - 01-01-2024 Thanks to: @bnitkin, @bugsounet, @dependabot, @jkriegshauser, @kaennchenstruggle, @KristjanESPERANTO and @Ybbet. Special thanks to @khassel, @rejas and @sdetweil for taking over most (if not all) of the work on this release as project collaborators. This version would not be there without their effort. Thank you guys! You are awesome! This release also marks the latest release by Michael Teeuw. For more info, please read the following post: [A New Chapter for MagicMirror: The Community Takes the Lead](https://forum.magicmirror.builders/topic/18329/a-new-chapter-for-magicmirror-the-community-takes-the-lead). ### Added - Added update notification updater (for 3rd party modules) - Added node 21 to the test matrix - Added transform object to calendar:customEvents - Added ESLint rules for jest (including jest/expect-expect and jest/no-done-callback) ### Removed - Removed Codecov workflow (not working anymore, other workflow required) (#3107) - Removed titleReplace from calendar, replaced + extended by customEvents (backward compatibility included) (#3249) - Removed failing unit test (#3254) - Removed some unused variables ### Updated - Update electron to v27 and update other dependencies as well as github actions - Update newsfeed: Use `html-to-text` instead of regex for transform description - Review ESLint config (#3269) - Updated dependencies - Clock module: optionally display current moon phase in addition to rise/set times - electron is now per default started without gpu, if needed it must be enabled with new env var `ELECTRON_ENABLE_GPU=1` on startup (#3226) - Replace prettier by stylistic in ESLint config to lint JavaScript (and disable some rules for `config/config.js*` files) - Update node-ical to v0.17.1 and fix tests ### Fixed - Avoid fade out/in on updateDom when many calendars are used - Fix the option eventClass on customEvents. - Fix yr API version in locationforecast and sunrise call (#3227) - Fix cloneObject() function to respect RegExp (#3237) - Fix newsfeed module for feeds using "a10:updated" tag (#3238) - Fix issue template (#3167) - Fix #3256 filter out bad results from rrule.between - Fix calendar events sometimes not respecting deleted events (#3250) - Fix electron loadurl locally on Windows when address "0.0.0.0" (#2550) - Fix updatanotification (update_helper.js): catch error if reponse is not an JSON format (check PM2) - Fix missing typeof in calendar module - Fix style issues after prettier update - Fix calendar test (#3291) by moving "Exdate check" from e2e to electron to run on a Thursday - Fix calendar config params `fetchInterval` and `excludedEvents` were never used from single calendar config (#3297) - Fix MM_PORT variable not used in electron and allow full path for MM_CONFIG_FILE variable (#3302) --------- Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Knapoc <Knapoc@users.noreply.github.com> Co-authored-by: sam detweiler <sdetweil@gmail.com> Co-authored-by: veeck <michael.veeck@nebenan.de> Co-authored-by: Paranoid93 <6515818+Paranoid93@users.noreply.github.com> Co-authored-by: NolanKingdon <27908974+NolanKingdon@users.noreply.github.com> Co-authored-by: J. Kenzal Hunter <kenzal.hunter@gmail.com> Co-authored-by: Teddy <teddy.payet@gmail.com> Co-authored-by: TeddyStarinvest <teddy.payet@starinvest.com> Co-authored-by: martingron <61826403+martingron@users.noreply.github.com> Co-authored-by: dgoth <132394363+dgoth@users.noreply.github.com> Co-authored-by: kaennchenstruggle <54073894+kaennchenstruggle@users.noreply.github.com> Co-authored-by: jkriegshauser <jkriegshauser@gmail.com> Co-authored-by: Ben Nitkin <ben@nitkin.net>
2024-01-01 15:38:08 +01:00
const Log = require("logger");
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
const CalendarFetcherUtils = {
Release 2.26.0 (#3319) ## [2.26.0] - 01-01-2024 Thanks to: @bnitkin, @bugsounet, @dependabot, @jkriegshauser, @kaennchenstruggle, @KristjanESPERANTO and @Ybbet. Special thanks to @khassel, @rejas and @sdetweil for taking over most (if not all) of the work on this release as project collaborators. This version would not be there without their effort. Thank you guys! You are awesome! This release also marks the latest release by Michael Teeuw. For more info, please read the following post: [A New Chapter for MagicMirror: The Community Takes the Lead](https://forum.magicmirror.builders/topic/18329/a-new-chapter-for-magicmirror-the-community-takes-the-lead). ### Added - Added update notification updater (for 3rd party modules) - Added node 21 to the test matrix - Added transform object to calendar:customEvents - Added ESLint rules for jest (including jest/expect-expect and jest/no-done-callback) ### Removed - Removed Codecov workflow (not working anymore, other workflow required) (#3107) - Removed titleReplace from calendar, replaced + extended by customEvents (backward compatibility included) (#3249) - Removed failing unit test (#3254) - Removed some unused variables ### Updated - Update electron to v27 and update other dependencies as well as github actions - Update newsfeed: Use `html-to-text` instead of regex for transform description - Review ESLint config (#3269) - Updated dependencies - Clock module: optionally display current moon phase in addition to rise/set times - electron is now per default started without gpu, if needed it must be enabled with new env var `ELECTRON_ENABLE_GPU=1` on startup (#3226) - Replace prettier by stylistic in ESLint config to lint JavaScript (and disable some rules for `config/config.js*` files) - Update node-ical to v0.17.1 and fix tests ### Fixed - Avoid fade out/in on updateDom when many calendars are used - Fix the option eventClass on customEvents. - Fix yr API version in locationforecast and sunrise call (#3227) - Fix cloneObject() function to respect RegExp (#3237) - Fix newsfeed module for feeds using "a10:updated" tag (#3238) - Fix issue template (#3167) - Fix #3256 filter out bad results from rrule.between - Fix calendar events sometimes not respecting deleted events (#3250) - Fix electron loadurl locally on Windows when address "0.0.0.0" (#2550) - Fix updatanotification (update_helper.js): catch error if reponse is not an JSON format (check PM2) - Fix missing typeof in calendar module - Fix style issues after prettier update - Fix calendar test (#3291) by moving "Exdate check" from e2e to electron to run on a Thursday - Fix calendar config params `fetchInterval` and `excludedEvents` were never used from single calendar config (#3297) - Fix MM_PORT variable not used in electron and allow full path for MM_CONFIG_FILE variable (#3302) --------- Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Knapoc <Knapoc@users.noreply.github.com> Co-authored-by: sam detweiler <sdetweil@gmail.com> Co-authored-by: veeck <michael.veeck@nebenan.de> Co-authored-by: Paranoid93 <6515818+Paranoid93@users.noreply.github.com> Co-authored-by: NolanKingdon <27908974+NolanKingdon@users.noreply.github.com> Co-authored-by: J. Kenzal Hunter <kenzal.hunter@gmail.com> Co-authored-by: Teddy <teddy.payet@gmail.com> Co-authored-by: TeddyStarinvest <teddy.payet@starinvest.com> Co-authored-by: martingron <61826403+martingron@users.noreply.github.com> Co-authored-by: dgoth <132394363+dgoth@users.noreply.github.com> Co-authored-by: kaennchenstruggle <54073894+kaennchenstruggle@users.noreply.github.com> Co-authored-by: jkriegshauser <jkriegshauser@gmail.com> Co-authored-by: Ben Nitkin <ben@nitkin.net>
2024-01-01 15:38:08 +01:00
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
/**
* Determine based on the title of an event if it should be excluded from the list of events
* @param {object} config the global config
* @param {string} title the title of the event
* @returns {object} excluded: true if the event should be excluded, false otherwise
* until: the date until the event should be excluded.
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
*/
shouldEventBeExcluded (config, title) {
[calendar] fix: prevent excessive fetching on client reload and refactor `calendarfetcherutils.js` (#3976) The bottom line of this PR is, that it fixes an issue and simplifies the code by dealing with the TODOs in the code. For review, I suggest looking at each commit individually. If there are too many changes for a PR, let me know and I'll split it up :slightly_smiling_face: ## 1. [fix(calendar): prevent excessive fetching with smart refresh strategy](https://github.com/MagicMirrorOrg/MagicMirror/pull/3976/commits/8892cd3d5aa3aca45ccc97e1eaff4685c98b3fcd) - Add lastFetch timestamp tracking to CalendarFetcher - Add shouldRefetch() method with configurable minimum interval (default: 3 minutes) - When reusing existing fetcher: fetch if data is stale (>3 min), otherwise broadcast cached events - Prevents double broadcasts to consuming modules while maintaining fresh data - Balances rate limit prevention (Issue https://github.com/MagicMirrorOrg/MagicMirror/issues/3971) with data freshness on user reload - Prevents excessive fetching during rapid reloads (e.g., Fully Kiosk screensaver use case) - Allows fresh calendar data when enough time has passed since last fetch ## 2. [refactor(calendar): simplify event exclusion logic](https://github.com/MagicMirrorOrg/MagicMirror/commit/d507aba82d68bb0feb0c3b45a321f9407f95d311) - Extract filtering logic from `shouldEventBeExcluded` into new helper `checkEventAgainstFilter` - Simplify the main loop in `shouldEventBeExcluded It resolves a TODO from the comments in the code: * `This seems like an overly complicated way to exclude events based on the title.` ## 3. [refactor(calendar): extract recurring event expansion logic](https://github.com/MagicMirrorOrg/MagicMirror/commit/d510160bd214d1440cb8c2f7598cf48ec0c19c36) This change separates the expansion of recurring events from the main filtering loop into a new helper function 'expandRecurringEvent'. It resolves two TODOs from the comments in the code: - `This should be a separate function` - `This should create an event per moment so we can change anything we want` This improves code readability, reduces complexity in 'filterEvents', and allows for cleaner handling of individual recurrence instances. ## 4. [refactor(calendar): simplify recurring event handling](https://github.com/MagicMirrorOrg/MagicMirror/commit/b04f716cc0f74883bbcf8d812d76ee56ebca8fe5) - Simplify 'getMomentsFromRecurringEvent' using modern syntax - Improve handling of full-day events across different timezones ## 5. [test(calendar): fix UNTIL date in fullday_until.ics fixture](https://github.com/MagicMirrorOrg/MagicMirror/pull/3976/commits/1d762b2ade2b24e157e66b83774cdef4ccc95c52) The issue was with the UNTIL date being May 4th while DTSTART was May 5th. This created an invalid recurrence rule where the end date came before the start date. The fix only adjusts the UNTIL date from May 4th to May 5th, so it matches the start date.
2025-12-08 10:07:04 +01:00
for (const filterConfig of config.excludedEvents) {
const match = CalendarFetcherUtils.checkEventAgainstFilter(title, filterConfig);
if (match) {
return {
excluded: !match.until,
until: match.until
};
}
}
return {
excluded: false,
until: null
};
},
/**
* Get local timezone.
* This method makes it easier to test if different timezones cause problems by changing this implementation.
* @returns {string} timezone
*/
getLocalTimezone () {
return moment.tz.guess();
},
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
/**
* Filter the events from ical according to the given config
* @param {object} data the calendar data from ical
* @param {object} config The configuration object
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
* @returns {object[]} the filtered events
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
*/
Release 2.26.0 (#3319) ## [2.26.0] - 01-01-2024 Thanks to: @bnitkin, @bugsounet, @dependabot, @jkriegshauser, @kaennchenstruggle, @KristjanESPERANTO and @Ybbet. Special thanks to @khassel, @rejas and @sdetweil for taking over most (if not all) of the work on this release as project collaborators. This version would not be there without their effort. Thank you guys! You are awesome! This release also marks the latest release by Michael Teeuw. For more info, please read the following post: [A New Chapter for MagicMirror: The Community Takes the Lead](https://forum.magicmirror.builders/topic/18329/a-new-chapter-for-magicmirror-the-community-takes-the-lead). ### Added - Added update notification updater (for 3rd party modules) - Added node 21 to the test matrix - Added transform object to calendar:customEvents - Added ESLint rules for jest (including jest/expect-expect and jest/no-done-callback) ### Removed - Removed Codecov workflow (not working anymore, other workflow required) (#3107) - Removed titleReplace from calendar, replaced + extended by customEvents (backward compatibility included) (#3249) - Removed failing unit test (#3254) - Removed some unused variables ### Updated - Update electron to v27 and update other dependencies as well as github actions - Update newsfeed: Use `html-to-text` instead of regex for transform description - Review ESLint config (#3269) - Updated dependencies - Clock module: optionally display current moon phase in addition to rise/set times - electron is now per default started without gpu, if needed it must be enabled with new env var `ELECTRON_ENABLE_GPU=1` on startup (#3226) - Replace prettier by stylistic in ESLint config to lint JavaScript (and disable some rules for `config/config.js*` files) - Update node-ical to v0.17.1 and fix tests ### Fixed - Avoid fade out/in on updateDom when many calendars are used - Fix the option eventClass on customEvents. - Fix yr API version in locationforecast and sunrise call (#3227) - Fix cloneObject() function to respect RegExp (#3237) - Fix newsfeed module for feeds using "a10:updated" tag (#3238) - Fix issue template (#3167) - Fix #3256 filter out bad results from rrule.between - Fix calendar events sometimes not respecting deleted events (#3250) - Fix electron loadurl locally on Windows when address "0.0.0.0" (#2550) - Fix updatanotification (update_helper.js): catch error if reponse is not an JSON format (check PM2) - Fix missing typeof in calendar module - Fix style issues after prettier update - Fix calendar test (#3291) by moving "Exdate check" from e2e to electron to run on a Thursday - Fix calendar config params `fetchInterval` and `excludedEvents` were never used from single calendar config (#3297) - Fix MM_PORT variable not used in electron and allow full path for MM_CONFIG_FILE variable (#3302) --------- Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Knapoc <Knapoc@users.noreply.github.com> Co-authored-by: sam detweiler <sdetweil@gmail.com> Co-authored-by: veeck <michael.veeck@nebenan.de> Co-authored-by: Paranoid93 <6515818+Paranoid93@users.noreply.github.com> Co-authored-by: NolanKingdon <27908974+NolanKingdon@users.noreply.github.com> Co-authored-by: J. Kenzal Hunter <kenzal.hunter@gmail.com> Co-authored-by: Teddy <teddy.payet@gmail.com> Co-authored-by: TeddyStarinvest <teddy.payet@starinvest.com> Co-authored-by: martingron <61826403+martingron@users.noreply.github.com> Co-authored-by: dgoth <132394363+dgoth@users.noreply.github.com> Co-authored-by: kaennchenstruggle <54073894+kaennchenstruggle@users.noreply.github.com> Co-authored-by: jkriegshauser <jkriegshauser@gmail.com> Co-authored-by: Ben Nitkin <ben@nitkin.net>
2024-01-01 15:38:08 +01:00
filterEvents (data, config) {
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
const newEvents = [];
Log.debug(`There are ${Object.entries(data).length} calendar entries.`);
const now = moment();
const pastLocalMoment = config.includePastEvents ? now.clone().startOf("day").subtract(config.maximumNumberOfDays, "days") : now;
const futureLocalMoment
= now
.clone()
.startOf("day")
.add(config.maximumNumberOfDays, "days")
// Subtract 1 second so that events that start on the middle of the night will not repeat.
.subtract(1, "seconds");
Object.values(data).forEach((event) => {
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
if (event.type !== "VEVENT") {
return;
}
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
const title = CalendarFetcherUtils.getTitleFromEvent(event);
Log.debug(`title: ${title}`);
// Return quickly if event should be excluded.
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
const { excluded, until: eventFilterUntil } = CalendarFetcherUtils.shouldEventBeExcluded(config, title);
if (excluded) {
return;
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
}
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
Log.debug(`Event: ${title} | start: ${event.start} | end: ${event.end} | recurring: ${!!event.rrule}`);
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
const location = CalendarFetcherUtils.unwrapParameterValue(event.location) || false;
const geo = event.geo || false;
const description = CalendarFetcherUtils.unwrapParameterValue(event.description) || false;
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
let instances;
try {
instances = CalendarFetcherUtils.expandRecurringEvent(event, pastLocalMoment, futureLocalMoment);
} catch (error) {
Log.error(`Could not expand event "${title}": ${error.message}`);
return;
}
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
for (const instance of instances) {
const { event: instanceEvent, startMoment, endMoment, isRecurring, isFullDay } = instance;
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
// Filter logic
if (endMoment.isBefore(pastLocalMoment) || startMoment.isAfter(futureLocalMoment)) {
continue;
[calendar] fix: prevent excessive fetching on client reload and refactor `calendarfetcherutils.js` (#3976) The bottom line of this PR is, that it fixes an issue and simplifies the code by dealing with the TODOs in the code. For review, I suggest looking at each commit individually. If there are too many changes for a PR, let me know and I'll split it up :slightly_smiling_face: ## 1. [fix(calendar): prevent excessive fetching with smart refresh strategy](https://github.com/MagicMirrorOrg/MagicMirror/pull/3976/commits/8892cd3d5aa3aca45ccc97e1eaff4685c98b3fcd) - Add lastFetch timestamp tracking to CalendarFetcher - Add shouldRefetch() method with configurable minimum interval (default: 3 minutes) - When reusing existing fetcher: fetch if data is stale (>3 min), otherwise broadcast cached events - Prevents double broadcasts to consuming modules while maintaining fresh data - Balances rate limit prevention (Issue https://github.com/MagicMirrorOrg/MagicMirror/issues/3971) with data freshness on user reload - Prevents excessive fetching during rapid reloads (e.g., Fully Kiosk screensaver use case) - Allows fresh calendar data when enough time has passed since last fetch ## 2. [refactor(calendar): simplify event exclusion logic](https://github.com/MagicMirrorOrg/MagicMirror/commit/d507aba82d68bb0feb0c3b45a321f9407f95d311) - Extract filtering logic from `shouldEventBeExcluded` into new helper `checkEventAgainstFilter` - Simplify the main loop in `shouldEventBeExcluded It resolves a TODO from the comments in the code: * `This seems like an overly complicated way to exclude events based on the title.` ## 3. [refactor(calendar): extract recurring event expansion logic](https://github.com/MagicMirrorOrg/MagicMirror/commit/d510160bd214d1440cb8c2f7598cf48ec0c19c36) This change separates the expansion of recurring events from the main filtering loop into a new helper function 'expandRecurringEvent'. It resolves two TODOs from the comments in the code: - `This should be a separate function` - `This should create an event per moment so we can change anything we want` This improves code readability, reduces complexity in 'filterEvents', and allows for cleaner handling of individual recurrence instances. ## 4. [refactor(calendar): simplify recurring event handling](https://github.com/MagicMirrorOrg/MagicMirror/commit/b04f716cc0f74883bbcf8d812d76ee56ebca8fe5) - Simplify 'getMomentsFromRecurringEvent' using modern syntax - Improve handling of full-day events across different timezones ## 5. [test(calendar): fix UNTIL date in fullday_until.ics fixture](https://github.com/MagicMirrorOrg/MagicMirror/pull/3976/commits/1d762b2ade2b24e157e66b83774cdef4ccc95c52) The issue was with the UNTIL date being May 4th while DTSTART was May 5th. This created an invalid recurrence rule where the end date came before the start date. The fix only adjusts the UNTIL date from May 4th to May 5th, so it matches the start date.
2025-12-08 10:07:04 +01:00
}
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
if (CalendarFetcherUtils.timeFilterApplies(now, endMoment, eventFilterUntil)) {
continue;
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
}
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
const instanceTitle = CalendarFetcherUtils.getTitleFromEvent(instanceEvent);
Log.debug(`saving event: ${instanceTitle}, start: ${startMoment.toDate()}, end: ${endMoment.toDate()}`);
newEvents.push({
title: instanceTitle,
startDate: startMoment.format("x"),
endDate: endMoment.format("x"),
fullDayEvent: isFullDay,
recurringEvent: isRecurring,
class: event.class,
firstYear: event.start.getFullYear(),
location: CalendarFetcherUtils.unwrapParameterValue(instanceEvent.location) || location,
geo: instanceEvent.geo || geo,
description: CalendarFetcherUtils.unwrapParameterValue(instanceEvent.description) || description
});
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
}
});
newEvents.sort(function (a, b) {
return a.startDate - b.startDate;
});
return newEvents;
},
/**
* Gets the title from the event.
* @param {object} event The event object to check.
* @returns {string} The title of the event, or "Event" if no title is found.
*/
Release 2.26.0 (#3319) ## [2.26.0] - 01-01-2024 Thanks to: @bnitkin, @bugsounet, @dependabot, @jkriegshauser, @kaennchenstruggle, @KristjanESPERANTO and @Ybbet. Special thanks to @khassel, @rejas and @sdetweil for taking over most (if not all) of the work on this release as project collaborators. This version would not be there without their effort. Thank you guys! You are awesome! This release also marks the latest release by Michael Teeuw. For more info, please read the following post: [A New Chapter for MagicMirror: The Community Takes the Lead](https://forum.magicmirror.builders/topic/18329/a-new-chapter-for-magicmirror-the-community-takes-the-lead). ### Added - Added update notification updater (for 3rd party modules) - Added node 21 to the test matrix - Added transform object to calendar:customEvents - Added ESLint rules for jest (including jest/expect-expect and jest/no-done-callback) ### Removed - Removed Codecov workflow (not working anymore, other workflow required) (#3107) - Removed titleReplace from calendar, replaced + extended by customEvents (backward compatibility included) (#3249) - Removed failing unit test (#3254) - Removed some unused variables ### Updated - Update electron to v27 and update other dependencies as well as github actions - Update newsfeed: Use `html-to-text` instead of regex for transform description - Review ESLint config (#3269) - Updated dependencies - Clock module: optionally display current moon phase in addition to rise/set times - electron is now per default started without gpu, if needed it must be enabled with new env var `ELECTRON_ENABLE_GPU=1` on startup (#3226) - Replace prettier by stylistic in ESLint config to lint JavaScript (and disable some rules for `config/config.js*` files) - Update node-ical to v0.17.1 and fix tests ### Fixed - Avoid fade out/in on updateDom when many calendars are used - Fix the option eventClass on customEvents. - Fix yr API version in locationforecast and sunrise call (#3227) - Fix cloneObject() function to respect RegExp (#3237) - Fix newsfeed module for feeds using "a10:updated" tag (#3238) - Fix issue template (#3167) - Fix #3256 filter out bad results from rrule.between - Fix calendar events sometimes not respecting deleted events (#3250) - Fix electron loadurl locally on Windows when address "0.0.0.0" (#2550) - Fix updatanotification (update_helper.js): catch error if reponse is not an JSON format (check PM2) - Fix missing typeof in calendar module - Fix style issues after prettier update - Fix calendar test (#3291) by moving "Exdate check" from e2e to electron to run on a Thursday - Fix calendar config params `fetchInterval` and `excludedEvents` were never used from single calendar config (#3297) - Fix MM_PORT variable not used in electron and allow full path for MM_CONFIG_FILE variable (#3302) --------- Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Knapoc <Knapoc@users.noreply.github.com> Co-authored-by: sam detweiler <sdetweil@gmail.com> Co-authored-by: veeck <michael.veeck@nebenan.de> Co-authored-by: Paranoid93 <6515818+Paranoid93@users.noreply.github.com> Co-authored-by: NolanKingdon <27908974+NolanKingdon@users.noreply.github.com> Co-authored-by: J. Kenzal Hunter <kenzal.hunter@gmail.com> Co-authored-by: Teddy <teddy.payet@gmail.com> Co-authored-by: TeddyStarinvest <teddy.payet@starinvest.com> Co-authored-by: martingron <61826403+martingron@users.noreply.github.com> Co-authored-by: dgoth <132394363+dgoth@users.noreply.github.com> Co-authored-by: kaennchenstruggle <54073894+kaennchenstruggle@users.noreply.github.com> Co-authored-by: jkriegshauser <jkriegshauser@gmail.com> Co-authored-by: Ben Nitkin <ben@nitkin.net>
2024-01-01 15:38:08 +01:00
getTitleFromEvent (event) {
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
return CalendarFetcherUtils.unwrapParameterValue(event.summary || event.description) || "Event";
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
},
/**
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
* Extracts the string value from a node-ical ParameterValue object ({val, params})
* or returns the value as-is if it is already a plain string.
* This handles ICS properties with parameters, e.g. DESCRIPTION;LANGUAGE=de:Text.
* @param {string|object} value The raw value from node-ical
* @returns {string|object} The unwrapped string value, or the original value if not a ParameterValue
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
*/
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
unwrapParameterValue (value) {
if (value && typeof value === "object" && typeof value.val !== "undefined") {
return value.val;
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
}
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
return value;
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
},
/**
* Determines if the user defined time filter should apply
* @param {moment.Moment} now Date object using previously created object for consistency
* @param {moment.Moment} endDate Moment object representing the event end date
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
* @param {string} filter The time to subtract from the end date to determine if an event should be shown
* @returns {boolean} True if the event should be filtered out, false otherwise
*/
Release 2.26.0 (#3319) ## [2.26.0] - 01-01-2024 Thanks to: @bnitkin, @bugsounet, @dependabot, @jkriegshauser, @kaennchenstruggle, @KristjanESPERANTO and @Ybbet. Special thanks to @khassel, @rejas and @sdetweil for taking over most (if not all) of the work on this release as project collaborators. This version would not be there without their effort. Thank you guys! You are awesome! This release also marks the latest release by Michael Teeuw. For more info, please read the following post: [A New Chapter for MagicMirror: The Community Takes the Lead](https://forum.magicmirror.builders/topic/18329/a-new-chapter-for-magicmirror-the-community-takes-the-lead). ### Added - Added update notification updater (for 3rd party modules) - Added node 21 to the test matrix - Added transform object to calendar:customEvents - Added ESLint rules for jest (including jest/expect-expect and jest/no-done-callback) ### Removed - Removed Codecov workflow (not working anymore, other workflow required) (#3107) - Removed titleReplace from calendar, replaced + extended by customEvents (backward compatibility included) (#3249) - Removed failing unit test (#3254) - Removed some unused variables ### Updated - Update electron to v27 and update other dependencies as well as github actions - Update newsfeed: Use `html-to-text` instead of regex for transform description - Review ESLint config (#3269) - Updated dependencies - Clock module: optionally display current moon phase in addition to rise/set times - electron is now per default started without gpu, if needed it must be enabled with new env var `ELECTRON_ENABLE_GPU=1` on startup (#3226) - Replace prettier by stylistic in ESLint config to lint JavaScript (and disable some rules for `config/config.js*` files) - Update node-ical to v0.17.1 and fix tests ### Fixed - Avoid fade out/in on updateDom when many calendars are used - Fix the option eventClass on customEvents. - Fix yr API version in locationforecast and sunrise call (#3227) - Fix cloneObject() function to respect RegExp (#3237) - Fix newsfeed module for feeds using "a10:updated" tag (#3238) - Fix issue template (#3167) - Fix #3256 filter out bad results from rrule.between - Fix calendar events sometimes not respecting deleted events (#3250) - Fix electron loadurl locally on Windows when address "0.0.0.0" (#2550) - Fix updatanotification (update_helper.js): catch error if reponse is not an JSON format (check PM2) - Fix missing typeof in calendar module - Fix style issues after prettier update - Fix calendar test (#3291) by moving "Exdate check" from e2e to electron to run on a Thursday - Fix calendar config params `fetchInterval` and `excludedEvents` were never used from single calendar config (#3297) - Fix MM_PORT variable not used in electron and allow full path for MM_CONFIG_FILE variable (#3302) --------- Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Knapoc <Knapoc@users.noreply.github.com> Co-authored-by: sam detweiler <sdetweil@gmail.com> Co-authored-by: veeck <michael.veeck@nebenan.de> Co-authored-by: Paranoid93 <6515818+Paranoid93@users.noreply.github.com> Co-authored-by: NolanKingdon <27908974+NolanKingdon@users.noreply.github.com> Co-authored-by: J. Kenzal Hunter <kenzal.hunter@gmail.com> Co-authored-by: Teddy <teddy.payet@gmail.com> Co-authored-by: TeddyStarinvest <teddy.payet@starinvest.com> Co-authored-by: martingron <61826403+martingron@users.noreply.github.com> Co-authored-by: dgoth <132394363+dgoth@users.noreply.github.com> Co-authored-by: kaennchenstruggle <54073894+kaennchenstruggle@users.noreply.github.com> Co-authored-by: jkriegshauser <jkriegshauser@gmail.com> Co-authored-by: Ben Nitkin <ben@nitkin.net>
2024-01-01 15:38:08 +01:00
timeFilterApplies (now, endDate, filter) {
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
if (filter) {
const until = filter.split(" "),
value = parseInt(until[0]),
increment = until[1].slice(-1) === "s" ? until[1] : `${until[1]}s`, // Massage the data for moment js
filterUntil = moment(endDate.format()).subtract(value, increment);
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
return now.isBefore(filterUntil);
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
}
return false;
},
/**
* Determines if the user defined title filter should apply
* @param {string} title the title of the event
* @param {string} filter the string to look for, can be a regex also
* @param {boolean} useRegex true if a regex should be used, otherwise it just looks for the filter as a string
* @param {string} regexFlags flags that should be applied to the regex
* @returns {boolean} True if the title should be filtered out, false otherwise
*/
Release 2.26.0 (#3319) ## [2.26.0] - 01-01-2024 Thanks to: @bnitkin, @bugsounet, @dependabot, @jkriegshauser, @kaennchenstruggle, @KristjanESPERANTO and @Ybbet. Special thanks to @khassel, @rejas and @sdetweil for taking over most (if not all) of the work on this release as project collaborators. This version would not be there without their effort. Thank you guys! You are awesome! This release also marks the latest release by Michael Teeuw. For more info, please read the following post: [A New Chapter for MagicMirror: The Community Takes the Lead](https://forum.magicmirror.builders/topic/18329/a-new-chapter-for-magicmirror-the-community-takes-the-lead). ### Added - Added update notification updater (for 3rd party modules) - Added node 21 to the test matrix - Added transform object to calendar:customEvents - Added ESLint rules for jest (including jest/expect-expect and jest/no-done-callback) ### Removed - Removed Codecov workflow (not working anymore, other workflow required) (#3107) - Removed titleReplace from calendar, replaced + extended by customEvents (backward compatibility included) (#3249) - Removed failing unit test (#3254) - Removed some unused variables ### Updated - Update electron to v27 and update other dependencies as well as github actions - Update newsfeed: Use `html-to-text` instead of regex for transform description - Review ESLint config (#3269) - Updated dependencies - Clock module: optionally display current moon phase in addition to rise/set times - electron is now per default started without gpu, if needed it must be enabled with new env var `ELECTRON_ENABLE_GPU=1` on startup (#3226) - Replace prettier by stylistic in ESLint config to lint JavaScript (and disable some rules for `config/config.js*` files) - Update node-ical to v0.17.1 and fix tests ### Fixed - Avoid fade out/in on updateDom when many calendars are used - Fix the option eventClass on customEvents. - Fix yr API version in locationforecast and sunrise call (#3227) - Fix cloneObject() function to respect RegExp (#3237) - Fix newsfeed module for feeds using "a10:updated" tag (#3238) - Fix issue template (#3167) - Fix #3256 filter out bad results from rrule.between - Fix calendar events sometimes not respecting deleted events (#3250) - Fix electron loadurl locally on Windows when address "0.0.0.0" (#2550) - Fix updatanotification (update_helper.js): catch error if reponse is not an JSON format (check PM2) - Fix missing typeof in calendar module - Fix style issues after prettier update - Fix calendar test (#3291) by moving "Exdate check" from e2e to electron to run on a Thursday - Fix calendar config params `fetchInterval` and `excludedEvents` were never used from single calendar config (#3297) - Fix MM_PORT variable not used in electron and allow full path for MM_CONFIG_FILE variable (#3302) --------- Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Knapoc <Knapoc@users.noreply.github.com> Co-authored-by: sam detweiler <sdetweil@gmail.com> Co-authored-by: veeck <michael.veeck@nebenan.de> Co-authored-by: Paranoid93 <6515818+Paranoid93@users.noreply.github.com> Co-authored-by: NolanKingdon <27908974+NolanKingdon@users.noreply.github.com> Co-authored-by: J. Kenzal Hunter <kenzal.hunter@gmail.com> Co-authored-by: Teddy <teddy.payet@gmail.com> Co-authored-by: TeddyStarinvest <teddy.payet@starinvest.com> Co-authored-by: martingron <61826403+martingron@users.noreply.github.com> Co-authored-by: dgoth <132394363+dgoth@users.noreply.github.com> Co-authored-by: kaennchenstruggle <54073894+kaennchenstruggle@users.noreply.github.com> Co-authored-by: jkriegshauser <jkriegshauser@gmail.com> Co-authored-by: Ben Nitkin <ben@nitkin.net>
2024-01-01 15:38:08 +01:00
titleFilterApplies (title, filter, useRegex, regexFlags) {
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
if (useRegex) {
let regexFilter = filter;
// Assume if leading slash, there is also trailing slash
if (filter[0] === "/") {
// Strip leading and trailing slashes
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
regexFilter = filter.slice(1, -1);
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
}
return new RegExp(regexFilter, regexFlags).test(title);
} else {
return title.includes(filter);
}
[calendar] fix: prevent excessive fetching on client reload and refactor `calendarfetcherutils.js` (#3976) The bottom line of this PR is, that it fixes an issue and simplifies the code by dealing with the TODOs in the code. For review, I suggest looking at each commit individually. If there are too many changes for a PR, let me know and I'll split it up :slightly_smiling_face: ## 1. [fix(calendar): prevent excessive fetching with smart refresh strategy](https://github.com/MagicMirrorOrg/MagicMirror/pull/3976/commits/8892cd3d5aa3aca45ccc97e1eaff4685c98b3fcd) - Add lastFetch timestamp tracking to CalendarFetcher - Add shouldRefetch() method with configurable minimum interval (default: 3 minutes) - When reusing existing fetcher: fetch if data is stale (>3 min), otherwise broadcast cached events - Prevents double broadcasts to consuming modules while maintaining fresh data - Balances rate limit prevention (Issue https://github.com/MagicMirrorOrg/MagicMirror/issues/3971) with data freshness on user reload - Prevents excessive fetching during rapid reloads (e.g., Fully Kiosk screensaver use case) - Allows fresh calendar data when enough time has passed since last fetch ## 2. [refactor(calendar): simplify event exclusion logic](https://github.com/MagicMirrorOrg/MagicMirror/commit/d507aba82d68bb0feb0c3b45a321f9407f95d311) - Extract filtering logic from `shouldEventBeExcluded` into new helper `checkEventAgainstFilter` - Simplify the main loop in `shouldEventBeExcluded It resolves a TODO from the comments in the code: * `This seems like an overly complicated way to exclude events based on the title.` ## 3. [refactor(calendar): extract recurring event expansion logic](https://github.com/MagicMirrorOrg/MagicMirror/commit/d510160bd214d1440cb8c2f7598cf48ec0c19c36) This change separates the expansion of recurring events from the main filtering loop into a new helper function 'expandRecurringEvent'. It resolves two TODOs from the comments in the code: - `This should be a separate function` - `This should create an event per moment so we can change anything we want` This improves code readability, reduces complexity in 'filterEvents', and allows for cleaner handling of individual recurrence instances. ## 4. [refactor(calendar): simplify recurring event handling](https://github.com/MagicMirrorOrg/MagicMirror/commit/b04f716cc0f74883bbcf8d812d76ee56ebca8fe5) - Simplify 'getMomentsFromRecurringEvent' using modern syntax - Improve handling of full-day events across different timezones ## 5. [test(calendar): fix UNTIL date in fullday_until.ics fixture](https://github.com/MagicMirrorOrg/MagicMirror/pull/3976/commits/1d762b2ade2b24e157e66b83774cdef4ccc95c52) The issue was with the UNTIL date being May 4th while DTSTART was May 5th. This created an invalid recurrence rule where the end date came before the start date. The fix only adjusts the UNTIL date from May 4th to May 5th, so it matches the start date.
2025-12-08 10:07:04 +01:00
},
/**
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
* Expands a recurring event into individual event instances using node-ical.
* Handles RRULE expansion, EXDATE filtering, RECURRENCE-ID overrides, and ongoing events.
[calendar] fix: prevent excessive fetching on client reload and refactor `calendarfetcherutils.js` (#3976) The bottom line of this PR is, that it fixes an issue and simplifies the code by dealing with the TODOs in the code. For review, I suggest looking at each commit individually. If there are too many changes for a PR, let me know and I'll split it up :slightly_smiling_face: ## 1. [fix(calendar): prevent excessive fetching with smart refresh strategy](https://github.com/MagicMirrorOrg/MagicMirror/pull/3976/commits/8892cd3d5aa3aca45ccc97e1eaff4685c98b3fcd) - Add lastFetch timestamp tracking to CalendarFetcher - Add shouldRefetch() method with configurable minimum interval (default: 3 minutes) - When reusing existing fetcher: fetch if data is stale (>3 min), otherwise broadcast cached events - Prevents double broadcasts to consuming modules while maintaining fresh data - Balances rate limit prevention (Issue https://github.com/MagicMirrorOrg/MagicMirror/issues/3971) with data freshness on user reload - Prevents excessive fetching during rapid reloads (e.g., Fully Kiosk screensaver use case) - Allows fresh calendar data when enough time has passed since last fetch ## 2. [refactor(calendar): simplify event exclusion logic](https://github.com/MagicMirrorOrg/MagicMirror/commit/d507aba82d68bb0feb0c3b45a321f9407f95d311) - Extract filtering logic from `shouldEventBeExcluded` into new helper `checkEventAgainstFilter` - Simplify the main loop in `shouldEventBeExcluded It resolves a TODO from the comments in the code: * `This seems like an overly complicated way to exclude events based on the title.` ## 3. [refactor(calendar): extract recurring event expansion logic](https://github.com/MagicMirrorOrg/MagicMirror/commit/d510160bd214d1440cb8c2f7598cf48ec0c19c36) This change separates the expansion of recurring events from the main filtering loop into a new helper function 'expandRecurringEvent'. It resolves two TODOs from the comments in the code: - `This should be a separate function` - `This should create an event per moment so we can change anything we want` This improves code readability, reduces complexity in 'filterEvents', and allows for cleaner handling of individual recurrence instances. ## 4. [refactor(calendar): simplify recurring event handling](https://github.com/MagicMirrorOrg/MagicMirror/commit/b04f716cc0f74883bbcf8d812d76ee56ebca8fe5) - Simplify 'getMomentsFromRecurringEvent' using modern syntax - Improve handling of full-day events across different timezones ## 5. [test(calendar): fix UNTIL date in fullday_until.ics fixture](https://github.com/MagicMirrorOrg/MagicMirror/pull/3976/commits/1d762b2ade2b24e157e66b83774cdef4ccc95c52) The issue was with the UNTIL date being May 4th while DTSTART was May 5th. This created an invalid recurrence rule where the end date came before the start date. The fix only adjusts the UNTIL date from May 4th to May 5th, so it matches the start date.
2025-12-08 10:07:04 +01:00
* @param {object} event The recurring event object
* @param {moment.Moment} pastLocalMoment The past date limit
* @param {moment.Moment} futureLocalMoment The future date limit
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
* @returns {object[]} Array of event instances with startMoment/endMoment in the local timezone
[calendar] fix: prevent excessive fetching on client reload and refactor `calendarfetcherutils.js` (#3976) The bottom line of this PR is, that it fixes an issue and simplifies the code by dealing with the TODOs in the code. For review, I suggest looking at each commit individually. If there are too many changes for a PR, let me know and I'll split it up :slightly_smiling_face: ## 1. [fix(calendar): prevent excessive fetching with smart refresh strategy](https://github.com/MagicMirrorOrg/MagicMirror/pull/3976/commits/8892cd3d5aa3aca45ccc97e1eaff4685c98b3fcd) - Add lastFetch timestamp tracking to CalendarFetcher - Add shouldRefetch() method with configurable minimum interval (default: 3 minutes) - When reusing existing fetcher: fetch if data is stale (>3 min), otherwise broadcast cached events - Prevents double broadcasts to consuming modules while maintaining fresh data - Balances rate limit prevention (Issue https://github.com/MagicMirrorOrg/MagicMirror/issues/3971) with data freshness on user reload - Prevents excessive fetching during rapid reloads (e.g., Fully Kiosk screensaver use case) - Allows fresh calendar data when enough time has passed since last fetch ## 2. [refactor(calendar): simplify event exclusion logic](https://github.com/MagicMirrorOrg/MagicMirror/commit/d507aba82d68bb0feb0c3b45a321f9407f95d311) - Extract filtering logic from `shouldEventBeExcluded` into new helper `checkEventAgainstFilter` - Simplify the main loop in `shouldEventBeExcluded It resolves a TODO from the comments in the code: * `This seems like an overly complicated way to exclude events based on the title.` ## 3. [refactor(calendar): extract recurring event expansion logic](https://github.com/MagicMirrorOrg/MagicMirror/commit/d510160bd214d1440cb8c2f7598cf48ec0c19c36) This change separates the expansion of recurring events from the main filtering loop into a new helper function 'expandRecurringEvent'. It resolves two TODOs from the comments in the code: - `This should be a separate function` - `This should create an event per moment so we can change anything we want` This improves code readability, reduces complexity in 'filterEvents', and allows for cleaner handling of individual recurrence instances. ## 4. [refactor(calendar): simplify recurring event handling](https://github.com/MagicMirrorOrg/MagicMirror/commit/b04f716cc0f74883bbcf8d812d76ee56ebca8fe5) - Simplify 'getMomentsFromRecurringEvent' using modern syntax - Improve handling of full-day events across different timezones ## 5. [test(calendar): fix UNTIL date in fullday_until.ics fixture](https://github.com/MagicMirrorOrg/MagicMirror/pull/3976/commits/1d762b2ade2b24e157e66b83774cdef4ccc95c52) The issue was with the UNTIL date being May 4th while DTSTART was May 5th. This created an invalid recurrence rule where the end date came before the start date. The fix only adjusts the UNTIL date from May 4th to May 5th, so it matches the start date.
2025-12-08 10:07:04 +01:00
*/
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
expandRecurringEvent (event, pastLocalMoment, futureLocalMoment) {
const localTimezone = CalendarFetcherUtils.getLocalTimezone();
return ical
.expandRecurringEvent(event, {
from: pastLocalMoment.toDate(),
to: futureLocalMoment.toDate(),
includeOverrides: true,
excludeExdates: true,
expandOngoing: true
})
.map((inst) => {
let startMoment, endMoment;
if (inst.isFullDay) {
startMoment = moment.tz([inst.start.getFullYear(), inst.start.getMonth(), inst.start.getDate()], localTimezone);
endMoment = moment.tz([inst.end.getFullYear(), inst.end.getMonth(), inst.end.getDate()], localTimezone);
} else {
startMoment = moment(inst.start).tz(localTimezone);
endMoment = moment(inst.end).tz(localTimezone);
[calendar] fix: prevent excessive fetching on client reload and refactor `calendarfetcherutils.js` (#3976) The bottom line of this PR is, that it fixes an issue and simplifies the code by dealing with the TODOs in the code. For review, I suggest looking at each commit individually. If there are too many changes for a PR, let me know and I'll split it up :slightly_smiling_face: ## 1. [fix(calendar): prevent excessive fetching with smart refresh strategy](https://github.com/MagicMirrorOrg/MagicMirror/pull/3976/commits/8892cd3d5aa3aca45ccc97e1eaff4685c98b3fcd) - Add lastFetch timestamp tracking to CalendarFetcher - Add shouldRefetch() method with configurable minimum interval (default: 3 minutes) - When reusing existing fetcher: fetch if data is stale (>3 min), otherwise broadcast cached events - Prevents double broadcasts to consuming modules while maintaining fresh data - Balances rate limit prevention (Issue https://github.com/MagicMirrorOrg/MagicMirror/issues/3971) with data freshness on user reload - Prevents excessive fetching during rapid reloads (e.g., Fully Kiosk screensaver use case) - Allows fresh calendar data when enough time has passed since last fetch ## 2. [refactor(calendar): simplify event exclusion logic](https://github.com/MagicMirrorOrg/MagicMirror/commit/d507aba82d68bb0feb0c3b45a321f9407f95d311) - Extract filtering logic from `shouldEventBeExcluded` into new helper `checkEventAgainstFilter` - Simplify the main loop in `shouldEventBeExcluded It resolves a TODO from the comments in the code: * `This seems like an overly complicated way to exclude events based on the title.` ## 3. [refactor(calendar): extract recurring event expansion logic](https://github.com/MagicMirrorOrg/MagicMirror/commit/d510160bd214d1440cb8c2f7598cf48ec0c19c36) This change separates the expansion of recurring events from the main filtering loop into a new helper function 'expandRecurringEvent'. It resolves two TODOs from the comments in the code: - `This should be a separate function` - `This should create an event per moment so we can change anything we want` This improves code readability, reduces complexity in 'filterEvents', and allows for cleaner handling of individual recurrence instances. ## 4. [refactor(calendar): simplify recurring event handling](https://github.com/MagicMirrorOrg/MagicMirror/commit/b04f716cc0f74883bbcf8d812d76ee56ebca8fe5) - Simplify 'getMomentsFromRecurringEvent' using modern syntax - Improve handling of full-day events across different timezones ## 5. [test(calendar): fix UNTIL date in fullday_until.ics fixture](https://github.com/MagicMirrorOrg/MagicMirror/pull/3976/commits/1d762b2ade2b24e157e66b83774cdef4ccc95c52) The issue was with the UNTIL date being May 4th while DTSTART was May 5th. This created an invalid recurrence rule where the end date came before the start date. The fix only adjusts the UNTIL date from May 4th to May 5th, so it matches the start date.
2025-12-08 10:07:04 +01:00
}
[calendar] refactor: delegate event expansion to node-ical's expandRecurringEvent (#4047) node-ical 0.25.x added `expandRecurringEvent()` — a proper API for expanding both recurring and non-recurring events, including EXDATE filtering and RECURRENCE-ID overrides. This PR replaces our hand-rolled equivalent with it. `calendarfetcherutils.js` loses ~125 lines of code. What's left only deals with MagicMirror-specific concerns: timezone conversion, config-based filtering, and output formatting. The extra lines in the diff come from new tests. ## What was removed - `getMomentsFromRecurringEvent()` — manual rrule.js wrapping with custom date extraction - `isFullDayEvent()` — heuristic with multiple fallback checks - `isFacebookBirthday` workaround — patched years < 1900 and special-cased `@facebook.com` UIDs - The `if (event.rrule) / else` split — all events now go through a single code path ## Bugs fixed along the way Both were subtle enough to go unnoticed before: - **`[object Object]` in event titles/description/location** — node-ical represents ICS properties with parameters (e.g. `DESCRIPTION;LANGUAGE=de:Text`) as `{val, params}` objects. The old code passed them straight through. Mainly affected multilingual Exchange/O365 setups. Fixed with `unwrapParameterValue()`. - **`excludedEvents` with `until` never worked** — `shouldEventBeExcluded()` returned `{ excluded, until }` but the caller destructured it as `{ excluded, eventFilterUntil }`, so the until date was always `undefined` and events were never hidden. Fixed by correcting the destructuring key. The expansion loop also gets error isolation: a single broken event is logged and skipped instead of aborting the whole feed. ## Other clean-ups - Replaced `this.shouldEventBeExcluded` with `CalendarFetcherUtils.shouldEventBeExcluded` — avoids context-loss bugs when the method is destructured or called indirectly. - Replaced deprecated `substr()` with `slice()`. - Replaced `now < filterUntil` (operator overloading) with `now.isBefore(filterUntil)` — idiomatic Moment.js comparison. - Fixed `@returns` JSDoc: `string[]` → `object[]`. - Moved verbose `Log.debug("Processing entry...")` after the `VEVENT` type guard to reduce log noise from non-event entries. - Replaced `JSON.stringify(event)` debug log with a lightweight summary to avoid unnecessary serialization cost. - Added comment explaining the 0-duration → end-of-day fallback for events without DTEND. ## Tests 24 unit tests, all passing (`npx vitest run tests/unit/modules/default/calendar/`). New coverage: `excludedEvents` with/without `until`, Facebook birthday year expansion, output object shape, no-DTEND fallback, error isolation, `unwrapParameterValue`, `getTitleFromEvent`, ParameterValue properties, RECURRENCE-ID overrides, DURATION (single and recurring).
2026-03-02 21:31:32 +01:00
// Events without DTEND (e.g. reminders) get start === end from node-ical;
// extend to end-of-day so they remain visible on the calendar.
if (startMoment.valueOf() === endMoment.valueOf()) endMoment = endMoment.endOf("day");
return { event: inst.event, startMoment, endMoment, isRecurring: inst.isRecurring, isFullDay: inst.isFullDay };
});
[calendar] fix: prevent excessive fetching on client reload and refactor `calendarfetcherutils.js` (#3976) The bottom line of this PR is, that it fixes an issue and simplifies the code by dealing with the TODOs in the code. For review, I suggest looking at each commit individually. If there are too many changes for a PR, let me know and I'll split it up :slightly_smiling_face: ## 1. [fix(calendar): prevent excessive fetching with smart refresh strategy](https://github.com/MagicMirrorOrg/MagicMirror/pull/3976/commits/8892cd3d5aa3aca45ccc97e1eaff4685c98b3fcd) - Add lastFetch timestamp tracking to CalendarFetcher - Add shouldRefetch() method with configurable minimum interval (default: 3 minutes) - When reusing existing fetcher: fetch if data is stale (>3 min), otherwise broadcast cached events - Prevents double broadcasts to consuming modules while maintaining fresh data - Balances rate limit prevention (Issue https://github.com/MagicMirrorOrg/MagicMirror/issues/3971) with data freshness on user reload - Prevents excessive fetching during rapid reloads (e.g., Fully Kiosk screensaver use case) - Allows fresh calendar data when enough time has passed since last fetch ## 2. [refactor(calendar): simplify event exclusion logic](https://github.com/MagicMirrorOrg/MagicMirror/commit/d507aba82d68bb0feb0c3b45a321f9407f95d311) - Extract filtering logic from `shouldEventBeExcluded` into new helper `checkEventAgainstFilter` - Simplify the main loop in `shouldEventBeExcluded It resolves a TODO from the comments in the code: * `This seems like an overly complicated way to exclude events based on the title.` ## 3. [refactor(calendar): extract recurring event expansion logic](https://github.com/MagicMirrorOrg/MagicMirror/commit/d510160bd214d1440cb8c2f7598cf48ec0c19c36) This change separates the expansion of recurring events from the main filtering loop into a new helper function 'expandRecurringEvent'. It resolves two TODOs from the comments in the code: - `This should be a separate function` - `This should create an event per moment so we can change anything we want` This improves code readability, reduces complexity in 'filterEvents', and allows for cleaner handling of individual recurrence instances. ## 4. [refactor(calendar): simplify recurring event handling](https://github.com/MagicMirrorOrg/MagicMirror/commit/b04f716cc0f74883bbcf8d812d76ee56ebca8fe5) - Simplify 'getMomentsFromRecurringEvent' using modern syntax - Improve handling of full-day events across different timezones ## 5. [test(calendar): fix UNTIL date in fullday_until.ics fixture](https://github.com/MagicMirrorOrg/MagicMirror/pull/3976/commits/1d762b2ade2b24e157e66b83774cdef4ccc95c52) The issue was with the UNTIL date being May 4th while DTSTART was May 5th. This created an invalid recurrence rule where the end date came before the start date. The fix only adjusts the UNTIL date from May 4th to May 5th, so it matches the start date.
2025-12-08 10:07:04 +01:00
},
/**
* Checks if an event title matches a specific filter configuration.
* @param {string} title The event title to check
* @param {string|object} filterConfig The filter configuration (string or object)
* @returns {object|null} Object with {until: string|null} if matched, null otherwise
*/
checkEventAgainstFilter (title, filterConfig) {
let filter = filterConfig;
let testTitle = title.toLowerCase();
let until = null;
let useRegex = false;
let regexFlags = "g";
if (filter instanceof Object) {
if (typeof filter.until !== "undefined") {
until = filter.until;
}
if (typeof filter.regex !== "undefined") {
useRegex = filter.regex;
}
if (filter.caseSensitive) {
filter = filter.filterBy;
testTitle = title;
} else if (useRegex) {
filter = filter.filterBy;
testTitle = title;
regexFlags += "i";
} else {
filter = filter.filterBy.toLowerCase();
}
} else {
filter = filter.toLowerCase();
}
if (CalendarFetcherUtils.titleFilterApplies(testTitle, filter, useRegex, regexFlags)) {
return { until };
}
return null;
Release 2.24.0 (#3141) Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Karsten Hassel <hassel@gmx.de> Co-authored-by: Malte Hallström <46646495+SkySails@users.noreply.github.com> Co-authored-by: Veeck <github@veeck.de> Co-authored-by: veeck <michael@veeck.de> Co-authored-by: dWoolridge <dwoolridge@charter.net> Co-authored-by: Johan <jojjepersson@yahoo.se> Co-authored-by: Dario Mratovich <dario_mratovich@hotmail.com> Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com> Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com> Co-authored-by: Naveen <172697+naveensrinivasan@users.noreply.github.com> Co-authored-by: buxxi <buxxi@omfilm.net> Co-authored-by: Thomas Hirschberger <47733292+Tom-Hirschberger@users.noreply.github.com> Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com> Co-authored-by: Andrés Vanegas Jiménez <142350+angeldeejay@users.noreply.github.com> Co-authored-by: Dave Child <dave@addedbytes.com> Co-authored-by: grenagit <46225780+grenagit@users.noreply.github.com> Co-authored-by: Grena <grena@grenabox.fr> Co-authored-by: Magnus Marthinsen <magmar@online.no> Co-authored-by: Patrick <psieg@users.noreply.github.com> Co-authored-by: Piotr Rajnisz <56397164+rajniszp@users.noreply.github.com> Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com> Co-authored-by: CarJem Generations (Carter Wallace) <cwallacecs@gmail.com> Co-authored-by: Nicholas Fogal <nfogal.misc@gmail.com> Co-authored-by: JakeBinney <126349119+JakeBinney@users.noreply.github.com> Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com> Co-authored-by: Oscar Björkman <17575446+oscarb@users.noreply.github.com> Co-authored-by: Ismar Slomic <ismar@slomic.no> Co-authored-by: Jørgen Veum-Wahlberg <jorgen.wahlberg@amedia.no> Co-authored-by: Eddie Hung <6740044+eddiehung@users.noreply.github.com> Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr> Co-authored-by: bugsounet <bugsounet@bugsounet.fr> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-01 21:17:31 +02:00
}
};
if (typeof module !== "undefined") {
module.exports = CalendarFetcherUtils;
}