Compare commits

..

482 Commits

Author SHA1 Message Date
Veeck
1b31cf19e9 Thoroughly check for precipitationAmount values in weathergov provider (#3859)
Fixes #3856

---------

Co-authored-by: veeck <gitkraken@veeck.de>
2025-08-16 20:56:52 +02:00
Veeck
0ca7d23b69 update github actions (#3858)
actions/checkout got updated last night

---------

Co-authored-by: veeck <gitkraken@veeck.de>
2025-08-12 21:14:41 +02:00
Veeck
839d074df1 Update dependencies (#3857)
Just some normal maintainance after the holidays

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: veeck <gitkraken@veeck.de>
2025-08-11 12:49:03 +02:00
Karsten Hassel
e34ef0cb6e update dependencies (#3849) 2025-07-22 22:09:29 +02:00
Karsten Hassel
3fa2b96054 cleanup and try to stabilize weather e2e tests (#3848)
The weather e2e tests are failing sometimes, failing is not really
reproducable.

After changing `updateDom(0)` to `updateDom(300)` in `weather.js` it
seems to work (we will se if it really works in the long term).

This PR contains some other weather e2e changes/cleanups/simplifying.
2025-07-20 08:23:52 +02:00
Karsten Hassel
e7b669af34 e2e: decrease stop app waitTime (#3847) 2025-07-16 23:54:02 +02:00
Karsten Hassel
54752f10e8 replace console with Log in calendar debug.js (#3846)
to avoid exception in eslint config.

Background: If someone has a copy of the `modules` folder in his setup
eslint fails because the file `debug.js` uses `console` statements. I
need the `modules` folder renamed in my docker setup so this test always
fails. I think this is a simple solution which has no impact.
2025-07-16 00:38:03 +02:00
Kristjan ESPERANTO
02e76da196 refactor: extract constants for weather electron tests (#3845)
I find the tests with clear variable names much easier to understand.
2025-07-15 00:27:35 +02:00
Kristjan ESPERANTO
7f8935a34c refactor: simplify jest config (#3844)
- changed export from async to sync function - this removes unnecessary
complexity
- reformatted `collectCoverageFrom` to use `<rootDir>` for each pattern
and switch to multi-line style - this is just harmonization
2025-07-13 21:32:58 +02:00
Kristjan ESPERANTO
931fe55022 refactor: optimize system information logging (#3843)
Additionally to #3839 did some rework on the system logging.

- feat: include MagicMirror version (like Sam suggested in #3839)
- refactor: use more variables to get the string array less complex
- refactor: get `installedNodeVersion` from si.versions (with that it
was possible to drop the import of `execSync`)
- fix: `used node` was always the same as the installed one. Since
Electron comes with its own node version, this can differ. This is now
shown correctly (again?) with the use of `process.version`.
- a bit formatting

I think these changes make the code easier to understand and therefore
easier to maintain. Except for showing the MM version there is no big
difference for the user.

## before

```bash
#####  System Information  #####
- SYSTEM:    manufacturer: Notebook; model: N650DU; virtual: false; timeZone: Europe/Berlin
- OS:        platform: linux; distro: Debian GNU/Linux; release: 12; arch: x64; kernel: 5.10.0-20-amd64
- VERSIONS:  electron: 36.3.2; used node: 22.15.0; installed node: 22.15.0; npm: 10.9.0; pm2: 6.0.6
- ENV:       XDG_SESSION_TYPE: wayland; MM_CONFIG_FILE: config/config_MMM-PublicTransportHafas.js;
             WAYLAND_DISPLAY:  wayland-0; DISPLAY: :0; ELECTRON_ENABLE_GPU: undefined
- RAM:       total: 15925.45 MB; free: 2716.90 MB; used: 13209.04 MB
- UPTIME:    259 minutes 
```

## after

```bash
####  System Information  ####
- SYSTEM:   manufacturer: Notebook; model: N650DU; virtual: false; MM: 2.33.0-develop
- OS:       platform: linux; distro: Debian GNU/Linux; release: 12; arch: x64; kernel: 5.10.0-20-amd64
- VERSIONS: electron: 36.3.2; used node: 22.15.1; installed node: 22.15.0; npm: 10.9.0; pm2: 6.0.6
- ENV:      XDG_SESSION_TYPE: wayland; MM_CONFIG_FILE: config/config_MMM-PublicTransportHafas.js
            WAYLAND_DISPLAY:  wayland-0; DISPLAY: :0; ELECTRON_ENABLE_GPU: undefined
- RAM:      total: 15925.45 MB; free: 2814.49 MB; used: 13110.96 MB
- OTHERS:   uptime: 260 minutes; timeZone: Europe/Berlin 
```
2025-07-12 08:24:09 +02:00
Karsten Hassel
a05eb23306 refactor default modules: move scheduleTimer to one place (#3837)
see #3819

---------

Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
Co-authored-by: Veeck <github@veeck.de>
2025-07-10 08:12:09 +02:00
Kristjan ESPERANTO
e115475a9d feat: enhance system information logging format and include additional env and RAM details (#3839)
When we introduced the system information, I selected `###` as the
prefix for each line. While this doesn't cause any problems in the
terminal, when someone copies the output to an issue or the forum, every
line is formatted as a heading, which is not ideal. That's why I made
some rework and suggest these changes.

In addition to the formatting changes, I added some env and RAM details
plus the uptime. These are just suggestions – if you don't think they're
worth adding, I'm happy to remove them. We wanted to keep this block
compact.

@sdetweil, since you are often on the front line with the error messages
from users: Is there any information missing in the system block that
you often have to request additionally?

Feel free to request changes!

-----

## in the terminal

### before

```
[2025-07-09 21:58:36.943] [INFO]  System information:
### SYSTEM:   manufacturer: Notebook; model: N650DU; virtual: false
### OS:       platform: linux; distro: Debian GNU/Linux; release: 12; arch: x64; kernel: 5.10.0-20-amd64
### VERSIONS: electron: 36.3.2; used node: 24.2.0; installed node: 24.2.0; npm: 10.9.0; pm2: 6.0.6
### OTHER:    timeZone: Europe/Berlin; ELECTRON_ENABLE_GPU: undefined 
```

-----

### after

```
[2025-07-09 21:57:47.604] [INFO]  
#####  System Information  #####
- SYSTEM:    manufacturer: Notebook; model: N650DU; virtual: false; timeZone: Europe/Berlin
- OS:        platform: linux; distro: Debian GNU/Linux; release: 12; arch: x64; kernel: 5.10.0-20-amd64
- VERSIONS:  electron: 36.3.2; used node: 24.2.0; installed node: 24.2.0; npm: 10.9.0; pm2: 6.0.6
- ENV:       XDG_SESSION_TYPE: wayland; MM_CONFIG_FILE: undefined;
             WAYLAND_DISPLAY:  wayland-0; DISPLAY: :0; ELECTRON_ENABLE_GPU: undefined
- RAM:       total: 15925.45 MB; free: 967.75 MB; used: 14957.70 MB
- UPTIME:    172 minutes 
```

-----

## as markdown (in an issue or the forum)

### before

[2025-07-09 21:58:36.943] [INFO]  System information:
### SYSTEM:   manufacturer: Notebook; model: N650DU; virtual: false
### OS: platform: linux; distro: Debian GNU/Linux; release: 12; arch:
x64; kernel: 5.10.0-20-amd64
### VERSIONS: electron: 36.3.2; used node: 24.2.0; installed node:
24.2.0; npm: 10.9.0; pm2: 6.0.6
### OTHER:    timeZone: Europe/Berlin; ELECTRON_ENABLE_GPU: undefined 

-----

### after

[2025-07-09 21:57:47.604] [INFO]  
#####  System Information  #####
- SYSTEM: manufacturer: Notebook; model: N650DU; virtual: false;
timeZone: Europe/Berlin
- OS: platform: linux; distro: Debian GNU/Linux; release: 12; arch: x64;
kernel: 5.10.0-20-amd64
- VERSIONS: electron: 36.3.2; used node: 24.2.0; installed node: 24.2.0;
npm: 10.9.0; pm2: 6.0.6
- ENV:       XDG_SESSION_TYPE: wayland; MM_CONFIG_FILE: undefined;
WAYLAND_DISPLAY: wayland-0; DISPLAY: :0; ELECTRON_ENABLE_GPU: undefined
- RAM:       total: 15925.45 MB; free: 967.75 MB; used: 14957.70 MB
- UPTIME:    172 minutes
2025-07-10 07:39:23 +02:00
Veeck
e4ec8c3589 Fix missing icons in clock module (#3834)
Fixes #3818

---------

Co-authored-by: veeck <gitkraken@veeck.de>
2025-07-05 22:47:38 +02:00
Koen Konst
d9e2e0272f Fix calendar unit test so it uses 1 day more than a full year for yearly recurring events test (#3833) 2025-07-02 22:03:41 +02:00
dathbe
3a2a52c864 Add CSS to clock module to prevent line breaking of sunrise/sunset information (#3816)
1. Base your pull requests against the `develop` branch.
Done
2. Include these infos in the description:
- Does the pull request solve a **related** issue?
No
- If so, can you reference the issue like this `Fixes #<issue_number>`?
N/A
- What does the pull request accomplish? Use a list if needed.
With some combinations of sunrise and sunset times (usually when the
time till rise/set is >9:59), the information will break across multiple
lines. This prevents that by adding CSS.
- If it includes major visual changes please add screenshots.
I don't consider it major.
3. Please run `npm run lint:prettier` before submitting so that style
issues are fixed.
Done
4. Don't forget to add an entry about your changes to the CHANGELOG.md
file.
Done

---------

Co-authored-by: veeck <gitkraken@veeck.de>
2025-07-02 19:20:03 +02:00
Karsten Hassel
855b1d7cbf update dependencies incl. electron to v37, remove one failing unit test (#3831)
- see title and #3820
- remove failing unit calendar test until solved, see
https://github.com/MagicMirrorOrg/MagicMirror/issues/3830
2025-07-01 22:38:40 +02:00
Karsten Hassel
106b505f2c Prepare 2.33.0-develop 2025-07-01 00:22:16 +02:00
Karsten Hassel
b506bbb10b Merge remote-tracking branch 'origin/master' into develop 2025-07-01 00:15:11 +02:00
Karsten Hassel
62b0f7f26e Release 2.32.0 (#3826)
## [2.32.0] - 2025-07-01

Thanks to: @bughaver, @bugsounet, @khassel, @KristjanESPERANTO,
@plebcity, @rejas, @sdetweil.

> ⚠️ This release needs nodejs version `v22.14.0 or higher`

### Added

- [config] Allow to change module order for final renderer (or
dynamically with CSS): Feature `order` in config (#3762)
- [clock] Added option 'disableNextEvent' to hide next sun event (#3769)
- [clock] Implement short syntax for clock week (#3775)

### Changed

- [refactor] Simplify module loading process (#3766)
- Use `node --run` instead of `npm run` (#3764) and adapt `start:dev`
script (#3773)
- [workflow] Run linter and spellcheck with LTS node version (#3767)
- [workflow] Split "Run test" step into two steps for more clarity
(#3767)
- [linter] Review linter setup (#3783)
  - Fix command to lint markdown in `CONTRIBUTING.md`
  - Re-activate JSDoc linting and fix linting issues
  - Refactor ESLint config to use `defineConfig` and `globalIgnores`
  - Replace `eslint-plugin-import` with `eslint-plugin-import-x`
- Switch Stylelint config to flat format and simplify Stylelint scripts
- [workflow] Replace Node.js version v23 with v24 (#3770)
- [refactor] Replace deprecated constants `fs.F_OK` and `fs.R_OK`
(#3789)
- [refactor] Replace `ansis` with built-in function `util.styleText`
(#3793)
- [core] Integrate stuff from `vendor` and `fonts` folders into main
`package.json`, simplifies install and maintaining dependencies (#3795,
#3805)
- [l10n] Complete translations (with the help of translation tools)
(#3794)
- [refactor] Refactored `calendarfetcherutils` in Calendar module to
handle timezones better (#3806)
  - Removed as many of the date conversions as possible
- Use `moment-timezone` when calculating recurring events, this will fix
problems from the past with offsets and DST not being handled properly
- Added some tests to test the behavior of the refactored methods to
make sure the correct event dates are returned
- [linter] Enable ESLint rule `no-console` and replace `console` with
`Log` in some files (#3810)
- [tests] Review and refactor translation tests (#3792)

### Fixed

- [fix] Handle spellcheck issues (#3783)
- [calendar] fix fullday event rrule until with timezone offset (#3781)
- [feat] Add rule `no-undef` in config file validation to fix #3785
(#3786)
- [fonts] Fix `roboto.css` to avoid error message `Unknown descriptor
'var(' in @font-face rule.` in firefox console (#3787)
- [tests] Fix and refactor e2e test `Same keys` in
`translations_spec.js` (#3809)
- [tests] Fix e2e tests newsfeed and calendar to exit without open
handles (#3817)

### Updated

- [core] Update dependencies including electron to v36 (#3774, #3788,
#3811, #3804, #3815, #3823)
- [core] Update package type to `commonjs`
- [logger] Review factory code part: use `switch/case` instead of
`if/else if` (#3812)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Michael Teeuw <michael@xonaymedia.nl>
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ross Younger <crazyscot@gmail.com>
Co-authored-by: Veeck <github@veeck.de>
Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr>
Co-authored-by: jkriegshauser <joshuakr@nvidia.com>
Co-authored-by: illimarkangur <116028111+illimarkangur@users.noreply.github.com>
Co-authored-by: sam detweiler <sdetweil@gmail.com>
Co-authored-by: vppencilsharpener <tim.pray@gmail.com>
Co-authored-by: veeck <michael.veeck@nebenan.de>
Co-authored-by: Paranoid93 <6515818+Paranoid93@users.noreply.github.com>
Co-authored-by: Brian O'Connor <btoconnor@users.noreply.github.com>
Co-authored-by: WallysWellies <59727507+WallysWellies@users.noreply.github.com>
Co-authored-by: Jason Stieber <jrstieber@gmail.com>
Co-authored-by: jargordon <50050429+jargordon@users.noreply.github.com>
Co-authored-by: Daniel <32464403+dkallen78@users.noreply.github.com>
Co-authored-by: Ryan Williams <65094007+ryan-d-williams@users.noreply.github.com>
Co-authored-by: Panagiotis Skias <panagiotis.skias@gmail.com>
Co-authored-by: Marc Landis <dirk.rettschlag@gmail.com>
Co-authored-by: HeikoGr <20295490+HeikoGr@users.noreply.github.com>
Co-authored-by: Pedro Lamas <pedrolamas@gmail.com>
Co-authored-by: veeck <gitkraken@veeck.de>
Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com>
Co-authored-by: Ikko Eltociear Ashimine <eltociear@gmail.com>
Co-authored-by: DevIncomin <56730075+Developer-Incoming@users.noreply.github.com>
Co-authored-by: Nathan <n8nyoung@gmail.com>
Co-authored-by: mixasgr <mixasgr@users.noreply.github.com>
Co-authored-by: Savvas Adamtziloglou <savvas-gr@greeklug.gr>
Co-authored-by: Konstantinos <geraki@gmail.com>
Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com>
Co-authored-by: BugHaver <43462320+bughaver@users.noreply.github.com>
Co-authored-by: BugHaver <43462320+lsaadeh@users.noreply.github.com>
Co-authored-by: Koen Konst <koenspero@gmail.com>
Co-authored-by: Koen Konst <c.h.konst@avisi.nl>
2025-07-01 00:10:47 +02:00
Karsten Hassel
26809725e5 Prepare Release 2.32.0 (#3825) 2025-06-30 23:52:58 +02:00
Karsten Hassel
5e506ea856 last dependency update before release (#3823) 2025-06-29 19:47:21 +02:00
Karsten Hassel
1e11d28224 fixes e2e tests (#3817)
- fix newsfeed and calendar e2e tests so they don't need `--forceExit`
anymore
- `--forceExit` should stay in test runs to avoid running until test
limit in case of errors
- remove mocking console, not needed anymore
- configFactory-stuff should not run in browser (otherwise we get errors
`[ReferenceError: exports is not defined]`)
2025-06-25 08:27:52 +02:00
Karsten Hassel
d2d4d7b37f update jest to v30 (#3815)
e2e:
- needed window.close(), otherwise the objects are not destroyed
- add missing `await` in clock test
- set maxListeners for all tests

remaining todo (comes with another PR if I find the problem):
- calendar e2e is now the only test which still needs `--forceExit`
2025-06-21 13:40:10 +02:00
Kristjan ESPERANTO
2809ed1750 [tests] Review and refactor translation tests (#3792)
I have refactored the translations tests, they should now be clearer and
easier to understand. There should be no functional impact.

I have discarded the original approach of also replacing
`XMLHttpRequest` with `fetch` in the file `js/translator.js`. I had
managed to get it to work functionally, but I couldn't get the tests to
work.
2025-06-21 00:37:15 +02:00
Bugsounet - Cédric
c7c0e67c1d review logger factory code part: use switch/case (#3812)
Styling code of `logger.js`:

Just use `switch/case` instead of `if/else if`

---------

Co-authored-by: Veeck <github@veeck.de>
2025-06-20 17:12:24 +02:00
Bugsounet - Cédric
9a3f4f098b Update package type to commonjs (#3814)
related to #3804 

added type to `commonjs` in package.json
2025-06-20 14:26:33 +02:00
Karsten Hassel
ee874836fe update deps and fix animateCSS_spec test (#3811)
- animateCSS_spec test did throw errors at least with newest
dependencies (running locally or on gitlab)
- dependency updates: New jest v30 breaks our tests so we have to stay
with v29 until fixed (will take a look)
2025-06-19 07:35:42 +02:00
Kristjan ESPERANTO
6501aabd2d [linter] Enable ESLint rule no-console (#3810)
In PR #3806 I noticed that ESLint did not complain about the use of
`console`. Then I realised that the rule `no-console` was not activated.
I have now changed this and replaced a few places where `console` was
used.

We can't apply the rule to all .js files because not all of them use our
logger. Therefore I had to add an extra config block for it.
2025-06-09 16:43:45 +02:00
Kristjan ESPERANTO
2194ffd929 [tests] Fix and refactor e2e test "Same keys" in "translations_spec.js" (#3809)
While working on the translations (in #3792 and #3794) I realised that
the e2e "Same keys" tests were not working entirely. There was also a
TODO entry for this in the test, as well as a try-catch-block
workaround. I therefore fixed and refactored it.

I also sorted the translations in `translations/translations.js`, so
that the test outputs are alphabetically.
2025-06-09 12:56:22 +02:00
Koen Konst
faf15ad211 Refactored calendarfetcherutils to fix many of the timezone and DST related issues and make debugging way easier (#3806)
Refactored calendarfetcherutils to remove as many of the date
conversions as possible and use moment tz when calculating recurring
events, this will make debugging a lot easier and fixes problems from
the past with offsets and DST not being handled properly. Also added
some tests to test the behavior of the refactored methodes to make sure
the correct event dates are returned.

Refactored calendar.js aswell to make sure the unix UTC start and end
date of events are properly converted to a local timezone and displayed
correctly for the user.

This PR relates to:
https://github.com/MagicMirrorOrg/MagicMirror/issues/3797

---------

Co-authored-by: Koen Konst <c.h.konst@avisi.nl>
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
2025-06-07 14:13:01 +02:00
Karsten Hassel
052ec1ca26 remove existing folders fonts and vendor from local installations (#3805)
see discussions
[here](https://github.com/MagicMirrorOrg/MagicMirror/pull/3795#issuecomment-2927804743).

The used command should work under windows too. I'm open to better
solutions.

Co-authored-by: Veeck <github@veeck.de>
2025-06-07 13:20:01 +02:00
Kristjan ESPERANTO
302b24c647 [l10n] Complete translations (#3794)
**Short description**: I completed the translations with the help of
translation tools.

**Long description**: I'm currently looking at the translation-tests and
I noticed the e2e-test `${language} should contain all base keys, ()`.
It is supposed to check whether all keys are present in each translation
file, but it doesn't actually work that way. When I fix it, a lot of
missing translations are reported. I have completed these translations
with the help of translation tools and packed them into this PR. I have
left out the modified test so that we can focus on the question if we
accept such amount of automatic translations or not.

rejas has already expressed in another PR
(https://github.com/MagicMirrorOrg/MagicMirror/pull/3775#discussion_r2083099252)
that he prefers human translators. I basically do too, but I don't see
how we can manage to have all translations completed by humans. And even
if a few translations are not correct, hopefully a user will get in
touch.

If we decide against the translations, we should at least remove the
test. If we go for the tranlsations, I'll add the test.

What do you think?

---------

Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com>
2025-06-05 10:18:12 +02:00
Karsten Hassel
975ee9c97d update dependencies (#3804)
and add now required "type" to `package.json`
2025-06-01 17:51:31 +02:00
Karsten Hassel
c8625ff506 simplify install and maintaining dependencies (#3795)
I was always unhappy when maintaining dependency updates to have 3
`package.json` files.

This PR moves all deps into the main `package.json` and removes the
folders `fonts` and `vendor`.

If accepted I will update the docs too.

---------

Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
2025-06-01 17:03:11 +02:00
Kristjan ESPERANTO
e26aed927d [refactor] Replace ansis with built-in function util.styleText (#3793)
> What does the pull request accomplish?

One external dependency less.
2025-05-27 22:36:02 +02:00
Kristjan ESPERANTO
85b4ece767 [refactor] Replace deprecated constants (#3789)
`fs.F_OK` and `fs.R_OK` are [deprecated since a while node
20.8.0](https://nodejs.org/api/deprecations.html#DEP0176).

Node 24 now complains about them when running server mode (`node --run
server`):

```bash
[2025-05-23 23:11:44.932] [ERROR] (node:37733) [DEP0176] DeprecationWarning: fs.F_OK is deprecated, use fs.constants.F_OK instead
(Use `node --trace-deprecation ...` to show where the warning was created) 
```

The replacements have been in place for a while, and this change should
work without any issues.
2025-05-23 23:57:50 +02:00
Kristjan ESPERANTO
4e3821c2ff [workflow] Replace Node.js version v23 with v24 (#3770)
node v24 was released today and v23 will have reached EOL with our next
release.
2025-05-23 19:34:43 +02:00
Karsten Hassel
d07912d4b2 update dependencies incl. electron to v36 (#3788) 2025-05-23 06:52:28 +02:00
Karsten Hassel
d179051329 fix roboto.css to avoid error message (#3787) 2025-05-20 06:48:10 +02:00
BugHaver
2f9f4b6253 [feature] implement short syntax for clock week (#3775)
Hello and thank you for wanting to contribute to the MagicMirror²
project!

**Please make sure that you have followed these 4 rules before
submitting your Pull Request:**

> 1. Base your pull requests against the `develop` branch.
> 2. Include these infos in the description: implement short syntax for
clock week
>
> - Does the pull request solve a **related** issue? n/a
> - If so, can you reference the issue like this `Fixes
#<issue_number>`?
> - What does the pull request accomplish? Use a list if needed.
> - If it includes major visual changes please add screenshots.
>
> 3. Please run `npm run lint:prettier` before submitting so that
>    style issues are fixed.
> 4. Don't forget to add an entry about your changes to
>    the CHANGELOG.md file.


![image](https://github.com/user-attachments/assets/e6c16981-de0a-45be-b553-7a7a67977d55)


![image](https://github.com/user-attachments/assets/ebae32e7-e6fb-41aa-971a-908880acc7b9)


**Note**: Sometimes the development moves very fast. It is highly
recommended that you update your branch of `develop` before creating a
pull request to send us your changes. This makes everyone's lives
easier (including yours) and helps us out on the development team.

Thanks again and have a nice day!

---------

Co-authored-by: BugHaver <43462320+lsaadeh@users.noreply.github.com>
2025-05-16 08:04:18 +02:00
Veeck
8e0b8468d3 Add Code of Conduct (#3763)
The project is lacking a Code of Conduct

---------

Co-authored-by: veeck <gitkraken@veeck.de>
2025-05-16 08:03:43 +02:00
Kristjan ESPERANTO
554bb0ed5c [feat] Add rule no-undef in config file validation (#3786)
This should solve the problem #3785.
2025-05-15 00:15:54 +02:00
Kristjan ESPERANTO
965e935881 [linter] Review linter setup (#3783)
- [2b395b9f] Fix command to lint markdown in `CONTRIBUTING.md`
- [fed4c86c] Re-activate JSDoc ESLint plugin and fix linting issues (As
far as I remember, we deactivated it when we upgraded to ESLint 9
because it was not compatible with it. But its now.)
- [a3d2064b] Refactor ESLint config to use `defineConfig` and
`globalIgnores` ([these are like new
defaults](https://eslint.org/blog/2025/03/flat-config-extends-define-config-global-ignores/))
- [a3d2064b] Replace `eslint-plugin-import` with
`eslint-plugin-import-x`
(https://github.com/es-tooling/module-replacements/blob/main/docs/modules/eslint-plugin-import.md)
- [86a185b6] Switch Stylelint config to flat format and simplify
Stylelint scripts (like we already did for ESLint and prettier)
  - [f5a2c541] Fix some typos
2025-05-12 23:40:05 +02:00
sam detweiler
2422e847b1 Fix calendar rrule until where event is fullday but rrule until has a non-0 time (#3782)
This fixes #3781 

tests supplied

see
https://forum.magicmirror.builders/topic/19637/issue-with-outlook-recurring-events
2025-05-12 23:39:36 +02:00
dependabot[bot]
ed419ce5b3 Bump pm2 from 5.4.3 to 6.0.5 (#3776)
Bumps [pm2](https://github.com/Unitech/pm2) from 5.4.3 to 6.0.5.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/Unitech/pm2/releases">pm2's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.5</h2>
<h1>6.0.5</h1>
<ul>
<li>Bun support - Fixes <a
href="https://redirect.github.com/Unitech/pm2/issues/5893">#5893</a> <a
href="https://redirect.github.com/Unitech/pm2/issues/5774">#5774</a> <a
href="https://redirect.github.com/Unitech/pm2/issues/5682">#5682</a> <a
href="https://redirect.github.com/Unitech/pm2/issues/5675">#5675</a> <a
href="https://redirect.github.com/Unitech/pm2/issues/5777">#5777</a></li>
<li>Disable git parsing by default <a
href="https://redirect.github.com/Unitech/pm2/issues/5909">#5909</a> <a
href="https://redirect.github.com/Unitech/pm2/issues/2182">#2182</a> <a
href="https://redirect.github.com/Unitech/pm2/issues/5801">#5801</a> <a
href="https://redirect.github.com/Unitech/pm2/issues/5051">#5051</a> <a
href="https://redirect.github.com/Unitech/pm2/issues/5696">#5696</a></li>
<li>Add WEBP content type for pm2 serve <a
href="https://redirect.github.com/Unitech/pm2/issues/5900">#5900</a> <a
href="https://github.com/tbo47"><code>@​tbo47</code></a></li>
<li>Enable PM2 module update from tarball <a
href="https://redirect.github.com/Unitech/pm2/issues/5906">#5906</a> <a
href="https://github.com/AYOKINYA"><code>@​AYOKINYA</code></a></li>
<li>Fix treekil on FreeBSD <a
href="https://redirect.github.com/Unitech/pm2/issues/5896">#5896</a> <a
href="https://github.com/skeyby"><code>@​skeyby</code></a></li>
<li>fix allowing to update namespaced pm2 NPM module
(<code>@​org/module-name</code>) <a
href="https://redirect.github.com/Unitech/pm2/issues/5915">#5915</a> <a
href="https://github.com/endelendel"><code>@​endelendel</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/Unitech/pm2/blob/master/CHANGELOG.md">pm2's
changelog</a>.</em></p>
<blockquote>
<h2>6.0.5</h2>
<ul>
<li>Bun support - Fixes <a
href="https://redirect.github.com/Unitech/pm2/issues/5893">#5893</a> <a
href="https://redirect.github.com/Unitech/pm2/issues/5774">#5774</a> <a
href="https://redirect.github.com/Unitech/pm2/issues/5682">#5682</a> <a
href="https://redirect.github.com/Unitech/pm2/issues/5675">#5675</a> <a
href="https://redirect.github.com/Unitech/pm2/issues/5777">#5777</a></li>
<li>Disable git parsing by default <a
href="https://redirect.github.com/Unitech/pm2/issues/5909">#5909</a> <a
href="https://redirect.github.com/Unitech/pm2/issues/2182">#2182</a> <a
href="https://redirect.github.com/Unitech/pm2/issues/5801">#5801</a> <a
href="https://redirect.github.com/Unitech/pm2/issues/5051">#5051</a> <a
href="https://redirect.github.com/Unitech/pm2/issues/5696">#5696</a></li>
<li>Add WEBP content type for pm2 serve <a
href="https://redirect.github.com/Unitech/pm2/issues/5900">#5900</a> <a
href="https://github.com/tbo47"><code>@​tbo47</code></a></li>
<li>Enable PM2 module update from tarball <a
href="https://redirect.github.com/Unitech/pm2/issues/5906">#5906</a> <a
href="https://github.com/AYOKINYA"><code>@​AYOKINYA</code></a></li>
<li>Fix treekil on FreeBSD <a
href="https://redirect.github.com/Unitech/pm2/issues/5896">#5896</a> <a
href="https://github.com/skeyby"><code>@​skeyby</code></a></li>
<li>fix allowing to update namespaced pm2 NPM module
(<code>@​org/module-name</code>) <a
href="https://redirect.github.com/Unitech/pm2/issues/5915">#5915</a> <a
href="https://github.com/endelendel"><code>@​endelendel</code></a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/Unitech/pm2/commits/v6.0.5">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=pm2&package-manager=npm_and_yarn&previous-version=5.4.3&new-version=6.0.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-09 22:47:20 +02:00
Karsten Hassel
53bff7243d update dependencies (#3774) 2025-05-09 22:35:09 +02:00
Bugsounet - Cédric
2831ae985c [Feature Request] Allow to make an display order of module position in config (#3762)
My proposal for #3761 

* I use `flex` box for create region container
* I have moved `container` definition to `main.css` (for css tunning,
maybe it can be useful)
* I create `order` in module config for define module order display from
position

# Advantage:

We don't have to move module config in another place in array of modules

# Another advantage that i did'nt think:

We can change dynamicaly module order of a container:

- So, in this case, for a module config builder, (I won't mention the
name because otherwise I'll get angry...)
It can be usefull for a config preview (before saving config)
--> just change style css `order` module value for see preview

- Or, change `order` value in dev console for testing

# Disadvantages

I don't see any ;)
2025-05-08 10:15:02 +02:00
Kristjan ESPERANTO
7b4d363b07 [fix] Fix start:dev script (#3773)
This will fix #3772 caused by #3764.

Since I work with `start:wayland:dev` instead of `start:dev`, I didn't
notice this, sorry.
2025-05-07 16:06:09 +02:00
Kristjan ESPERANTO
a5b85c4ab6 [workflow] Use LTS node version and split "Run test" step (#3767)
Two small changes to the workflows:

- Run linter and spellcheck workflows with LTS node version. The
advantage of this is that we no longer have to raise the node version
for them.
- Split "Run test" step into two steps for more clarity.
2025-05-07 07:51:01 +02:00
Kristjan ESPERANTO
b9d63d7252 Use "node --run" instead of "npm run" (#3764)
This has the advantage that the package manager is no longer involved
after the installation process.

However, previous start commands such as `npm run start` continue to
work. So we don't even have to adapt the documentation.
2025-05-06 20:33:42 +02:00
BugHaver
ff6682982f [feature] Introduce disableNextEvent to hide next sun event (#3769)
Hello and thank you for wanting to contribute to the MagicMirror²
project!

**Please make sure that you have followed these 4 rules before
submitting your Pull Request:**

> 1. Base your pull requests against the `develop` branch.
> 2. Include these infos in the description:
>
> - Does the pull request solve a **related** issue? No
> - If so, can you reference the issue like this `Fixes
#<issue_number>`? N/A
> - What does the pull request accomplish? Use a list if needed.
Introduce showNextEvent to show/hide next sun event
> - If it includes major visual changes please add screenshots.
>
![image](https://github.com/user-attachments/assets/410f6a82-e4fe-4c40-a477-8249149febf3)
> 3. Please run `npm run lint:prettier` before submitting so that
>    style issues are fixed.
> 4. Don't forget to add an entry about your changes to
>    the CHANGELOG.md file.

**Note**: Sometimes the development moves very fast. It is highly
recommended that you update your branch of `develop` before creating a
pull request to send us your changes. This makes everyone's lives
easier (including yours) and helps us out on the development team.

Thanks again and have a nice day!

---------

Co-authored-by: BugHaver <43462320+lsaadeh@users.noreply.github.com>
2025-04-27 18:37:17 +02:00
Kristjan ESPERANTO
e1a53ef2d5 [refactor] Simplify module loading process (#3766)
While debugging a 3rd party module, I looked at how modules are loaded
and realized that the `loadModules` method can be implemented much
simpler. This refactor makes the method easier to understand and
maintain.
2025-04-24 00:42:48 +02:00
veeck
86934c8375 Prepare v2.32.0-develop 2025-04-01 21:54:00 +02:00
veeck
7938c3a175 Merge branch 'mm_master' into mm_develop 2025-04-01 20:25:52 +02:00
Veeck
39a614e0de Release 2.31.0 (#3758)
Thanks to: @Developer-Incoming, @eltociear, @geraki, @khassel,
@KristjanESPERANTO, @MagMar94, @mixasgr, @n8many, @OWL4C, @rejas,
@savvadam, @sdetweil.

> ⚠️ This release needs nodejs version `v22.14.0 or higher`

### Added

- Add CSS support to the digital clock hour/minute/second through the
use of the classes `clock-hour-digital`, `clock-minute-digital`, and
`clock-second-digital`.
- Add Arabic (#3719) and Esperanto translation.
- Mark option `secondsColor` as deprecated in clock module.
- Add Greek translation to Alerts module.
- [newsfeed] Add specific ignoreOlderThan value (override) per feed
(#3360)
- [weather] Added option Humidity to hourly View
- [weather] Added option to hide hourly entries that are Zero, hiding
the entire column if empty.
- [updatenotification] Added option to iterate over modules directory
instead using modules defined in `config.js` (#3739)

### Changed

- [core] starting clientonly now checks for needed env var
`WAYLAND_DISPLAY` or `DISPLAY` and starts electron with needed
parameters (if both are set wayland is used) (#3677)
- [core] Optimize systeminformation calls and output (#3689)
- [core] Add issue templates for feature requests and bug reports
(#3695)
- [core] Adapt `start:x11:dev` script
- [weather/yr] The Yr weather provider now enforces a minimum
`updateInterval` of 600 000 ms (10 minutes) to comply with the terms of
service. If a lower value is set, it will be automatically increased to
this minimum.
- [weather/weatherflow] Fixed icons and added hourly support as well as
UV, precipitation, and location name support.
- [workflow] Run `sudo apt-get update` before installing packages to
avoid install errors
- [workflow] Exclude issues with label `ready (coming with next
release)` from stale job

### Removed

### Updated

- [core] Update requirements and dependencies including electron to v35
and formatting (#3593, #3693, #3717)
- [core] Update prettier, ESLint and simplify config
- Update Greek translation

### Fixed

- [calendar] Fix clipping events being broadcast (#3678)
- [tests] Fix Electron tests by running them under new github image
ubuntu-24.04, replace xserver with labwc, running under xserver and
labwc depending on env variable WAYLAND_DISPLAY is set (#3676)
- [calendar] Fix arrayed symbols, #3267, again, add testcase, add
testcase for #3678
- [weather] Fix wrong weatherCondition name in openmeteo provider which
lead to n/a icon (#3691)
- [core] Fix wrong port in log message when starting server only (#3696)
- [calendar] Fix NewYork event processed on system in Central timezone
shows wrong time #3701
- [weather/yr] The Yr weather provider is now able to recover from bad
API responses instead of freezing (#3296)
- [compliments] Fix evening events being shown during the day (#3727)
- [weather] Fixed minor spacing issues when using UV Index in Hourly
- [workflow] Fix command to run spellcheck

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Michael Teeuw <michael@xonaymedia.nl>
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Karsten Hassel <hassel@gmx.de>
Co-authored-by: Ross Younger <crazyscot@gmail.com>
Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr>
Co-authored-by: jkriegshauser <joshuakr@nvidia.com>
Co-authored-by: illimarkangur <116028111+illimarkangur@users.noreply.github.com>
Co-authored-by: sam detweiler <sdetweil@gmail.com>
Co-authored-by: vppencilsharpener <tim.pray@gmail.com>
Co-authored-by: Paranoid93 <6515818+Paranoid93@users.noreply.github.com>
Co-authored-by: Brian O'Connor <btoconnor@users.noreply.github.com>
Co-authored-by: WallysWellies <59727507+WallysWellies@users.noreply.github.com>
Co-authored-by: Jason Stieber <jrstieber@gmail.com>
Co-authored-by: jargordon <50050429+jargordon@users.noreply.github.com>
Co-authored-by: Daniel <32464403+dkallen78@users.noreply.github.com>
Co-authored-by: Ryan Williams <65094007+ryan-d-williams@users.noreply.github.com>
Co-authored-by: Panagiotis Skias <panagiotis.skias@gmail.com>
Co-authored-by: Marc Landis <dirk.rettschlag@gmail.com>
Co-authored-by: HeikoGr <20295490+HeikoGr@users.noreply.github.com>
Co-authored-by: Pedro Lamas <pedrolamas@gmail.com>
Co-authored-by: veeck <gitkraken@veeck.de>
Co-authored-by: Magnus <34011212+MagMar94@users.noreply.github.com>
Co-authored-by: Ikko Eltociear Ashimine <eltociear@gmail.com>
Co-authored-by: DevIncomin <56730075+Developer-Incoming@users.noreply.github.com>
Co-authored-by: Nathan <n8nyoung@gmail.com>
Co-authored-by: mixasgr <mixasgr@users.noreply.github.com>
Co-authored-by: Savvas Adamtziloglou <savvas-gr@greeklug.gr>
Co-authored-by: Konstantinos <geraki@gmail.com>
Co-authored-by: OWL4C <124401812+OWL4C@users.noreply.github.com>
2025-04-01 20:11:02 +02:00
veeck
a2c1daa667 Merge branch 'mm_master' into mm_develop 2025-04-01 19:18:19 +02:00
Veeck
01fd41c191 Prepare 2.31.0 release (#3757)
updated CHANGELOG and release process documentation

---------

Co-authored-by: veeck <gitkraken@veeck.de>
2025-04-01 18:47:56 +02:00
Veeck
f80b1f1321 Update deps before release (#3756)
Co-authored-by: veeck <gitkraken@veeck.de>
2025-04-01 08:33:31 +02:00
Karsten Hassel
e546fedeb1 updatenotification: add param to get modules from modules-dir instead… (#3755)
… from config

implements #3739
2025-03-31 17:57:42 +02:00
Karsten Hassel
2e57d785ac update dependencies (#3754) 2025-03-28 07:31:36 +01:00
OWL4C
6d909d24e9 [weather] add humidity to hourly view, fix spacing error when using UV Index, add config option to hide precipitation entries that are zero [Rebased Version of PR #3526] (#3748)
Fixed Version of PR #3526 since that was against the wrong branch and
had issues.

Original PR Text: 
Basically the title. Just some existing weather data included into
hourly, some config option ("hideZeroes") to hide precipitation when it
is zero (this actually shrinks the entire table, removing columns that
are completely empty), and add a spacing column to fix the UV Index
column.

---------

Co-authored-by: Veeck <github@veeck.de>
2025-03-27 21:23:17 +01:00
Kristjan ESPERANTO
2ddb7859f6 Fix command to run spellcheck (#3753)
The command wasn't correct.
2025-03-27 11:59:59 +01:00
Karsten Hassel
791f77105a fix stale job (#3751)
exclude issues with label `ready (coming with next release)` from stale
job
2025-03-22 21:23:10 +01:00
Karsten Hassel
46d64abb4b update required node version and dependencies (#3747)
see discussion in
https://github.com/MagicMirrorOrg/MagicMirror/pull/3746

As [electron v35 requires node js
v22.14.0](https://www.electronjs.org/blog/electron-35-0) we should
update this here too.
2025-03-21 12:30:08 +01:00
Kristjan ESPERANTO
68ec696c25 Update ESLint and prettier (#3746)
This will fix #3745.
2025-03-18 22:30:20 +01:00
Karsten Hassel
0cfe2730ea newsfeed: add specific ignoreOlderThan value (override) per feed (#3742)
fixes #3360 

superseeds https://github.com/MagicMirrorOrg/MagicMirror/pull/3429

had to open a new PR because getting `permission denied` when trying to
push to the old one.
2025-03-18 10:19:05 +01:00
sam detweiler
51d11bf26c add support for digital clock time color (#3737)
see
https://forum.magicmirror.builders/topic/19440/digital-clock-minutes-darker

changelog added

question.. 

we have a config parm for seconds color, but not hour/minute
I have used css here.. is that too inconsistent?

---------

Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
Co-authored-by: Veeck <github@veeck.de>
2025-03-16 15:33:27 +01:00
mixasgr
0afc1ed58d Updated Greek Translations (#3741)
Hello,

we have updated the core Greek translation and added Greek translation
to Alerts module.

Thank you!

---------

Co-authored-by: Savvas Adamtziloglou <savvas-gr@greeklug.gr>
Co-authored-by: Konstantinos <geraki@gmail.com>
Co-authored-by: Veeck <github@veeck.de>
2025-03-15 21:54:20 +01:00
Kristjan ESPERANTO
2adf341fef Add Esperanto translation (#3740)
I've had this on my agenda for a long time 🙂
2025-03-13 13:02:02 +01:00
Karsten Hassel
1fcc028e49 update dependencies incl. electron to v35 (#3733) 2025-03-05 12:28:25 +01:00
Nathan
66b8656595 Fix icons, add hourly support, add other weatherflow changes (#3729)
I have updated weatherflow.js to implement the following changes (as
described in #3728)

- Fixed: Weather icons now show up properly
- Added: Location Name support
- Added: Hourly weather forecast support
- Added to current conditions:
  - "Feels like" temp
- Fixed icon for current conditions to be sourced from current
conditions (rather than daily forecast)
  - UV index
- Added to daily forecast
  - Precipitation amount and UV index (via hourly forecast data)

Before:

![image](https://github.com/user-attachments/assets/cfef043c-75ef-4571-8bdc-462e75d3ed81)

After:

![image](https://github.com/user-attachments/assets/e36118bb-a508-4ab1-a7ad-a775bd7a9bb3)
2025-03-01 10:34:02 +01:00
Veeck
4a398f03eb Fix empty part-of-day logic (#3726)
Fixes #3727

---------

Co-authored-by: veeck <gitkraken@veeck.de>
2025-02-27 19:31:00 +01:00
Kristjan ESPERANTO
28bcee7de6 Update ESLint and simplify config (#3724)
This does not change the rules of ESLint. It's just a little cosmetic
fine-tuning.
2025-02-22 19:12:01 +01:00
DevIncomin
62c22d785c Arabic Translation (#3719)
Hello and thank you for wanting to contribute to the MagicMirror²
project!

**Please make sure that you have followed these 4 rules before
submitting your Pull Request:**

> 1. Base your pull requests against the `develop` branch.
> 2. Include these infos in the description:
>
> - Does the pull request solve a **related** issue?
> - If so, can you reference the issue like this `Fixes
#<issue_number>`?
> - What does the pull request accomplish? Use a list if needed.
> - If it includes major visual changes please add screenshots.
>
> 3. Please run `npm run lint:prettier` before submitting so that
>    style issues are fixed.
> 4. Don't forget to add an entry about your changes to
>    the CHANGELOG.md file.

**Note**: Sometimes the development moves very fast. It is highly
recommended that you update your branch of `develop` before creating a
pull request to send us your changes. This makes everyone's lives
easier (including yours) and helps us out on the development team.

Thanks again and have a nice day!
2025-02-06 10:00:41 +01:00
Veeck
aa20eadca3 Monthly update to dependencies (#3717)
nothing to see here really

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: veeck <gitkraken@veeck.de>
2025-02-01 22:24:49 +01:00
Ikko Eltociear Ashimine
e00a666795 chore: update newsfeed.js (#3692)
Therefor -> Therefore

refs: #3690
2025-02-01 07:02:29 +01:00
Karsten Hassel
f34c8f2993 update github workflows (#3709)
to call `sudo apt-get update` before `sudo apt-get install`

I had problems running the tests on my fork, while running the `apt-get
install` command in automated tests workflow I got

```bash
E: Failed to fetch http://security.ubuntu.com/ubuntu/pool/main/m/mesa/libegl-mesa0_24.0.9-0ubuntu0.3_amd64.deb  404  Not Found [IP: 52.147.219.192 80]
```

Found a similar
[Issue](https://github.com/actions/runner-images/issues/10785#issuecomment-2420741561)
with a solution which is to run `sudo apt-get update` before.
2025-01-31 14:54:48 -07:00
Magnus
d6f2e7165f Fix frozen Yr weather-module (#3706)
Fixes #3296 

The problem was that the fetch-methods threw errors when something went
wrong instead of calling `updateAvailable()`. `updateAvailable()` must
be called in order to schedule the next update.

I added some filtering for the hourly forecast that removes hours in the
past. If the API call fails we use the cached data, but we should only
display hours in the future.
2025-01-27 22:41:51 +01:00
sam detweiler
af77b7b628 fix #3701, calculation wrong, added testcase, ics, config (#3702)
fixes #3701 

offset calculation wrong when user looking back at east coast event

added testcase
2025-01-23 08:37:41 +01:00
Kristjan ESPERANTO
53ac31dcf3 Adapt start:x11:dev script (#3700)
This doesn't actually change anything functionally, but with this we use
the same schema as for `start:wayland:dev` and `start:windows:dev`.
2025-01-19 16:29:28 +01:00
Karsten Hassel
9c9a5359dd Use different issue templates (#3695)
This PR will introduce different issue templates for bug reports,
feature requests and so on on GitHub. There is still room for
fine-tuning, but it's reached a state to show it to you and get
feedback.

I think that this can lead to better bug reports.

You can see the result in my repo:
https://github.com/KristjanESPERANTO/MagicMirror/issues/new/choose

Feel free to create new issues for testing.

What do you think? Do we want to pursue this further?
# Conflicts:
#	CHANGELOG.md
2025-01-17 19:19:17 +01:00
Kristjan ESPERANTO
77fe01175c Use different issue templates (#3695)
This PR will introduce different issue templates for bug reports,
feature requests and so on on GitHub. There is still room for
fine-tuning, but it's reached a state to show it to you and get
feedback.

I think that this can lead to better bug reports.

You can see the result in my repo:
https://github.com/KristjanESPERANTO/MagicMirror/issues/new/choose

Feel free to create new issues for testing.

What do you think? Do we want to pursue this further?
2025-01-17 19:03:28 +01:00
Karsten Hassel
6e40c446f4 fix wrong port in log message when starting server only (#3697)
fixes #3696
2025-01-14 22:58:14 +01:00
Karsten Hassel
2400e2045f update dependencies and formatting (#3693)
after updating deps 2 files needed formatting updates
2025-01-13 21:36:44 +01:00
Veeck
99dda821d3 Fix unknown (n/a) icon in openmeteo provider (#3691)
Due to a typo the icon displayed in the openmeteo provider was "N/A" for
a certain weather condition

<img width="284" alt="Bildschirmfoto 2025-01-13 um 16 35 40"
src="https://github.com/user-attachments/assets/e64bf0f8-32d9-44a5-a2b0-42d4f2d6b6df"
/>

---------

Co-authored-by: veeck <gitkraken@veeck.de>
2025-01-13 20:09:33 +01:00
Kristjan ESPERANTO
a7f814d76b Optimize systeminformation calls and output string (#3689)
Since we don't use the `raspberry` information, calling it in `si.get`
is useless.

I also made the string construction in the code a bit more readable. The
output remains the same.
2025-01-12 23:27:31 +01:00
Karsten Hassel
553d2d4a21 electron tests (#3684)
- fix setup to run with xserver and labwc
- remove electronParams from calendar_spec.js (forgotten in
https://github.com/MagicMirrorOrg/MagicMirror/pull/3680)

fixes [running tests locally without labwc
installed](https://github.com/MagicMirrorOrg/MagicMirror/pull/3681#issuecomment-2571736233)

follow up to https://github.com/MagicMirrorOrg/MagicMirror/pull/3680
2025-01-08 11:46:42 +01:00
Kristjan ESPERANTO
b1bc554729 Update year (#3686)
I also added a few new words to the cspell dictionary that were added in
the changelog.

I have not made an extra entry in the changelog for these tiny things.
2025-01-06 21:20:19 +01:00
sam detweiler
5e337f8b5f fix #3267, CORRECTLY, add testcase, add testcase for #3279 (#3681)
fixes #3267 AGAIN, correctly, add testcase
add testcase for #3679 , broadcast clipping incorrectly

I added a test module (tests/testNotification) to catch the notification
and check the count. (one way to configure)
i put this module in the tests folder, and added /tests to the server
paths.
(can't have a module in a nested folder, like tests/modules/xxx)

but I have a problem. i can run the test config (MM_CONFIG_FILE), and
the two modules work correctly,
but in the spec runner, the calendar module times out on the broadcast
test.. there is only local ics file access, no outside hosts

I forced my system date to 1/1/24 (same as runner) and again the manual
testcase works fine

I added two test config.js,(configs/calendar) one works great (symbols)
, one fails (broadcast test)
I added additional delay in the calendarspec runner to try to debug the
module, but it still not long enough.. no messages of trouble when I get
into the browser.. BUT, this may be because of the log being turned
off... (just thought of this)

I created a special ICS (in mocks) that has 12 events, 1 for each
month.. (so I can check clipping and broadcast) the US holidays one is
sensitive to the current date, and I couldn't get it to work on
1/1/2024..

also, in general, is there a mechanism to run test:just_one_runner?
waiting thru the electron test to get to one testcase.. ugh..
2025-01-05 22:25:32 +01:00
Karsten Hassel
8fdd865cb1 electron tests: fixes for running under new github image ubuntu-24.04 (#3680)
and replace xserver with labwc, fixes #3676
2025-01-05 11:07:34 +01:00
Karsten Hassel
0f6efac8e6 clientonly and wayland, hotfix electron tests (#3677)
clientonly:
- did work only with xserver and `DISPLAY` env var
- now checks for `WAYLAND_DISPLAY` or `DISPLAY` env var before running
- if `WAYLAND_DISPLAY` is set now starts with wayland parameters

electron tests see #3676
2025-01-03 21:52:10 +01:00
sam detweiler
75dbe67167 Fix calendar clipping before broadcast (#3679)
-fixes #3678
2025-01-03 19:10:29 +01:00
sam detweiler
6f50a7b3bd Release 2.31.0 (#3674)
begin next release
2025-01-01 10:33:17 -06:00
sam detweiler
c24de64d77 Release 2.30.0 (#3673)
## [2.30.0] - 2025-01-01

Thanks to: @xsorifc28, @HeikoGr, @bugsounet, @khassel,
@KristjanESPERANTO, @rejas, @sdetweil.

> ⚠️ This release needs nodejs version `v20` or `v22 or higher`, minimum
version is `v20.18.1`

### Added

- [core] Add wayland and windows start options to `package.json` (#3594)
- [docs] Add step for npm publishing in release process (#3595)
- [core] Add GitHub workflow to run spellcheck a few days before each
release (#3623)
- [core] Add test flag to `index.html` to pass to module js for test
mode detection (needed by #3630)
- [core] Add export on animation names (#3644)
- [compliments] Add support for refreshing remote compliments file, and
test cases (#3630)
- [linter] Re-add `eslint-plugin-import`now that it supports ESLint v9
(#3586)
- [linter] Re-activate `eslint-plugin-package-json` to lint
`package.json` (#3643)
- [linter] Add linting for markdown files (#3646)
- [linter] Add some handy ESLint rules.
- [calendar] Add ability to display end date for full date events, where
end is not same day (showEnd=true) (#3650)
- [core] Add text to the config.js.sample file about the locale variable
(#3654, #3655)
- [core] Add fetch timeout for all node_helpers (thru undici, forces
node 20.18.1 minimum) to help on slower systems. (#3660) (3661)

### Changed

- [core] Run code style checks in workflow only once (#3648)
- [core] Fix animations export #3644 only on server side (#3649)
- [core] Use project URL in fallback config (#3656)
- [core] Fix Access Denied crash writing js/positions.js (on synology
nas) #3651. new message, MM starts, but no modules showing (#3652)
- [linter] Switch to 'npx' for lint-staged in pre-commit hook (#3658)

### Removed

- [tests] Remove `node-pty` and `drivelist` from rebuilded test (#3575)
- [deps] Remove `@eslint/js` dependency. Already installed with `eslint`
in deep (#3636)

### Updated

- [repo] Reactivate `stale.yaml` as GitHub action to mark issues as
stale after 60 days and close them 7 days later (if no activity) (#3577,
#3580, #3581)
- [core] Update electron dependency to v32 (test electron rebuild) and
all other dependencies too (#3657)
- [tests] All test configs have been updated to allow full external
access, allowing for easier debugging (especially when running as a
container)
- [core] Run and test with node 23 (#3588)
- [workflow] delete exception `allow-ghsas: GHSA-8hc4-vh64-cxmj` in
`dep-review.yaml` (#3659)

### Fixed

- [updatenotification] Fix pm2 using detection when pm2 script is inside
or outside MagicMirror root folder (#3576) (#3605) (#3626) (#3628)
- [core] Fix loading node_helper of modules: avoid black screen, display
errors and continue loading with next module (#3578)
- [weather] Change default value for weatherEndpoint of provider
openweathermap to "/onecall" (#3574)
- [tests] Fix electron tests with mock dates, the mock on server side
was missing (#3597)
- [tests] Fix testcases with hard coded Date.now (#3597)
- [core] Fix missing `basePath` where `location.host` is used (#3613)
- [compliments] croner library changed filenames used in latest version
(#3624)
- [linter] Fix ESLint ignore pattern which caused that default modules
not to be linted (#3632)
- [core] Fix module path in case of sub/sub folder is used and use
path.resolve for resolve `moduleFolder` and `defaultModuleFolder` in
app.js (#3653)
- [calendar] Update to resolve issues #3098 #3144 #3351 #3422 #3443
#3467 #3537 related to timezone changes
- [calendar] Fix #3267 (styles array), also fixes event with both exdate
AND recurrence(and testcase)
- [calendar] Fix showEndsOnlyWithDuration not working, #3598, applies
ONLY to full day events
- [calendar] Fix showEnd for Full Day events (#3602)
- [tests] Suppress "module is not defined" in e2e tests (#3647)
- [calendar] Fix #3267 (styles array, really this time!)
- [core] Fix #3662 js/positions.js created incorrectly

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Michael Teeuw <michael@xonaymedia.nl>
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Karsten Hassel <hassel@gmx.de>
Co-authored-by: Ross Younger <crazyscot@gmail.com>
Co-authored-by: Veeck <github@veeck.de>
Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr>
Co-authored-by: jkriegshauser <joshuakr@nvidia.com>
Co-authored-by: illimarkangur <116028111+illimarkangur@users.noreply.github.com>
Co-authored-by: vppencilsharpener <tim.pray@gmail.com>
Co-authored-by: veeck <michael.veeck@nebenan.de>
Co-authored-by: Paranoid93 <6515818+Paranoid93@users.noreply.github.com>
Co-authored-by: Brian O'Connor <btoconnor@users.noreply.github.com>
Co-authored-by: WallysWellies <59727507+WallysWellies@users.noreply.github.com>
Co-authored-by: Jason Stieber <jrstieber@gmail.com>
Co-authored-by: jargordon <50050429+jargordon@users.noreply.github.com>
Co-authored-by: Daniel <32464403+dkallen78@users.noreply.github.com>
Co-authored-by: Ryan Williams <65094007+ryan-d-williams@users.noreply.github.com>
Co-authored-by: Panagiotis Skias <panagiotis.skias@gmail.com>
Co-authored-by: Marc Landis <dirk.rettschlag@gmail.com>
Co-authored-by: HeikoGr <20295490+HeikoGr@users.noreply.github.com>
Co-authored-by: Pedro Lamas <pedrolamas@gmail.com>
Co-authored-by: veeck <gitkraken@veeck.de>
2025-01-01 08:27:27 -06:00
sam detweiler
9be625c72b ready for release 2.30.0 (#3672)
Update files impacted for release
2025-01-01 15:18:25 +01:00
Veeck
c92fbb8a7e Final dependency updates for v2.30 (#3671)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: veeck <gitkraken@veeck.de>
2025-01-01 14:30:18 +01:00
Kristjan ESPERANTO
143dfd6b67 Add some ESLint rules + minor changes (#3665)
Main point was to enable ESLint `dot-notation` and `no-unneeded-ternary`
rules for more code consistency.

I took the occasion to add two minor commits:
- Fix a problem found by running `test:spelling
- Minor dependency update

It wouldn't be a problem if the PR didn't arrive in the next release,
the changes are cosmetic.
2024-12-30 12:24:51 +01:00
Karsten Hassel
d41ce81469 update dependencies, fix typo in Collaboration.md (#3664)
last dependency update before release
2024-12-28 20:18:45 +01:00
sam detweiler
93a0c24c22 fix #3662 line parse on windows with linux line ends (#3663)
line parse used os.EOL, which failed with linux line ends in index.html,
change to '\n'
2024-12-28 18:57:39 +01:00
Bugsounet - Cédric
9d0501f240 Fix: package-lock.json after PR #3660 (#3661)
continue from #3660 

Fix: package-lock.json (check node engine)
2024-12-27 14:20:24 +01:00
sam detweiler
6a09bc4ec4 add support for fetch timeout control for node_helpers, fix timeouts on armv6l (#3660)
user reporting slow/no connection/timeout errors on armv6l for calendar,
and newsfeed

we can increase the timeout by adding calls to the undici lib, but it
requires node 20.18.1 or above.

this adds the support for timeout
(also environment variable to override if needed,, mmFetchTimeout
(default 30 seconds)

and updates the base node version
2024-12-26 00:28:16 +01:00
Bugsounet - Cédric
2fb51436a5 delete exception allow-ghsas: GHSA-8hc4-vh64-cxmj in dep-review.yaml (#3659)
node needed with new version of `node-ical`
2024-12-24 15:20:29 +01:00
Kristjan ESPERANTO
0b3a04c520 Switch to 'npx' for lint-staged in pre-commit hook (#3658)
This way we get rid of the script entry in the `package.json` and the
whole thing becomes a little less complex.
2024-12-22 07:26:01 +01:00
Bugsounet - Cédric
c485ff670d path resolve and sub/sub folder module (#3653)
Fix:
 - use `path.resolve` for `moduleFolder` and `defaultModuleFolder` path
- Fix module path in case of sub/sub folder is used (sample
`module/test/test`)
 
---
case of module installation on `module/test/test`:

config will be:
```js
 {
    module: "test/test",
    ...
 }
```

module core will be:
```js
Module.register("test", {
...
```
`test.js` is used for module core (no change)

---

case of module installation on `module/test` (no change):
config will be:
```js
 {
    module: "test",
    ...
 }
```

module core will be:
```js
Module.register("test", {
...
```
so `test.js` is used for module core

---

In reality, with this patch, `module` config feature have 2
functionalites:
 -  determinate module path with more precision
 -  allow to use sub/sub folder in modules folder

---------

Co-authored-by: Veeck <github@veeck.de>
2024-12-18 22:07:09 +01:00
Karsten Hassel
b910c60eb2 update dependencies (#3657) 2024-12-18 22:04:16 +01:00
sam detweiler
24d9b70c4c fix access denied fault error writing js/positions.js (#3652)
if the MagicMirror js folder is not writable (synology nas created by
different user than docker container) there is an uncaught throw

```
[ERROR] EACCES: permission denied, open 'js/positions.js' 
```

add try/catch, output new message, console.error
```text
unable to write js/positions.js with the discovered module positions
make the MagicMirror/js folder writeable by the user starting MagicMirror 
```

MM will start, but no modules will show, as no positions were discovered
this file is used to pass the list from the server side to the browser
side

fixes #3651
2024-12-18 17:37:51 +01:00
sam detweiler
786eacf41a update config.js.sample about locale variable (#3655)
add text to config.js.sample about usage of locale variable/property

Co-authored-by: Veeck <github@veeck.de>
2024-12-18 13:43:20 +01:00
Kristjan ESPERANTO
5b3b40da66 Use project URL in fallback config (#3656) 2024-12-18 08:00:00 +01:00
sam detweiler
5232f46d44 fix #3267 again this time, dropped from big cal update (#3650)
this change was dropped from #3267 by mistake
2024-12-08 21:23:53 +01:00
sam detweiler
39ab651319 Show animations, fix export only on server side (#3649)
fix #3644 so only on server side
2024-12-08 16:24:39 +01:00
Kristjan ESPERANTO
76fac78909 Run code style checks in workflow only once (#3648)
It's enough if the code style checks are successful once, it's not
necessary to run them with every node version.

Also, if there is an error, we can see more quickly whether it is a code
style or a test-runner issue.
2024-12-07 18:29:49 +01:00
Kristjan ESPERANTO
5b7b76c877 Add linting for markdown files (#3646)
I also reworked the Linters section in `CONTRIBUTING.md` a bit and
switched the `prettier` config to a flat config.

Co-authored-by: Veeck <github@veeck.de>
2024-12-07 10:12:28 +01:00
sam detweiler
19bd76ab93 Fixcaldates2 fix calendar module date processing, using node-ical@0.20.1 (#3587)
here is an updated test version of the fixes for all kinds of calendar
date problems.

NOTE: the changed branch name
NOTE: this used the node-cal@0.19.0 library UNCHANGED

best to make a new folder and git clone there

git clone https://github.com/sdetweil/MagicMirror
cd MagicMirror
git checkout fixcaldates2 // <------ note this is a changed branch name
npm run install-mm
copy your config.js and custom.css from the prior folder
and the non-default modules you have installed…

this ONLY changes the default calendar
but DOES ship an updated node-ical library too

if you need to fall back, just rename the folders around again so that
your original is called MagicMirror

all the testcases for node-ical and MagicMirror execute successfully.

the ‘BIG’ change here is to get the local NON-TZ dates for the
rrule.between()

all the checking and conversion code is commented out or not used
the node-ical fixes are for excluded dates (exdate) values being
adjusted for DST/STD time… waiting to submit that PR

one fix in calendar.js for checking if a past date was too far back,
but it never checked to see IF the event date was in the past… (before
today) so it chopped off too many

and one change in calendarfetcher.js to put out a better diagnostic
message of the parsed data… (exdate was excluded cause JSON stringify
couldn’t convert the complex structure)

I added the tests you all have documented

please re-pull and checkout the new branch (I deleted the old branch)
and npm run install-mm again

---------

Co-authored-by: Veeck <github@veeck.de>
2024-12-07 09:51:11 +01:00
Kristjan ESPERANTO
291ae8546c Handle "module is not defined" in e2e tests (#3647)
Even in successful tests, there are many module not defined` error
entries. Like this:
https://github.com/MagicMirrorOrg/MagicMirror/actions/runs/12199106844/job/34032254241#step:5:353

I think we can suppress them.
2024-12-07 08:17:04 +01:00
sam detweiler
63178eba72 Export animations (#3644)
I am adding the animateIn/Out support to MMM-Config, but I need the list
of animations..
but they are not visible in js/animateCSS.js (from require)

adding an export satisfies that

side issue, these would go in a dropdown list
what value can I use for the default behavior? none/default?
don't want an error produced..
should I add code to check for this value to prevent error?
2024-12-02 10:17:19 +01:00
Kristjan ESPERANTO
07768c3a88 Reactivate eslint-plugin-package-json (#3643)
Somehow the plugin get lost when we moved to ESLint flat config. Now I
reactivated it.

One rules caused sorting the scripts. If this is not okay, I can undo
this and switch off the rule.

Thank's @bugsounet for the pinging in
https://github.com/MagicMirrorOrg/MagicMirror/pull/3637#issuecomment-2509771362.
2024-12-01 15:26:23 +01:00
dependabot[bot]
8d61336e8b Bump @fortawesome/fontawesome-free from 6.6.0 to 6.7.1 in /vendor (#3641)
Bumps
[@fortawesome/fontawesome-free](https://github.com/FortAwesome/Font-Awesome)
from 6.6.0 to 6.7.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/FortAwesome/Font-Awesome/releases"><code>@​fortawesome/fontawesome-free</code>'s
releases</a>.</em></p>
<blockquote>
<h2>Release 6.7.1</h2>
<p><strong>Change log available at <a
href="https://fontawesome.com/docs/changelog/">https://fontawesome.com/docs/changelog/</a></strong></p>
<h2>Release 6.7.0</h2>
<p><strong>Change log available at <a
href="https://fontawesome.com/docs/changelog/">https://fontawesome.com/docs/changelog/</a></strong></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3447c58c6b"><code>3447c58</code></a>
Release 6.7.1 (<a
href="https://redirect.github.com/FortAwesome/Font-Awesome/issues/20426">#20426</a>)</li>
<li><a
href="a03a91d681"><code>a03a91d</code></a>
Release 6.7.0 (<a
href="https://redirect.github.com/FortAwesome/Font-Awesome/issues/20418">#20418</a>)</li>
<li>See full diff in <a
href="https://github.com/FortAwesome/Font-Awesome/compare/6.6.0...6.7.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@fortawesome/fontawesome-free&package-manager=npm_and_yarn&previous-version=6.6.0&new-version=6.7.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-01 12:27:20 +01:00
dependabot[bot]
28341d4a54 Bump eslint-plugin-package-json from 0.15.4 to 0.17.0 (#3637)
Bumps
[eslint-plugin-package-json](https://github.com/JoshuaKGoldberg/eslint-plugin-package-json)
from 0.15.4 to 0.17.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/releases">eslint-plugin-package-json's
releases</a>.</em></p>
<blockquote>
<h2>v0.17.0</h2>
<h2>What's Changed</h2>
<ul>
<li>docs: add sasial-dev as a contributor for code by <a
href="https://github.com/allcontributors"><code>@​allcontributors</code></a>
in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/669">JoshuaKGoldberg/eslint-plugin-package-json#669</a></li>
<li>feat: sort alphabetically with co-located hooks for
<code>scripts</code> by <a
href="https://github.com/sasial-dev"><code>@​sasial-dev</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/632">JoshuaKGoldberg/eslint-plugin-package-json#632</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/compare/v0.16.0...v0.17.0">https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/compare/v0.16.0...v0.17.0</a></p>
<h2>v0.16.0</h2>
<h2>What's Changed</h2>
<ul>
<li>chore(deps): update dependency cspell to v8.16.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/617">JoshuaKGoldberg/eslint-plugin-package-json#617</a></li>
<li>chore(deps): update dependency eslint-plugin-jsonc to v2.17.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/618">JoshuaKGoldberg/eslint-plugin-package-json#618</a></li>
<li>docs: add unique dependencies rule by <a
href="https://github.com/davidlj95"><code>@​davidlj95</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/620">JoshuaKGoldberg/eslint-plugin-package-json#620</a></li>
<li>docs: add rakleed as a contributor for ideas by <a
href="https://github.com/allcontributors"><code>@​allcontributors</code></a>
in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/622">JoshuaKGoldberg/eslint-plugin-package-json#622</a></li>
<li>docs: add davidlj95 as a contributor for doc by <a
href="https://github.com/allcontributors"><code>@​allcontributors</code></a>
in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/621">JoshuaKGoldberg/eslint-plugin-package-json#621</a></li>
<li>chore(deps): update dependency eslint-plugin-jsonc to v2.18.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/623">JoshuaKGoldberg/eslint-plugin-package-json#623</a></li>
<li>chore(deps): update dependency knip to v5.36.4 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/624">JoshuaKGoldberg/eslint-plugin-package-json#624</a></li>
<li>chore(deps): update dependency knip to v5.36.5 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/625">JoshuaKGoldberg/eslint-plugin-package-json#625</a></li>
<li>chore(deps): update dependency eslint-plugin-jsonc to v2.18.1 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/626">JoshuaKGoldberg/eslint-plugin-package-json#626</a></li>
<li>chore(deps): update dependency knip to v5.36.6 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/627">JoshuaKGoldberg/eslint-plugin-package-json#627</a></li>
<li>chore(deps): update dependency
<code>@​typescript-eslint/parser</code> to v8.14.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/628">JoshuaKGoldberg/eslint-plugin-package-json#628</a></li>
<li>chore(deps): update dependency knip to v5.36.7 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/629">JoshuaKGoldberg/eslint-plugin-package-json#629</a></li>
<li>chore(deps): update dependency
<code>@​release-it/conventional-changelog</code> to v9.0.3 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/630">JoshuaKGoldberg/eslint-plugin-package-json#630</a></li>
<li>chore(deps): update dependency eslint-plugin-jsdoc to v50.5.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/631">JoshuaKGoldberg/eslint-plugin-package-json#631</a></li>
<li>chore(deps): update pnpm to v9.13.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/633">JoshuaKGoldberg/eslint-plugin-package-json#633</a></li>
<li>chore(deps): update dependency knip to v5.37.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/634">JoshuaKGoldberg/eslint-plugin-package-json#634</a></li>
<li>chore(deps): update pnpm to v9.13.1 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/635">JoshuaKGoldberg/eslint-plugin-package-json#635</a></li>
<li>chore(deps): update dependency eslint-plugin-regexp to v2.7.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/636">JoshuaKGoldberg/eslint-plugin-package-json#636</a></li>
<li>chore(deps): update pnpm to v9.13.2 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/637">JoshuaKGoldberg/eslint-plugin-package-json#637</a></li>
<li>chore(deps): update codecov/codecov-action action to v5 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/638">JoshuaKGoldberg/eslint-plugin-package-json#638</a></li>
<li>chore(deps): update dependency knip to v5.37.1 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/639">JoshuaKGoldberg/eslint-plugin-package-json#639</a></li>
<li>chore(deps): update dependency eslint-plugin-jsonc to v2.18.2 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/640">JoshuaKGoldberg/eslint-plugin-package-json#640</a></li>
<li>chore(deps): update dependency husky to v9.1.7 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/641">JoshuaKGoldberg/eslint-plugin-package-json#641</a></li>
<li>chore(deps): update dependency
<code>@​typescript-eslint/parser</code> to v8.15.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/642">JoshuaKGoldberg/eslint-plugin-package-json#642</a></li>
<li>chore(deps): update dependency <code>@​types/node</code> to v22.9.1
by <a href="https://github.com/renovate"><code>@​renovate</code></a> in
<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/644">JoshuaKGoldberg/eslint-plugin-package-json#644</a></li>
<li>chore(deps): update pnpm to v9.14.1 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/645">JoshuaKGoldberg/eslint-plugin-package-json#645</a></li>
<li>chore(deps): update pnpm to v9.14.2 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/646">JoshuaKGoldberg/eslint-plugin-package-json#646</a></li>
<li>chore(deps): update dependency prettier-plugin-packagejson to v2.5.5
by <a href="https://github.com/renovate"><code>@​renovate</code></a> in
<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/647">JoshuaKGoldberg/eslint-plugin-package-json#647</a></li>
<li>chore(deps): update dependency knip to v5.37.2 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/649">JoshuaKGoldberg/eslint-plugin-package-json#649</a></li>
<li>chore(deps): update dependency typescript to v5.7.2 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/650">JoshuaKGoldberg/eslint-plugin-package-json#650</a></li>
<li>chore(deps): update dependency <code>@​types/node</code> to v22.9.2
by <a href="https://github.com/renovate"><code>@​renovate</code></a> in
<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/651">JoshuaKGoldberg/eslint-plugin-package-json#651</a></li>
<li>chore(deps): update dependency <code>@​types/node</code> to v22.9.3
by <a href="https://github.com/renovate"><code>@​renovate</code></a> in
<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/652">JoshuaKGoldberg/eslint-plugin-package-json#652</a></li>
<li>chore(deps): update dependency markdownlint-cli to ^0.43.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/653">JoshuaKGoldberg/eslint-plugin-package-json#653</a></li>
<li>docs: fix jsonc-eslint-parser installation instructions by <a
href="https://github.com/JoshuaKGoldberg"><code>@​JoshuaKGoldberg</code></a>
in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/654">JoshuaKGoldberg/eslint-plugin-package-json#654</a></li>
<li>chore(deps): update dependency prettier-plugin-packagejson to v2.5.6
by <a href="https://github.com/renovate"><code>@​renovate</code></a> in
<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/648">JoshuaKGoldberg/eslint-plugin-package-json#648</a></li>
<li>chore(deps): update dependency
<code>@​typescript-eslint/parser</code> to v8.16.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/656">JoshuaKGoldberg/eslint-plugin-package-json#656</a></li>
<li>chore(deps): update dependency <code>@​types/node</code> to v22.9.4
by <a href="https://github.com/renovate"><code>@​renovate</code></a> in
<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/657">JoshuaKGoldberg/eslint-plugin-package-json#657</a></li>
<li>chore(deps): update dependency <code>@​types/node</code> to v22.10.0
by <a href="https://github.com/renovate"><code>@​renovate</code></a> in
<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/658">JoshuaKGoldberg/eslint-plugin-package-json#658</a></li>
<li>chore(deps): update dependency knip to v5.38.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/659">JoshuaKGoldberg/eslint-plugin-package-json#659</a></li>
<li>chore(deps): update dependency eslint-plugin-jsdoc to v50.6.0 by <a
href="https://github.com/renovate"><code>@​renovate</code></a> in <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/pull/662">JoshuaKGoldberg/eslint-plugin-package-json#662</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/blob/main/CHANGELOG.md">eslint-plugin-package-json's
changelog</a>.</em></p>
<blockquote>
<h1><a
href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/compare/v0.16.0...v0.17.0">0.17.0</a>
(2024-11-30)</h1>
<h3>Features</h3>
<ul>
<li>sort alphabetically with co-located hooks for <code>scripts</code>
(<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/632">#632</a>)
(<a
href="4ccae4f58e">4ccae4f</a>),
closes <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/499">#499</a>
<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/499">#499</a></li>
</ul>
<h1><a
href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/compare/v0.15.6...v0.16.0">0.16.0</a>
(2024-11-30)</h1>
<h3>Features</h3>
<ul>
<li><strong>sort-collections:</strong> should sort
<code>overrides</code> (<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/668">#668</a>)
(<a
href="18129cd5c4">18129cd</a>),
closes <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/619">#619</a></li>
</ul>
<h2><a
href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/compare/v0.15.5...v0.15.6">0.15.6</a>
(2024-11-09)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>add sorting exports field (<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/615">#615</a>)
(<a
href="116c74be65">116c74b</a>),
closes <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/000">#000</a></li>
</ul>
<h2><a
href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/compare/v0.15.4...v0.15.5">0.15.5</a>
(2024-11-06)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>add plugin export (<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/609">#609</a>)
(<a
href="a2c83b42c2">a2c83b4</a>),
closes <a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/000">#000</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="a16b6ba552"><code>a16b6ba</code></a>
chore: release v0.17.0</li>
<li><a
href="4ccae4f58e"><code>4ccae4f</code></a>
feat: sort alphabetically with co-located hooks for <code>scripts</code>
(<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/632">#632</a>)</li>
<li><a
href="100ce08a05"><code>100ce08</code></a>
docs: add sasial-dev as a contributor for code (<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/669">#669</a>)</li>
<li><a
href="79a18e278c"><code>79a18e2</code></a>
chore: release v0.16.0</li>
<li><a
href="18129cd5c4"><code>18129cd</code></a>
feat(sort-collections): should sort <code>overrides</code> (<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/668">#668</a>)</li>
<li><a
href="36e68b70fb"><code>36e68b7</code></a>
chore(deps): update dependency cspell to v8.16.1 (<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/667">#667</a>)</li>
<li><a
href="189345dfb9"><code>189345d</code></a>
docs: add rakleed as a contributor for doc (<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/666">#666</a>)</li>
<li><a
href="3b23f4a054"><code>3b23f4a</code></a>
docs: add <code>Development</code> section in README (<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/665">#665</a>)</li>
<li><a
href="383fe630b8"><code>383fe63</code></a>
docs: add rakleed as a contributor for tool (<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/664">#664</a>)</li>
<li><a
href="4a6e3c4c4f"><code>4a6e3c4</code></a>
chore(deps): update dependency knip to v5.38.1 (<a
href="https://redirect.github.com/JoshuaKGoldberg/eslint-plugin-package-json/issues/663">#663</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/JoshuaKGoldberg/eslint-plugin-package-json/compare/v0.15.4...v0.17.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=eslint-plugin-package-json&package-manager=npm_and_yarn&previous-version=0.15.4&new-version=0.17.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-01 12:01:50 +01:00
dependabot[bot]
f417bc0204 Bump prettier from 3.3.3 to 3.4.1 (#3638)
Bumps [prettier](https://github.com/prettier/prettier) from 3.3.3 to
3.4.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/releases">prettier's
releases</a>.</em></p>
<blockquote>
<h2>3.4.1</h2>
<p>🔗 <a
href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md#341">Changelog</a></p>
<h2>3.4.0</h2>
<p><a
href="https://github.com/prettier/prettier/compare/3.3.3...3.4.0">diff</a></p>
<p>🔗 <a href="https://prettier.io/blog/2024/11/26/3.4.0.html">Release
note</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md">prettier's
changelog</a>.</em></p>
<blockquote>
<h1>3.4.1</h1>
<p><a
href="https://github.com/prettier/prettier/compare/3.4.0...3.4.1">diff</a></p>
<h4>Remove unnecessary parentheses around assignment in
<code>v-on</code> (<a
href="https://redirect.github.com/prettier/prettier/pull/16887">#16887</a>
by <a href="https://github.com/fisker"><code>@​fisker</code></a>)</h4>
<!-- raw HTML omitted -->
<pre lang="vue"><code>&lt;!-- Input --&gt;
\&lt;template&gt;
  &lt;button @click=&quot;foo += 2&quot;&gt;Click&lt;/button&gt;
&lt;/template&gt;
<p>&lt;!-- Prettier 3.4.0 --&gt;<br />
&amp;lt;template&gt;<br />
&lt;button <a
href="https://github.com/click"><code>@​click</code></a>=&quot;(foo +=
2)&quot;&gt;Click&lt;/button&gt;<br />
&lt;/template&gt;</p>
<p>&lt;!-- Prettier 3.4.1 --&gt;<br />
&amp;lt;template&gt;<br />
&lt;button <a
href="https://github.com/click"><code>@​click</code></a>=&quot;foo +=
2&quot;&gt;Click&lt;/button&gt;<br />
&lt;/template&gt;<br />
</code></pre></p>
<h1>3.4.0</h1>
<p><a
href="https://github.com/prettier/prettier/compare/3.3.3...3.4.0">diff</a></p>
<p>🔗 <a href="https://prettier.io/blog/2024/11/26/3.4.0.html">Release
Notes</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="37fd1774d1"><code>37fd177</code></a>
Release 3.4.1</li>
<li><a
href="1fb629709a"><code>1fb6297</code></a>
Update ts-api-utils to v1.4.2 (<a
href="https://redirect.github.com/prettier/prettier/issues/16888">#16888</a>)</li>
<li><a
href="f6fccadbc7"><code>f6fccad</code></a>
Remove unnecessary parentheses around assignment in <code>v-on</code>
(<a
href="https://redirect.github.com/prettier/prettier/issues/16887">#16887</a>)</li>
<li><a
href="5fef089377"><code>5fef089</code></a>
Minor improvements in v3.4.0 blog post (<a
href="https://redirect.github.com/prettier/prettier/issues/16886">#16886</a>)</li>
<li><a
href="3542f13845"><code>3542f13</code></a>
3.4 release blog (<a
href="https://redirect.github.com/prettier/prettier/issues/16851">#16851</a>)</li>
<li><a
href="f53791a2c8"><code>f53791a</code></a>
Clean changelog_unreleased</li>
<li><a
href="2b41c937fc"><code>2b41c93</code></a>
Bump Prettier dependency to 3.4.0</li>
<li><a
href="10baab2f57"><code>10baab2</code></a>
Update dependents count</li>
<li><a
href="7999e10265"><code>7999e10</code></a>
Release 3.4.0</li>
<li><a
href="2262d1e4a3"><code>2262d1e</code></a>
chore(config): migrate renovate config (<a
href="https://redirect.github.com/prettier/prettier/issues/16884">#16884</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/prettier/prettier/compare/3.3.3...3.4.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=prettier&package-manager=npm_and_yarn&previous-version=3.3.3&new-version=3.4.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-01 12:00:28 +01:00
dependabot[bot]
3627bebc3a Bump stylelint from 16.10.0 to 16.11.0 (#3639)
Bumps [stylelint](https://github.com/stylelint/stylelint) from 16.10.0
to 16.11.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/stylelint/stylelint/releases">stylelint's
releases</a>.</em></p>
<blockquote>
<h2>16.11.0</h2>
<ul>
<li>Added: <code>--report-unscoped-disables</code> CLI flag and
<code>reportUnscopedDisables</code> option to Node.js API and
configuration object (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8024">#8024</a>)
(<a
href="https://github.com/Mouvedia"><code>@​Mouvedia</code></a>).</li>
<li>Added: <code>ignoreFunctions: []</code> to
<code>media-query-no-invalid</code> (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8060">#8060</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Added: <code>name</code> configuration property under
<code>overrides</code> (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8095">#8095</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>benchmark-rule</code> script to resolve
<code>TypeError</code> (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8090">#8090</a>)
(<a
href="https://github.com/ybiquitous"><code>@​ybiquitous</code></a>).</li>
<li>Fixed: <code>github</code> formatter deprecation warning link to
<code>https://stylelint.io/awesome-stylelint#formatters</code> (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8115">#8115</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>function-calc-no-unspaced-operator</code> false
negatives for <code>calc-size</code> (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8026">#8026</a>)
(<a href="https://github.com/azat-io"><code>@​azat-io</code></a>).</li>
<li>Fixed: <code>max-nesting-depth</code> false positives when the
<code>&amp;</code> selector is being ignored (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8048">#8048</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>media-feature-name-value-no-unknown</code> false
positives for <code>display-mode: picture-in-picture</code> (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8136">#8136</a>)
(<a
href="https://github.com/Mouvedia"><code>@​Mouvedia</code></a>).</li>
<li>Fixed: <code>no-irregular-whitespace</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8066">#8066</a>)
(<a
href="https://github.com/romainmenke"><code>@​romainmenke</code></a>).</li>
<li>Fixed: <code>selector-attribute-name-disallowed-list</code> reported
ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8037">#8037</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-attribute-operator-allowed-list</code>
reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8038">#8038</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-attribute-operator-disallowed-list</code>
reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8039">#8039</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-class-pattern</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8042">#8042</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-combinator-allowed-list</code> reported ranges
(<a
href="https://redirect.github.com/stylelint/stylelint/issues/8046">#8046</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-combinator-disallowed-list</code> reported
ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8047">#8047</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-disallowed-list</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8067">#8067</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-id-pattern</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8045">#8045</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-max-attribute</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8052">#8052</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-max-class</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8053">#8053</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-max-combinators</code> reported-ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8055">#8055</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-max-compound-selectors</code> reported ranges
(<a
href="https://redirect.github.com/stylelint/stylelint/issues/8056">#8056</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-max-id</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8054">#8054</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-max-pseudo-class</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8057">#8057</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-max-specificity</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8058">#8058</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-max-universal</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8059">#8059</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-nested-pattern</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8072">#8072</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-no-vendor-prefix</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8073">#8073</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-not-notation</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8074">#8074</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-pseudo-class-allowed-list</code> reported
ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8061">#8061</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-pseudo-class-disallowed-list</code> reported
ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8062">#8062</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-pseudo-class-no-unknown</code> reported ranges
(<a
href="https://redirect.github.com/stylelint/stylelint/issues/8063">#8063</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-pseudo-element-allowed-list</code> reported
ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8068">#8068</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-pseudo-element-colon-notation</code> reported
ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8069">#8069</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-pseudo-element-disallowed-list</code> reported
ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8070">#8070</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-pseudo-element-no-unknown</code> false
positives for <code>::scroll-marker</code> and
<code>::scroll-marker-group</code> (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8110">#8110</a>)
(<a
href="https://github.com/Mouvedia"><code>@​Mouvedia</code></a>).</li>
<li>Fixed: <code>selector-pseudo-element-no-unknown</code> reported
ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8071">#8071</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-type-no-unknown</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8076">#8076</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md">stylelint's
changelog</a>.</em></p>
<blockquote>
<h2>16.11.0</h2>
<ul>
<li>Added: <code>--report-unscoped-disables</code> CLI flag and
<code>reportUnscopedDisables</code> option to Node.js API and
configuration object (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8024">#8024</a>)
(<a
href="https://github.com/Mouvedia"><code>@​Mouvedia</code></a>).</li>
<li>Added: <code>ignoreFunctions: []</code> to
<code>media-query-no-invalid</code> (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8060">#8060</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Added: <code>name</code> configuration property under
<code>overrides</code> (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8095">#8095</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>benchmark-rule</code> script to resolve
<code>TypeError</code> (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8090">#8090</a>)
(<a
href="https://github.com/ybiquitous"><code>@​ybiquitous</code></a>).</li>
<li>Fixed: <code>github</code> formatter deprecation warning link to
<code>https://stylelint.io/awesome-stylelint#formatters</code> (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8115">#8115</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>function-calc-no-unspaced-operator</code> false
negatives for <code>calc-size</code> (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8026">#8026</a>)
(<a href="https://github.com/azat-io"><code>@​azat-io</code></a>).</li>
<li>Fixed: <code>max-nesting-depth</code> false positives when the
<code>&amp;</code> selector is being ignored (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8048">#8048</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>media-feature-name-value-no-unknown</code> false
positives for <code>display-mode: picture-in-picture</code> (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8136">#8136</a>)
(<a
href="https://github.com/Mouvedia"><code>@​Mouvedia</code></a>).</li>
<li>Fixed: <code>no-irregular-whitespace</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8066">#8066</a>)
(<a
href="https://github.com/romainmenke"><code>@​romainmenke</code></a>).</li>
<li>Fixed: <code>selector-attribute-name-disallowed-list</code> reported
ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8037">#8037</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-attribute-operator-allowed-list</code>
reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8038">#8038</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-attribute-operator-disallowed-list</code>
reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8039">#8039</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-class-pattern</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8042">#8042</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-combinator-allowed-list</code> reported ranges
(<a
href="https://redirect.github.com/stylelint/stylelint/pull/8046">#8046</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-combinator-disallowed-list</code> reported
ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8047">#8047</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-disallowed-list</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8067">#8067</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-id-pattern</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8045">#8045</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-max-attribute</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8052">#8052</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-max-class</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8053">#8053</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-max-combinators</code> reported-ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8055">#8055</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-max-compound-selectors</code> reported ranges
(<a
href="https://redirect.github.com/stylelint/stylelint/pull/8056">#8056</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-max-id</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8054">#8054</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-max-pseudo-class</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8057">#8057</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-max-specificity</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8058">#8058</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-max-universal</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8059">#8059</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-nested-pattern</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8072">#8072</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-no-vendor-prefix</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8073">#8073</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-not-notation</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8074">#8074</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-pseudo-class-allowed-list</code> reported
ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8061">#8061</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-pseudo-class-disallowed-list</code> reported
ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8062">#8062</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-pseudo-class-no-unknown</code> reported ranges
(<a
href="https://redirect.github.com/stylelint/stylelint/pull/8063">#8063</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-pseudo-element-allowed-list</code> reported
ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8068">#8068</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-pseudo-element-colon-notation</code> reported
ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8069">#8069</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-pseudo-element-disallowed-list</code> reported
ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8070">#8070</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-pseudo-element-no-unknown</code> false
positives for <code>::scroll-marker</code> and
<code>::scroll-marker-group</code> (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8110">#8110</a>)
(<a
href="https://github.com/Mouvedia"><code>@​Mouvedia</code></a>).</li>
<li>Fixed: <code>selector-pseudo-element-no-unknown</code> reported
ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8071">#8071</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
<li>Fixed: <code>selector-type-no-unknown</code> reported ranges (<a
href="https://redirect.github.com/stylelint/stylelint/pull/8076">#8076</a>)
(<a
href="https://github.com/ryo-manba"><code>@​ryo-manba</code></a>).</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="4385d8fcbf"><code>4385d8f</code></a>
16.11.0</li>
<li><a
href="d24438b924"><code>d24438b</code></a>
Prepare 16.11.0 (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8049">#8049</a>)</li>
<li><a
href="cce8a86596"><code>cce8a86</code></a>
Fix <code>font-family-no-missing-generic-family-keyword</code> false
positives for `font...</li>
<li><a
href="49f32a5089"><code>49f32a5</code></a>
Bump typescript from 5.6.3 to 5.7.2 in the typescript group (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8141">#8141</a>)</li>
<li><a
href="25cf2b306d"><code>25cf2b3</code></a>
Bump rollup from 4.27.2 to 4.27.4 (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8142">#8142</a>)</li>
<li><a
href="4a82b50a1d"><code>4a82b50</code></a>
Fix <code>media-feature-name-value-no-unknown</code> false positives for
`display-mode: ...</li>
<li><a
href="e1460bdbbd"><code>e1460bd</code></a>
Bump <code>@​changesets/cli</code> from 2.27.9 to 2.27.10 in the
changesets group (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8140">#8140</a>)</li>
<li><a
href="aefbb7afb4"><code>aefbb7a</code></a>
Bump rollup from 4.25.0 to 4.27.2 (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8130">#8130</a>)</li>
<li><a
href="3de7212316"><code>3de7212</code></a>
Enable tokenless upload for Codecov (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8131">#8131</a>)</li>
<li><a
href="bda98abd99"><code>bda98ab</code></a>
Bump eslint from 9.14.0 to 9.15.0 in the eslint group (<a
href="https://redirect.github.com/stylelint/stylelint/issues/8128">#8128</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/stylelint/stylelint/compare/16.10.0...16.11.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=stylelint&package-manager=npm_and_yarn&previous-version=16.10.0&new-version=16.11.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-01 11:59:23 +01:00
Bugsounet - Cédric
bd1324cc42 Remove @eslint/js dependency. Already installed with eslint in deep (#3636)
I lint my modules and just see this:

`@eslint/js` is now not needed.
it's installed by `eslint` it self
2024-11-17 13:15:51 +01:00
Kristjan ESPERANTO
15baffdede Adapt to "Keep a Changelog" (#3634)
- Adapt heading and description to "Keep a Changelog" guideline v1.1.0
- Add missing links at the end - with this, users can click on the
version number to see the diffs (I think this was intended from the
beginning)
- Fix two bare URLs

## The link fix
Before (the link on the version number doesn't work):
![Screenshot from 2024-11-14
01-15-07](https://github.com/user-attachments/assets/e0ff4eee-abc8-4ba8-9fb7-f18fd3279ddf)

After (the link on the version number works):
![Screenshot from 2024-11-14
01-15-52](https://github.com/user-attachments/assets/7b2997e7-cf6d-4e23-b4fc-50536174f4c6)
2024-11-14 19:05:41 +01:00
sam detweiler
bd620e0061 Enhance compliments remote file with refresh support (#3630)
add support to refresh the compliments remotefile
add testcases for both without refresh (testcase missing) and with
refresh

doc to be updated
2024-11-13 09:57:55 +01:00
Kristjan ESPERANTO
f1522da153 Fix eslint ignores (#3633)
This will fix #3632.
2024-11-12 21:05:31 +01:00
sam detweiler
56cb536df1 add support for test mode detection in modulename.js via index.html (#3631)
in some cases the modulename.js may need to detect running in test mode
(compliments pr #3630)

window.name is not set  web mode

add a new field to the index.html 
window.intest 
and use the server_function to replace the hard coded string like we do
for window.mmversion=#VERSION#
then change the two  test helpers to set the env variable
app.js detects and sets global.intest=true
server func replace with value of global.intest

then module can use   if(window.intest)
2024-11-12 15:58:36 +01:00
Bugsounet - Cédric
4259d7c075 updatenotification: some fixes (#3628)
continue from #3626 

Is it ok for you ?
2024-11-09 09:59:12 +01:00
Bugsounet - Cédric
cd6f10c843 PM2 Fix (again): add pm2_env.unique_id checking and cleaning (#3626)
#3605 : new purpose code with `pm2_env.unique_id` checking
2024-11-07 11:38:46 +01:00
dependabot[bot]
b250cfa0ee Bump croner from 8.1.2 to 9.0.0 in /vendor (#3614)
Bumps [croner](https://github.com/hexagon/croner) from 8.1.2 to 9.0.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/hexagon/croner/releases">croner's
releases</a>.</em></p>
<blockquote>
<h2>9.0.0</h2>
<h2>Croner 9.0.0</h2>
<p>This major release brings significant changes to Croner, improving
consistency, fixing bugs, and modernizing the codebase.</p>
<h3>Changes</h3>
<ul>
<li>
<p><strong>Bug Fixes:</strong></p>
<ul>
<li>Fixed an issue where &quot;every X seconds&quot; crons would fail
with a &quot;maximum call stack exceeded&quot; error (<a
href="https://redirect.github.com/hexagon/croner/issues/260">#260</a>).</li>
<li>Fixed an issue where types were not supported when using ES module
via <a href="https://jsr.io">jsr.io</a> (<a
href="https://redirect.github.com/hexagon/croner/issues/258">#258</a>).</li>
</ul>
</li>
<li>
<p><strong>API Changes:</strong></p>
<ul>
<li>The <code>new</code> keyword is now mandatory when instantiating
Croner (e.g., <code>new Cron(/* ... */)</code>).</li>
<li>The default export has been removed. You now need to use
<code>import { Cron } from 'croner';</code> or <code>const { Cron } =
require('croner');</code>.</li>
</ul>
</li>
<li>
<p><strong>File Structure Changes</strong> <em>(relevant for direct file
access)</em>:</p>
<ul>
<li>All files in the <code>/dist</code> directory are now minified.
<code>croner.min.js</code> has been renamed to
<code>croner.js</code>.</li>
<li>Typings have been moved from <code>/types</code> to
<code>/dist</code>.</li>
<li>Only the <code>/src</code> directory is exposed in the jsr module <a
href="https://jsr.io/@hexagon/croner">jsr.io/<code>@​hexagon/croner</code></a>.</li>
</ul>
</li>
<li>
<p><strong>Codebase Modernization:</strong></p>
<ul>
<li>The entire codebase has been migrated from JavaScript with JSDoc to
TypeScript.</li>
<li>Deno is now used for formatting, type checking, and linting,
resulting in a cleaner and more maintainable repository. Esbuild is used
to build the <a href="https://www.npmjs.com/package/croner">npm
module</a> and typings.</li>
</ul>
</li>
</ul>
<p><strong>Upgrade Notice:</strong></p>
<p>Due to the API and file structure changes, upgrading from 8.x to 9.x
may require modifications to your existing code. Please review the above
changes carefully before migrating.</p>
<h2>9.0.0-dev.12</h2>
<ul>
<li>Test new release workflow</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="244a439e6e"><code>244a439</code></a>
Merge pull request <a
href="https://redirect.github.com/hexagon/croner/issues/263">#263</a>
from Hexagon/dev</li>
<li><a
href="7e280b5b8a"><code>7e280b5</code></a>
Bump version to 9.0.0 stable</li>
<li><a
href="c99144fe95"><code>c99144f</code></a>
Remove CodeQl. Rename dev release workflow.</li>
<li><a
href="4847b7d097"><code>4847b7d</code></a>
Merge pull request <a
href="https://redirect.github.com/hexagon/croner/issues/262">#262</a>
from Hexagon/dev</li>
<li><a
href="7bfefc49ed"><code>7bfefc4</code></a>
Fix workflow name</li>
<li><a
href="020cf92959"><code>020cf92</code></a>
Bump version.</li>
<li><a
href="40dabf4fa5"><code>40dabf4</code></a>
Fix npm release ci. Improve tsdoc. Refactor build script.</li>
<li><a
href="c45e868a92"><code>c45e868</code></a>
Increase timeout</li>
<li><a
href="df7974a13b"><code>df7974a</code></a>
Re-enable more async tests</li>
<li><a
href="8304e287cf"><code>8304e28</code></a>
Re-add async tests</li>
<li>Additional commits viewable in <a
href="https://github.com/hexagon/croner/compare/8.1.2...9.0.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=croner&package-manager=npm_and_yarn&previous-version=8.1.2&new-version=9.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-04 17:50:09 +01:00
sam detweiler
7e6349c093 Fix compliments croner (#3625)
croner changed the filename we need to use in the latest version
fix the alias table in vendor/vendor.js

fixes #3624
2024-11-04 17:41:48 +01:00
Kristjan ESPERANTO
6ce3622c61 Add spelling check to GitHub workflow (#3623)
Besides updating cspell and handling spelling issues, the important
change is adding the spelling check to the GitHub workflow.

I'm not sure if it will bother us too much when people create PRs. But I
wanted to give it a try. Or do you have any other ideas on how we can
run the spelling check on a regular basis?
2024-11-03 21:49:00 +01:00
Veeck
0aae771799 Update dependencies reported by Dependabot (#3621)
... maybe we should group those dependabot PRs someday (see
https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#groups)

---------

Co-authored-by: veeck <gitkraken@veeck.de>
2024-11-02 15:58:20 +01:00
Karsten Hassel
9114aefecc fix missing basePath (#3620)
fixes #3613 

wanted to write a test for `basePath` but have no idea at the moment to
simulate this without a reverse proxy.

Here my test setup for documentation:
```yaml
networks:
  proxy:
    driver: bridge

services:
  socket-proxy:
    privileged: true
    image: tecnativa/docker-socket-proxy:edge
    container_name: socket-proxy
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
    environment:
      CONTAINERS: 1
    ports:
      - "127.0.0.1:2375:2375"
    networks:
      - proxy

  traefik:
    image: traefik:latest
    container_name: traefik
    restart: unless-stopped
    user: 1000:1000
    command:
      - "--providers.docker=true"
      - "--providers.docker.network=traefik_proxy"
      - "--providers.docker.endpoint=tcp://socket-proxy:2375"
      - "--entryPoints.http.address=:80"
      - "--global.sendAnonymousUsage=false"
      - "--log.level=INFO"
      - "--api=true"
      - "--api.dashboard=true"
#      - "--accessLog=true"
#      - "--accesslog.fields.defaultmode=keep"
#      - "--accesslog.fields.headers.defaultmode=keep"
    networks:
      - proxy
    ports:
      - "80:80"

  magicmirror:
    image: karsten13/magicmirror:develop
    container_name: mm
    restart: unless-stopped
    entrypoint:
      - sleep
      - infinity
    networks:
      - proxy
    labels:
      - "traefik.http.services.karsten13.loadbalancer.server.port=8080"
      - "traefik.http.routers.k13-http.service=karsten13"
      - "traefik.http.routers.k13-http.entrypoints=http"
      - "traefik.http.routers.k13-http.rule=Host(`localhost`) && PathPrefix(`/testbasepath`)"
      - "traefik.http.middlewares.k13-stripprefix.stripprefix.prefixes=/testbasepath"
      - "traefik.http.routers.k13-http.middlewares=k13-stripprefix"
```
2024-11-02 08:22:27 +01:00
Bugsounet - Cédric
399e2ae1da [updatenotification] Fix pm2 using detection when pm2 script is inside or outside MagicMirror root folder (#3605)
This will fix #3576 

@FrankBlackMG: 

I don't use `*env.unique_id` because some others modules can use pm2 too
for starting a service and unique_id is the same (this will make
confusion)
So I check `name` and `pm_id` for found it
2024-10-28 10:32:39 +01:00
sam detweiler
c96326b760 Cleanup testcases that had hard coded Date() values which override the testcase runner (#3601)
cleanup testcases with hard coded Date settings after #3597
2024-10-25 20:52:00 +02:00
Karsten Hassel
cfa5c0d127 fix electron tests mocking dates (#3599)
fixes #3597 

Changes:
- electron tests: add mocking to `electron.js` for mocking the server
side, before only the browser side was mocked
- publish "/tests/configs" and "/tests/mocks" always in `server.js`,
this reverts a change done with latest release, we need this for
debugging (otherwise you get on the screen that your config has errors
but config check is successful ...)
- revert hotfix in
`tests/configs/modules/calendar/show-duplicates-in-calendar.js`
- fix `tests/configs/modules/calendar/custom.js` to allow events in the
past (~~I don't know how this could work before~~ when testing css
classes `yesterday` and `dayBeforeYesterday` --> it worked before
because the server side did not mock and therefore was not in the past)
2024-10-25 11:34:35 +02:00
sam detweiler
6946b49977 Fixtestcase calendar testcase failure (#3596)
fix calendar testcase failing after date change (exposes helper failure)
2024-10-23 23:46:32 +02:00
Kristjan ESPERANTO
aa7e856170 Add wayland and windows start options (#3594)
This PR adds start options for Wayland and Windows.

This would solve issue #3582.

**To Do if this PR is merged:**

- [ ] Adjust [Windows
section](https://docs.magicmirror.builders/getting-started/installation.html#windows)
in documentation
- [ ] Add Wayland section to the documentation
2024-10-23 21:42:29 +02:00
Veeck
b54fc08da7 Add npm publishing step to release process (#3595)
so that the npm version also stays in sync and
https://github.com/MagicMirrorOrg/MagicMirror/issues/2876 can be closed
for good
2024-10-23 20:47:01 +02:00
Kristjan ESPERANTO
0f024cff4e Run and test with node 23 (#3588) 2024-10-19 12:11:20 +02:00
Veeck
fff31068ab Re-add eslint-plugin-import (#3586)
eslint-plugin-import was missing since the switch to
[v9](https://github.com/MagicMirrorOrg/MagicMirror/pull/3558). They
finally
[support](https://github.com/import-js/eslint-plugin-import/pull/2996)
it so we can re-add it.
2024-10-13 15:22:02 +02:00
Karsten Hassel
3d1e8ab849 add address and ipWhitelist to all test configs (#3585)
All test configs have been updated to allow full external access,
allowing for easier debugging (especially when running as a container)
2024-10-12 07:53:58 +02:00
Bugsounet - Cédric
1b80e87563 [core] test electron v32 and electron rebuild (#3584)
test deps: nan v2.22.0 and electron v32
2024-10-11 11:57:34 +02:00
HeikoGr
7489e51a67 Change default for weatherEndpoint according to API 3.0 (#3583)
since API 3.0 is default, weatherEndpoint should be set to "/onecall"
Fixes #3574

ATTENTION: since lat / lon defaults to 0 / 0, the weather plugins works
after this patch, but shows the weather from
https://de.wikipedia.org/wiki/Null_Island if lat / lon is not manually
set.

---------

Co-authored-by: Karsten Hassel <hassel@gmx.de>
Co-authored-by: Pedro Lamas <pedrolamas@gmail.com>
2024-10-11 08:51:00 +02:00
Karsten Hassel
0130dc45ab stale workflow: increase operations-per-run (default=30) so that all … (#3581)
…issues can be processed
2024-10-05 22:41:41 +02:00
Karsten Hassel
c7dcf542cf allow manually running stale workflow (#3580) 2024-10-05 19:47:34 +02:00
Bugsounet - Cédric
961bae637c [core] add try / catch on mode_helper loading (#3578)
When a library is missing on an 3rd party module, MM² stop loading and
display a black screen. (I'm sure it's happened to everyone.)

So, I have added a try/catch block and it's avoid black screen, display
errors and allow continue loading with next module
2024-10-05 15:23:36 +02:00
Karsten Hassel
f51fbe39c4 reactivated stale.yaml as github action (#3577)
The old `stale.yaml` seems not to work anymore, so I set up the same
content in a new github workflow.

I think we should use it again to get rid of old issues.
2024-10-04 21:47:07 +02:00
dependabot[bot]
f91340ceca Bump helmet from 7.1.0 to 8.0.0 (#3570)
Bumps [helmet](https://github.com/helmetjs/helmet) from 7.1.0 to 8.0.0.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/helmetjs/helmet/blob/main/CHANGELOG.md">helmet's
changelog</a>.</em></p>
<blockquote>
<h2>8.0.0</h2>
<h3>Changed</h3>
<ul>
<li><strong>Breaking:</strong> <code>Strict-Transport-Security</code>
now has a max-age of 365 days, up from 180</li>
<li><strong>Breaking:</strong> <code>Content-Security-Policy</code>
middleware now throws an error if a directive should have quotes but
does not, such as <code>self</code> instead of <code>'self'</code>. See
<a
href="https://redirect.github.com/helmetjs/helmet/issues/454">#454</a></li>
<li><strong>Breaking:</strong> <code>Content-Security-Policy</code>'s
<code>getDefaultDirectives</code> now returns a deep copy. This only
affects users who were mutating the result</li>
<li><strong>Breaking:</strong> <code>Strict-Transport-Security</code>
now throws an error when &quot;includeSubDomains&quot; option is
misspelled. This was previously a warning</li>
</ul>
<h3>Removed</h3>
<ul>
<li><strong>Breaking:</strong> Drop support for Node 16 and 17. Node 18+
is now required</li>
</ul>
<h2>7.2.0 - 2024-09-28</h2>
<h3>Changed</h3>
<ul>
<li><code>Content-Security-Policy</code> middleware now warns if a
directive should have quotes but does not, such as <code>self</code>
instead of <code>'self'</code>. This will be an error in future
versions. See <a
href="https://redirect.github.com/helmetjs/helmet/issues/454">#454</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="9a8e6d5322"><code>9a8e6d5</code></a>
8.0.0</li>
<li><a
href="6562cd7074"><code>6562cd7</code></a>
CSP: speed up <code>getDefaultDirectives</code></li>
<li><a
href="a8befb3b9d"><code>a8befb3</code></a>
<code>getDefaultDirectives</code> should do a deep copy</li>
<li><a
href="558ef2ce90"><code>558ef2c</code></a>
HSTS: throw when misspelling &quot;includeSubDomains&quot; option</li>
<li><a
href="73e75952fe"><code>73e7595</code></a>
Content-Security-Policy: throw if directive value lacks necessary
quotes</li>
<li><a
href="76410e1093"><code>76410e1</code></a>
Content-Security-Policy can now use Object.hasOwn</li>
<li><a
href="293bd18bf5"><code>293bd18</code></a>
Strict-Transport-Security: increase max-age to 1 year</li>
<li><a
href="898cdc4c61"><code>898cdc4</code></a>
Require Node 18+</li>
<li><a
href="7e2b06947f"><code>7e2b069</code></a>
7.2.0</li>
<li><a
href="7bea9158d4"><code>7bea915</code></a>
Update changelog for 7.2.0 release</li>
<li>Additional commits viewable in <a
href="https://github.com/helmetjs/helmet/compare/v7.1.0...v8.0.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=helmet&package-manager=npm_and_yarn&previous-version=7.1.0&new-version=8.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-02 18:42:05 +02:00
dependabot[bot]
0eafa19096 Bump eslint-plugin-jsdoc from 50.3.0 to 50.3.1 (#3571)
Bumps
[eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) from
50.3.0 to 50.3.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/gajus/eslint-plugin-jsdoc/releases">eslint-plugin-jsdoc's
releases</a>.</em></p>
<blockquote>
<h2>v50.3.1</h2>
<h2><a
href="https://github.com/gajus/eslint-plugin-jsdoc/compare/v50.3.0...v50.3.1">50.3.1</a>
(2024-10-01)</h2>
<h3>Bug Fixes</h3>
<ul>
<li><strong><code>check-alignment</code>:</strong> handle zero indent;
fixes <a
href="https://redirect.github.com/gajus/eslint-plugin-jsdoc/issues/1322">#1322</a>
(<a
href="34866bc988">34866bc</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="34866bc988"><code>34866bc</code></a>
fix(<code>check-alignment</code>): handle zero indent; fixes <a
href="https://redirect.github.com/gajus/eslint-plugin-jsdoc/issues/1322">#1322</a></li>
<li>See full diff in <a
href="https://github.com/gajus/eslint-plugin-jsdoc/compare/v50.3.0...v50.3.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=eslint-plugin-jsdoc&package-manager=npm_and_yarn&previous-version=50.3.0&new-version=50.3.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-02 18:41:36 +02:00
Bugsounet - Cédric
ee98a0c7e5 [UpdateNotification] Fix pm2 using detection when pm2 script is in MagicMirror root folder (#3576)
I discover this bug:

When pm2 `sh` script is on MagicMirror root folder, updatenotification
is not able to detect pm2 using

```
0|MagicMirror  | [2024-10-02 17:23:09.215] [DEBUG]   Version Compare: 2.30.0-develop 2.30.0-develop --> true 
0|MagicMirror  | [2024-10-02 17:23:09.216] [DEBUG]   Status: online 
0|MagicMirror  | [2024-10-02 17:23:09.216] [DEBUG]   PM2 MagicMirror starting  from Path: /home/bugsounet/MagicMirror-dev 
0|MagicMirror  | [2024-10-02 17:23:09.216] [DEBUG]   MagicMirror Path /home/bugsounet/MagicMirror-dev/
0|MagicMirror  | [2024-10-02 17:23:09.216] [DEBUG]   Compare: false
0|MagicMirror  | [2024-10-02 17:23:09.216] [INFO]  updatenotification: [PM2] You are not using pm2 
```
2024-10-02 18:33:46 +02:00
Bugsounet - Cédric
4c7c859ae6 [Electron rebuild] Removed node-pty and drivelist from rebuilded test (#3575)
Related to #3573 

I think it's better to keep new library node-libgpiod for testing
(library to manage RPI gpio for pir sensor management) and delete others
Only one test is better
2024-10-02 18:31:57 +02:00
Karsten Hassel
d1be92a426 Prepare v2.30.0-develop 2024-10-01 00:09:29 +02:00
Karsten Hassel
15a934641d Merge remote-tracking branch 'origin/master' into develop 2024-10-01 00:06:36 +02:00
Karsten Hassel
94c3c699e8 Release 2.29.0 (#3568)
## [2.29.0] - 2024-10-01

Thanks to: @bugsounet, @dkallen78, @jargordon, @khassel,
@KristjanESPERANTO, @MarcLandis, @rejas, @ryan-d-williams, @sdetweil,
@skpanagiotis.

> ⚠️ This release needs nodejs version `v20` or `v22`, minimum version
is `v20.9.0`

### Added

- [compliments] Added support for cron type date/time format entries mm
hh DD MM dow (minutes/hours/days/months and day of week) see
https://crontab.cronhub.io for construction (#3481)
- [core] Check config at every start of MagicMirror² (#3450)
- [core] Add spelling check (cspell): `npm run test:spelling` and handle
spelling issues (#3544)
- [core] removed `config.paths.vendor` (could not work because `vendor`
is hardcoded in `index.html`), renamed `config.paths.modules` to
`config.foreignModulesDir`, added variable `MM_CUSTOMCSS_FILE` which -
if set - overrides `config.customCss`, added variable `MM_MODULES_DIR`
which - if set - overrides `config.foreignModulesDir`, added test for
`MM_MODULES_DIR` (#3530)
- [core] elements are now removed from `index.html` when loading script
or stylesheet files fails
- [core] Added `MODULE_DOM_UPDATED` notification each time the DOM is
re-rendered via `updateDom` (#3534)
- [tests] added minimal needed node version to tests (currently v20.9.0)
to avoid releases with wrong node version info
- [tests] Added `node-libgpiod` library to electron-rebuild tests
(#3563)

### Removed

- [core] removed installer only files (#3492)
- [core] removed raspberry object from systeminformation (#3505)
- [linter] removed `eslint-plugin-import`, because it doesn't support
ESLint v9. We will reenter it later when it does.
- [tests] removed `onoff` library from electron-rebuild tests (#3563)

### Updated

- [weather] Updated `apiVersion` default from 2.5 to 3.0 (#3424)
- [core] Updated dependencies including stylistic-eslint
- [core] nail down `node-ical` version to `0.18.0` with exception
`allow-ghsas: GHSA-8hc4-vh64-cxmj` in `dep-review.yaml` (which should
removed after next `node-ical` update)
- [core] Updated SocketIO catch all to new API
- [core] Allow custom modules positions by scanning index.html for the
defined regions, instead of hard coded (PR #3518 fixes issue #3504)
- [core] Detail optimizations in `config_check.js`
- [core] Updated minimal needed node version in `package.json`
(currently v20.9.0) (#3559) and except for v21 (no security updates)
(#3561)
- [linter] Switch to ESLint v9 and flat config and replace
`eslint-plugin-unicorn` by `@eslint/js`
- [core] fix discovering module positions twice after #3450

### Fixed

- Fixed `checks` badge in README.md
- [weather] Fixed issue with the UK Met Office provider following a
change in their API paths and header info.
- [core] add check for node_helper loading for multiple instances of
same module (#3502)
- [weather] Fixed issue for respecting unit config on broadcasted
notifications
- [tests] Fixes calendar test by moving it from e2e to electron with
fixed date (#3532)
- [calendar] fixed sliceMultiDayEvents getting wrong count and
displaying incorrect entries, Europe/Berlin (#3542)
- [tests] ignore `js/positions.js` when linting (this file is created at
runtime)
- [calendar] fixed sliceMultiDayEvents showing previous day without
config enabled

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Michael Teeuw <michael@xonaymedia.nl>
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ross Younger <crazyscot@gmail.com>
Co-authored-by: Veeck <github@veeck.de>
Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr>
Co-authored-by: jkriegshauser <joshuakr@nvidia.com>
Co-authored-by: illimarkangur <116028111+illimarkangur@users.noreply.github.com>
Co-authored-by: sam detweiler <sdetweil@gmail.com>
Co-authored-by: vppencilsharpener <tim.pray@gmail.com>
Co-authored-by: veeck <michael.veeck@nebenan.de>
Co-authored-by: Paranoid93 <6515818+Paranoid93@users.noreply.github.com>
Co-authored-by: Brian O'Connor <btoconnor@users.noreply.github.com>
Co-authored-by: WallysWellies <59727507+WallysWellies@users.noreply.github.com>
Co-authored-by: Jason Stieber <jrstieber@gmail.com>
Co-authored-by: jargordon <50050429+jargordon@users.noreply.github.com>
Co-authored-by: Daniel <32464403+dkallen78@users.noreply.github.com>
Co-authored-by: Ryan Williams <65094007+ryan-d-williams@users.noreply.github.com>
Co-authored-by: Panagiotis Skias <panagiotis.skias@gmail.com>
Co-authored-by: Marc Landis <dirk.rettschlag@gmail.com>
2024-10-01 00:02:17 +02:00
Karsten Hassel
d84d612df5 Release 2.29.0 2024-09-30 23:49:05 +02:00
Karsten Hassel
719eca49fe update dependencies, nail down node-ical version to 0.18.0 (#3566)
- node-ical use `0.18.0` instead of `^0.18.0` in `package.json`
- cleanup `package-lock.json`
2024-09-28 15:33:53 -05:00
sam detweiler
d9eefff066 fix double load of positions now that check:config at startup is active (#3565)
after adding check:config to the MM startup process, #3450, we
accidentally discover module positions more than once, and write the
file each time..

add a check to see if we have done this work already
2024-09-28 15:52:09 +02:00
Bugsounet - Cédric
731512c2e5 Electron rebuild tests update (#3563)
# Update electron-rebuild.yaml
* remove onoff library: Not updated since 3 years, don't work with last
rpi Os
 * add node-libgpiod library in replacement
2024-09-26 19:09:39 +02:00
Bugsounet - Cédric
ebaeed935f Engine except on node v21 (#3561)
in addition of #3559 

except with node v21: no security updates and EOL
2024-09-26 19:09:10 +02:00
Marc Landis
2e6e86887b fix calendar showing previous day when using sliceMultiDayEvents (#3555)
This bug is caused by #3543.

The calculation for midnight adds a day but for endDate we want the day
to be subtracted again.
2024-09-25 21:16:43 +02:00
Kristjan ESPERANTO
d3187689f0 Switch to ESLint v9 and flat config (#3558)
Since PR #3551 was not yet complete, I made my own attempt.

1. Update to ESLint v9.
2. Replace deprecated `.eslintrc.json` and `.eslintignore` by flat
config `eslint.config.mjs`.
3. Adapt `check_config.js` to use flat config.
4. Since `eslint-plugin-import` still doesn't support ESLint v9 I
removed it. We can add it back when it does support v9.
5. Run tests `npm run check:js` and `npm run config:check`.
6. In order not to overload this PR, I have not yet activated more
additional rules - there are some useful ones in the new plugin
`@eslint/js`.

@bugsounet, please don't take it as an offence that I have created a
competing PR. The migration to ESLint v9 has been burning under my nails
for some time.
2024-09-25 21:05:11 +02:00
Bugsounet - Cédric
5ffdf9af09 Updated minimal needed node version in package.json (currently v20.9.0) (#3559)
Update of package*.json for minimal node verion requirement (v20.9.0)

 * it's an addition to #3556
* According to changelog v2.28.0: `⚠️ This release needs nodejs version
>= v20.9.0`
2024-09-25 09:03:09 +02:00
Karsten Hassel
08116b8e64 fixes for running tests for MM_MODULES_DIR (#3550)
and ignore `js/positions.js` when linting (because this file is
generated at runtime).
2024-09-24 22:38:00 +02:00
Karsten Hassel
fa6a7521b4 add tests for minimal node version (currently v20.9.0) (#3556)
Beside testing against node version `v20.x` and `v22.x` we should also
test against the minimal node version, currently `v20.9.0`.

This is for seeing changes in dependencies which needs higher node
version as with the July-24-release, where we wrote `node >=20` but
shipped an `eslint` version which required `node>=20.9.0`.
2024-09-24 22:09:28 +02:00
Veeck
06a8b517aa Cleanup github actions (#3549)
- should now correct itself when one changes from (accidentaly selected)
master to develop
- also fixes wrong CHANGELOG entry from
https://github.com/MagicMirrorOrg/MagicMirror/pull/3481
- update deps a little
2024-09-19 12:25:41 +02:00
Ryan Williams
1823f5a130 Updated to new notification name DOM_OBJECTS_UPDATED -> MODULE_DOM_UPDATED (#3548)
This is an update to #3535. See #3534 for discussion and context. Fixes
#3534 (again).
2024-09-19 07:29:43 +02:00
Karsten Hassel
8f5aa50d79 added test for MM_MODULES_DIR (#3546)
uses newsfeed test after copying this module to config dir

addition for #3530
2024-09-19 07:29:04 +02:00
Karsten Hassel
65d7e2d067 fix CHANGELOG.md 2024-09-18 21:53:18 +02:00
Kristjan ESPERANTO
06f6fbf49b Review config_check.js (#3545)
Only details changes. No functional changes.

- remove superfluous colors in Log.error
- invert negative if
- update ESLint env
- use camel case variable name
- optimize Log strings
2024-09-18 21:39:02 +02:00
Ryan Williams
c6e05c9fec Added DOM_OBJECTS_UPDATED notification when the DOM is re-rendered via updateDom (#3535)
- [x] Base your pull requests against the `develop` branch.
- [x] Include these infos in the description:
> - Does the pull request solve a **related** issue?
Yes - solves #3534

> - If so, can you reference the issue like this `Fixes
#<issue_number>`?
Fixes #3534 (also mentioned in commit message)

> - What does the pull request accomplish? Use a list if needed.

> > - Adds a new notification (`DOM_OBJECTS_UPDATED`) when the DOM is
updated via `updateDom`

- [x] Please run `npm run lint:prettier` before submitting
- [x] Don't forget to add an entry about your changes to the
CHANGELOG.md file.

More info can be found in #3534, but as a summary:

The `updateDom` function is not synchronous - there is an undetermined
amount of time between when it completes and when the DOM has actually
been re-rendered and is ready for interaction. The existing notification
(`MODULE_DOM_CREATED`) only fires once on the initial DOM render. This
PR solves the issue of subsequent re-renders by adding a new
notification that fires whenever the DOM is ready after an update. This
notification falls within expected lifecycle notifications (very similar
to other libraries that provide DOM lifecycle notifications).
2024-09-18 19:40:46 +02:00
Kristjan ESPERANTO
866419eb95 Check config before starting MM (#3450)
I think it might be a good idea to check the config at every start.
2024-09-18 19:37:25 +02:00
Karsten Hassel
659e0c74cb add new env vars MM_MODULES_DIR and MM_CUSTOMCSS_FILE … (#3530)
… for setting these things from outside (and overriding corresponding
config.js properties `config.foreignModulesDir` and `customCss`)

- remove elements from index.html when loading script or stylesheet
files fails
- removed `config.paths.vendor` (could never work because `vendor` is
hardcoded in `index.html`) and renamed `config.paths.modules` to
`config.foreignModulesDir`. The `config.paths. ...` properties were
implemented in the initial commit in `js/defaults.js` but were never
functional.
- fixes `app.js` which didn't respect `config.paths.modules` before
- as `modules/defaults` is directly set in many places in the source
code restrict `config.paths.modules` to foreign modules (it has never
worked for default modules), now renamed to `config.foreignModulesDir`
- adds new `/env` section in `server.js` for getting the new env vars in
the browser
- fixes TODO in `server.js` so test directories are now only published
when running tests

These changes allow changing some main paths from outside mm with the
new env vars. You now **can** put all user stuff into one directory,
e.g. the `config` dir:
- `config.js` as before
- `custom.css`
- foreign modules

This would simplify other setups e.g. the docker setup. At the moment we
have to deal with 3 directories where 2 of them (`modules` and `css`)
contains mixed stuff, which means mm owned files and user files. This
can now simplified and leads to cleaner setups (if wanted).
2024-09-18 19:10:46 +02:00
Kristjan ESPERANTO
d9f9f41e98 Add spell check (#3544)
I felt like adding a spell checker, but it's okay if you find it
superfluous. At least then we could fix the found spell issues.

What is still missing is an automatic integration so that the spell
checker does not have to be called manually. Would it perhaps make sense
to always do it before a release?
2024-09-18 07:37:09 +02:00
sam detweiler
ea3a323581 add fix for sliceMultiDayEvents (#3543)
sliceMultiDayEvents occasionally gets the number of events wrong and
produces too many rows

Math.ceil() rounds up over 1.04 so we get an abnormal count

then the calcs for the midnight loop control used different moment()
functions, producing different results

fixes #3542
2024-09-17 08:01:49 +02:00
Karsten Hassel
0faefd109a fixes calendar test by moving it from e2e to electron with fixed date (#3540)
and refactor tests/electron/modules/calendar_spec.js

fixes #3532
2024-09-15 08:36:11 +02:00
Karsten Hassel
81351fb4cc update dependencies (#3536) 2024-09-14 22:05:20 +02:00
Karsten Hassel
3380314c11 hotfix for calendar_spec.js (used data now returns 20 events) (#3533)
fixes #3532
2024-09-13 16:52:34 -05:00
Kristjan ESPERANTO
bca5d9c845 Ignore positions.js (#3531)
This file is generated when MM is started. As I understand it, it should
not be included in the repository.

Should probably have been part of #3518.
2024-09-11 23:12:34 +02:00
Karsten Hassel
7915de3149 update dependencies (#3527)
We cannot upgrade to electron v32 because electron-rebuild is failing
with epoll, so staying at v31.
2024-08-31 07:14:30 +02:00
sam detweiler
2b97e0d26e add support for custom regions, by detecting what is used in index.html (#3518)
read index.html to discover the regions used, make them the list checked
by app.js and check:config test

fixes #3504   supercedes #3506 

no config.js param required
2024-08-27 22:52:59 +02:00
Panagiotis Skias
56736786fd Bug in Weather Units for Broadcasted Notification (#3519)
This PR resolve Issue number #3419 .

I have added the method `convertWeatherObjectToImperial()` which
converts the units of the `notificationPayload` to imperial if needed,
in order to pass the object in `sendNotification()`.

---------

Co-authored-by: veeck <michael.veeck@nebenan.de>
2024-08-18 10:04:51 +02:00
Ryan Williams
cc1d4ab240 Improve duplicate module filtering. Update SocketIO catch-all API. (#3523)
- [x] Base your pull requests against the `develop` branch.
- [x] Include these infos in the description:
> - Does the pull request solve a **related** issue?
Yes - solves #3521

> - If so, can you reference the issue like this `Fixes
#<issue_number>`?
Fixes #3521 (also mentioned in commit message)

> - What does the pull request accomplish? Use a list if needed.

> > - Updates duplicate module filter method (upstream vs downstream -
see #3502)
> > - Updates socket io catchall functionality to new API
[[docs](https://socket.io/docs/v4/listening-to-events/)].

- [x] Please run `npm run lint:prettier` before submitting
- [x] Don't forget to add an entry about your changes to the
CHANGELOG.md file.
2024-08-18 09:25:01 +02:00
Veeck
976c8ae00a Bump stylistic-eslint (#3520)
updates plugin and adjust docs and config for smooth cleaning :-D

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-12 22:52:43 +02:00
sam detweiler
780e4e2e06 Fix loading of multiple instances of node_helper when multiple instances of a module are in config.js (#3517)
adds a check for already loaded/loading for node helper of a each
module, only does once

fixes #3502
2024-08-04 21:28:20 +02:00
Karsten Hassel
76d8f98969 allow custom module positions by setting allowCustomModulePositions… (#3506)
… in `config.js`

fixes #3504, related to
https://github.com/MagicMirrorOrg/MagicMirror/pull/3445
2024-08-01 21:24:16 +02:00
Veeck
4182c2129f Update dependencies (#3515)
its the start of the month so dependabot is waking up :-)
2024-08-01 19:00:36 +02:00
Karsten Hassel
d22d0e1f87 remove raspberry object from systeminformation (#3507)
fixes #3505
2024-07-29 12:22:59 +02:00
sam detweiler
d9665b35df Update compliments with support for cron type date/time for selections, addition to just date. (#3481)
> - What does the pull request accomplish? Use a list if needed.

this change allows uses to configure date/time events for compliments..
also linked site that will build the cron entry..

and example was Happy hour in a pub, on fri/sat between 5 and 7 pm. 

or just after midnight on Halloween (Boooooo!)

I also added testcases for #3478 

(and added support for this in MMM-Config), with a custom, drop down
selection list of the types.. )

|  if this is approved I will update the module doc
2024-07-15 19:51:05 +02:00
Daniel
974a1da9f0 [weather] update provider openweathermap to new apiVersion (#3496)
Co-authored-by: Karsten Hassel <hassel@gmx.de>
2024-07-11 13:37:44 +02:00
jargordon
4d14f4a2c1 Fixes the UK Met Office Datahub provider (#3499)
Fixes #3384

Changed the UKMetOfficeDataHub provider to the new API structure as per
the documentation.

API Base URL updated.
Header information amended to the correct key name.
API Secret no longer required so removed.

Changelog updated to reflect the change.
2024-07-07 16:36:59 -05:00
Karsten Hassel
3b22622054 fixes checks badge in README.md (#3494)
old url: 

![grafik](https://github.com/MagicMirrorOrg/MagicMirror/assets/25914086/025597f2-c1f1-4879-a76c-5a20c7b7099e)


new url:

![grafik](https://github.com/MagicMirrorOrg/MagicMirror/assets/25914086/f3b8850e-3fe4-4cb0-aa07-7525eb8f82eb)
2024-07-04 22:47:21 +02:00
sam detweiler
160d95ac34 Cleanup folders for #3492 (#3493)
remove installer only files. into installer

addresses #3492
2024-07-02 00:09:50 +02:00
Karsten Hassel
f7369a7e85 Prepare v2.29.0-develop 2024-06-30 23:53:28 +02:00
Karsten Hassel
7389a33f80 Merge remote-tracking branch 'origin/master' into develop 2024-06-30 23:50:35 +02:00
Karsten Hassel
53fc814ff8 Release 2.28.0 (#3490)
## [2.28.0] - 2024-07-01

Thanks to: @btoconnor, @bugsounet, @JasonStieber, @khassel,
@kleinmantara and @WallysWellies.

> ⚠️ This release needs nodejs version >= v20

### Added

- [calendar] Added config option "showEndsOnlyWithDuration" for default
calendar
- [compliments] Added `specialDayUnique` config option, defaults to
`false` (#3465)
- [weather] Provider weathergov: Use `precipitationLast3Hours` if
`precipitationLastHour` is `null` (#3124)

### Removed

- [tests] delete node v18 support (#3462)

### Updated

- [core] Update dependencies including electron to v31
- [core] use node >= v20 (#3462)
- [core] Update `config.js.sample` to use openmeteo as weather provider
which needs no api key
- [tests] Use latest@version of node for `automated-tests.yaml` (#3483)
- [updatenotification] Avoid using pm2 when running in docker container

### Fixed

- [core] Fixed crash possibility if `module: <name>` is not defined and
on `postion: <positon>` mistake (#3445)
- [weather] Fixed precipitationProbability in forecast for provider
openmeteo (#3446)
- [weather] Fixed type=daily for provider openmeteo having no data when
running after 23:00 (#3449)
- [weather] Fixed type=daily for provider openmeteo showing nightly
icons in forecast when current time is "nightly" (#3458)
- [weather] Fixed forecast and hourly weather for provider openmeteo to
use real temperatures, not apparent temperatures (#3466)
- [tests] Fixed e2e tests running in docker container which needs
`address: "0.0.0.0"` (#3479)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Michael Teeuw <michael@xonaymedia.nl>
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ross Younger <crazyscot@gmail.com>
Co-authored-by: Veeck <github@veeck.de>
Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr>
Co-authored-by: jkriegshauser <joshuakr@nvidia.com>
Co-authored-by: illimarkangur <116028111+illimarkangur@users.noreply.github.com>
Co-authored-by: sam detweiler <sdetweil@gmail.com>
Co-authored-by: vppencilsharpener <tim.pray@gmail.com>
Co-authored-by: veeck <michael.veeck@nebenan.de>
Co-authored-by: Paranoid93 <6515818+Paranoid93@users.noreply.github.com>
Co-authored-by: Brian O'Connor <btoconnor@users.noreply.github.com>
Co-authored-by: WallysWellies <59727507+WallysWellies@users.noreply.github.com>
Co-authored-by: Jason Stieber <jrstieber@gmail.com>
2024-06-30 23:44:21 +02:00
Karsten Hassel
795e5c76c1 Release 2.28.0 2024-06-30 23:25:27 +02:00
Karsten Hassel
92ac3895a7 updatenotification: avoid using pm2 when running in docker container (#3484)
related to #3480 

Change module updatenotification so that it can work without `pm2` in a
docker container.

It now tests if file `/.dockerenv` exists and if so `require("pm2")` is
never called.
2024-06-28 22:33:21 +02:00
Jason Stieber
c89c3edf97 Fix weathergov api precipitationLastHour (#3125)
Pull request fixes small big in weathergov api format mismatch #3124

---------

Co-authored-by: Karsten Hassel <hassel@gmx.de>
2024-06-28 22:21:38 +02:00
Karsten Hassel
74c6bb30b0 Update dependencies (#3487)
and minor fixes in changelog.
2024-06-28 22:09:44 +02:00
Bugsounet - Cédric
cfc0bc617f Update CHANGELOG.md (#3486)
Adjust my own ChangeLog entry
2024-06-27 21:37:22 +02:00
Karsten Hassel
4aafa32875 fixes e2e tests running in docker container (#3485)
which needs `address: "0.0.0.0"`

fixes #3479
2024-06-27 10:38:29 +02:00
Bugsounet - Cédric
f28b4bd709 Use latest@version of node for automated-tests.yaml (#3483)
Maybe it's a good idea to use latest@node version for automated-tests

Actually it's an "random" version

Note: it's already used [there in
electronRebuild](https://github.com/MagicMirrorOrg/MagicMirror/blob/develop/.github/workflows/electronRebuild.yaml#L19)
2024-06-26 21:43:41 +02:00
WallysWellies
aefb3a0b6d Update compliments module (#3471)
`Fixes #3465`

Add config option `specialDayUnique` that defaults to `false` and causes
special day compliments to be added to the existing compliments array.
Setting this option to `true` will only show the compliments that have
been configured for that day.

---------

Co-authored-by: Veeck <github@veeck.de>
Co-authored-by: veeck <michael.veeck@nebenan.de>
Co-authored-by: Karsten Hassel <hassel@gmx.de>
2024-06-24 22:40:59 +02:00
Brian O'Connor
3d9d72e64e Open-Meteo: Fix forecast and hourly weather to use real temperatures, not apparent temperatures (#3468)
As discussed in #3466, the Open-Meteo provider is using the apparent
temperature ("Feels like") in the forecast and hourly weather reporting.
This is contrary to expected behavior.

Note: I'm a little unclear on how I should be editing the `CHANGELOG.md`
file with this PR - happy to update this PR with a little guidance. This
is my first attempted PR in this project.

Let me know if there are any questions.

---------

Co-authored-by: veeck <michael.veeck@nebenan.de>
2024-06-24 22:18:49 +02:00
Karsten Hassel
8d20832bc5 [calendar] add config option "showEndsOnlyWithDuration" (#3477)
redo and rebase changes made in PR
https://github.com/MagicMirrorOrg/MagicMirror/pull/2968 by
https://github.com/kleinmantara
2024-06-24 21:52:19 +02:00
Bugsounet - Cédric
e95c144c3e Fix crash possibility if module: <name> is not defined and on mistake position: <position> (#3445)
Fix #3442
2024-06-24 21:51:54 +02:00
Karsten Hassel
4c748a4d32 update config.js.sample to use openmeteo as weather provider (#3476)
which needs no api key.

I think this is a better choice than the old one because new users which
use this config as starting point will now see weather data instead of
`loading...`
2024-06-22 21:23:58 +02:00
Karsten Hassel
9cbd30f296 update dependencies incl. electron v31 (#3473) 2024-06-19 22:21:46 +02:00
Bugsounet - Cédric
bc27c46723 MM² Main core use node >= v20 // delete node v18 from test suite (#3463)
#3462
2024-06-19 22:11:04 +02:00
Karsten Hassel
63324454a9 update dependencies (#3460)
see
https://github.com/MagicMirrorOrg/MagicMirror/pull/3457#issuecomment-2159316713
2024-06-11 06:54:17 +02:00
Karsten Hassel
4bd66cb121 fixed type=daily for provider openmeteo showing nightly icons (#3459)
in forecast when current time is "nightly"

Fixes #3458
2024-06-08 11:48:31 +02:00
Karsten Hassel
cd0bc5b160 fixed type=daily for provider openmeteo having no data … (#3451)
… when running after 23:00

Fixes #3449
2024-05-20 09:36:03 +02:00
Karsten Hassel
d1c17e7fc0 weather module: Fixed precipitationProbability in forecast … (#3448)
…for provider openmeteo, fixed #3446
2024-05-13 22:36:35 +02:00
Karsten Hassel
3b0035760d Update deps (#3439)
- update dependencies including electron to v30
- replace node v21 with v22 in tests
2024-05-01 19:54:38 +02:00
dependabot[bot]
1fa17883bc Bump ansis from 2.3.0 to 3.0.1 (#3417)
Bumps [ansis](https://github.com/webdiscus/ansis) from 2.3.0 to 3.0.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/webdiscus/ansis/releases">ansis's
releases</a>.</em></p>
<blockquote>
<h2>v3.0.0</h2>
<h1>Features</h1>
<ul>
<li>Added detection of color spaces support: TrueColor, 256 colors, 16
colors, no color (black &amp; white).</li>
<li>Added fallback for supported color space: truecolor —&gt; 256 colors
—&gt; 16 colors —&gt; no colors.</li>
<li>Improved  performance for the <code>hex()</code> function.</li>
</ul>
<h1>BREAKING CHANGE</h1>
<p>In the new major version <code>3.x</code> are removed unused styles
and methods.</p>
<blockquote>
<p>⚠️ Warning</p>
<p>Before update, please check your code whether is used deleted styles
and methods.</p>
</blockquote>
<h3>Support Node.js</h3>
<p>Drop supports for Node &lt;= <code>14</code>. Minimal supported
version is <code>15.0.0</code> (Released 2020-10-20).
In the theory the <code>v3</code> can works with Node<code>12</code>,
but we can't test it.</p>
<h3>Deleted styles</h3>
<p>The <code>not widely supported</code> styles are deleted:</p>
<ul>
<li><code>faint</code> (alias for dim), replace in your code with
<code>dim</code></li>
<li><code>doubleUnderline</code>, replace in your code with
<code>underline</code></li>
<li><code>frame</code>, replace in your code with
<code>underline</code></li>
<li><code>encircle</code>, replace in your code with
<code>underline</code></li>
<li><code>overline</code>, replace in your code with
<code>underline</code></li>
</ul>
<h3>Deleted methods</h3>
<p>The methods are deleted:</p>
<ul>
<li><code>ansi</code>, replace in your code with <code>ansi256</code> or
<code>fg</code></li>
<li><code>bgAnsi</code>, replace in your code with
<code>bgAnsi256</code> or <code>bg</code></li>
</ul>
<h3>Deleted clamp in functions</h3>
<p>The clamp (0, 255) for the ANSI 256 codes and RGB values is removed,
because is unused.
You should self check the function arguments.</p>
<p>The affected functions:</p>
<ul>
<li><code>ansi256</code> and <code>fg</code> (alias to ansi256) -
expected a code in the range <code>0 - 255</code></li>
<li><code>bgAnsi256</code> and <code>bg</code> (alias to bgAnsi256) -
expected a code in the range<code>0 - 255</code></li>
<li><code>rgb</code> - expected r, g, b values in the range <code>0 -
255</code></li>
<li><code>bgRgb</code> - expected r, g, b values in the range <code>0 -
255</code></li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/webdiscus/ansis/blob/master/CHANGELOG.md">ansis's
changelog</a>.</em></p>
<blockquote>
<h2>3.0.1 (2024-04-01)</h2>
<ul>
<li>refactor: improve code</li>
<li>chore: reduce code bundle size from 3.8 KB to 3.4 KB</li>
<li>chore: update benchmark</li>
<li>chore: update compare tests</li>
<li>test: add more tests</li>
<li>docs: improve readme</li>
</ul>
<h2>3.0.0 (2024-03-29)</h2>
<ul>
<li>feat: add detection of color spaces support: TrueColor, 256 colors,
16 colors, no color</li>
<li>feat: add fallback for supported color space: truecolor —&gt; 256
colors —&gt; 16 colors —&gt; no colors</li>
<li>perform: improve performance for <code>hex()</code> function</li>
<li>chore: size increased from 3.2 KB to 3.8 KB as new features were
added</li>
<li>test: switch from jest to vitest</li>
<li>test: add tests for new features</li>
<li>docs: update readme for color spaces support</li>
</ul>
<h3>BREAKING CHANGE</h3>
<p>In the new major version <code>3.x</code> are removed unused styles
and methods.</p>
<blockquote>
<p>⚠️ Warning</p>
<p>Before update, please check your code whether is used deleted styles
and methods.</p>
</blockquote>
<h3>Support Node.js</h3>
<p>Drop supports for Node &lt;= <code>14</code>. Minimal supported
version is <code>15.0.0</code> (Released 2020-10-20).
In the theory the <code>v3</code> can works with Node<code>12</code>,
but we can't test it.</p>
<h3>Deleted styles</h3>
<p>The <code>not widely supported</code> styles are deleted:</p>
<ul>
<li><code>faint</code> (alias for dim), replace in your code with
<code>dim</code></li>
<li><code>doubleUnderline</code>, replace in your code with
<code>underline</code></li>
<li><code>frame</code>, replace in your code with
<code>underline</code></li>
<li><code>encircle</code>, replace in your code with
<code>underline</code></li>
<li><code>overline</code>, replace in your code with
<code>underline</code></li>
</ul>
<h3>Deleted methods</h3>
<p>The methods are deleted:</p>
<ul>
<li><code>ansi</code>, replace in your code with <code>ansi256</code> or
<code>fg</code></li>
<li><code>bgAnsi</code>, replace in your code with
<code>bgAnsi256</code> or <code>bg</code></li>
</ul>
<h3>Deleted clamp in functions</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/webdiscus/ansis/commits">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=ansis&package-manager=npm_and_yarn&previous-version=2.3.0&new-version=3.0.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-01 22:11:52 +02:00
veeck
8aaad8e7ec Prepare v2.28.0-develop 2024-04-01 22:05:54 +02:00
veeck
1981601f0a Merge branch 'mm_master' into mm_develop 2024-04-01 22:03:49 +02:00
Veeck
5ea8a3469a Release 2.27.0 (#3410)
## [2.27.0] - 2024-04-01

Thanks to: @bugsounet, @crazyscot, @illimarkangur, @jkriegshauser,
@khassel, @KristjanESPERANTO, @Paranoid93, @rejas, @sdetweil and
@vppencilsharpener.

This release marks the first release without Michael Teeuw (@michmich).
A very special thanks to him for creating MagicMirror and leading the
project for so many years.

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

- Output of system information to the console for troubleshooting (#3328
and #3337), ignore errors under aarch64 (#3349)
- [chore] Add `eslint-plugin-package-json` to lint the `package.json`
files (#3368)
- [weather] `showHumidity` config is now a string describing where to
show this element. Supported values: "wind", "temp", "feelslike",
"below", "none". (#3330)
- electron-rebuild test suite for electron and 3rd party modules
compatibility (#3392)
- Create MM² icon and attach it to electron process (#3407)

### Updated

- Update updatenotification (update_helper.js): Recode with pm2 library
(#3332)
- Removing lodash dependency by replacing merge by spread operator
(#3339)
- Use node prefix for build-in modules (#3340)
- Rework logging colors (#3350)
- Update pm2 to v5.3.1 with no allow-ghsas (#3364)
- [chore] Update husky and let lint-staged fix ESLint issues
- [chore] Update dependencies including electron to v29 (#3357) and
node-ical
- Update translations for estonian (#3371)
- Update electron to v29 and update other dependencies
- [calendar] fullDay events over several days now show the left days
from the first day on and 'today' on the last day
- Update layout of current weather indoor values

### Fixed

- Correct apibase of weathergov weatherprovider to match documentation
(#2926)
- Worked around several issues in the RRULE library that were causing
deleted calender events to still show, some
initial and recurring events to not show, and some event times to be off
an hour. (#3291)
- Skip changelog requirement when running tests for dependency updates
(#3320)
- Display precipitation probability when it is 0% instead of blank/empty
(#3345)
- [newsfeed] Suppress unsightly animation cases when there are 0 or 1
active news items (#3336)
- [newsfeed] Always compute the feed item URL using the same helper
function (#3336)
- Ignore all custom css files (#3359)
- [newsfeed] Fix newsfeed stall issue introduced by #3336 (#3361)
- Changed `log.debug` to `log.log` in `app.js` where logLevel is not set
because config is not loaded at this time (#3353)
- [calendar] deny fetch interval < 60000 and set 60000 in this case
(prevent fetch loop failed) (#3382)
- added message in case where config.js is missing the module.export
line PR #3383
- Fixed an issue where recurring events could extend past their
recurrence end date (#3393)
- Don't display any `npm WARN <....>` on install (#3399)
- Fixed move suncalc dependency to production from dev, as it is used by
clock module
- [compliments] Fix mirror not responding anymore when no compliments
are to be shown (#3385)

### Deleted

- Unneeded file headers (#3358)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Michael Teeuw <michael@xonaymedia.nl>
Co-authored-by: Kristjan ESPERANTO <35647502+KristjanESPERANTO@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Karsten Hassel <hassel@gmx.de>
Co-authored-by: Ross Younger <crazyscot@gmail.com>
Co-authored-by: Bugsounet - Cédric <github@bugsounet.fr>
Co-authored-by: jkriegshauser <joshuakr@nvidia.com>
Co-authored-by: illimarkangur <116028111+illimarkangur@users.noreply.github.com>
Co-authored-by: sam detweiler <sdetweil@gmail.com>
Co-authored-by: vppencilsharpener <tim.pray@gmail.com>
Co-authored-by: Paranoid93 <6515818+Paranoid93@users.noreply.github.com>
2024-04-01 22:03:20 +02:00
Veeck
2a883c393c Remove codecov yaml (#3416)
CodeCov isnt used at the moment and MAYBE this blocks our release
2024-04-01 20:08:31 +02:00
Veeck
53420f5be9 Fix check for mastermerge label (#3415)
Mastermerge label wasnt checked correctly, this PR should hopefully
fixes it for good

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-01 18:16:20 +02:00
veeck
b262bf6144 Release 2.27.0 2024-04-01 12:01:44 +02:00
Karsten Hassel
72ef8235b1 update Collaboration.md (added infos from discord) (#3408) 2024-03-30 23:29:57 +01:00
Paranoid93
e004b33fab Change multiday fullDay Event behaviour (#3396)
Hey!

This PR should change the behaviour of starting fullDay events that last
several days. The goal was to change the behavior of the "Starting
today, ends T" (T=Tomorrow) event, so it should show how many days it
will occur from the first day on

Before situation:

a fullDay event that started 'today' and ends several days later showed
Today on the first day. The rest of the days it showed X days left.


![grafik](https://github.com/MagicMirrorOrg/MagicMirror/assets/6515818/da4e06cf-3122-44d9-b78a-88f9970c57d4)

Y => Yesterday
T => Tomorrow


Target situation with this commit:
a fullDay event that started 'today' shows 'X days left' from the first
day on and 'Today' on the last day.


![grafik](https://github.com/MagicMirrorOrg/MagicMirror/assets/6515818/c42b9a27-35cf-47b7-9a8f-937a6009f904)

---------

Co-authored-by: Veeck <github@veeck.de>
2024-03-28 22:02:22 +01:00
Bugsounet - Cédric
d9926fad79 MM² Icon (#3407)
* Create `MM²` icon
 * Allow to change default electron icon to this icon
2024-03-28 12:37:18 +01:00
Karsten Hassel
fd44445ec3 update deps and package.json's (eslint) (#3406) 2024-03-27 23:13:01 +01:00
Bugsounet - Cédric
be63e365bd Add electron-rebuild to suite test (#3392)
because actually i'm not able to rebuild any libraries to works with
electron v29.x
I write a suite test to check `electron-rebuild`

Note: works with
[v28.x](https://github.com/MagicMirrorOrg/MagicMirror/actions/runs/8122468177/job/22201931385)
2024-03-27 22:45:01 +01:00
Veeck
57549fa19c Fix compliments module bringing mirror to a halt (#3402)
... when no compliments are to be displayed. We shouldnt even try to
randomize when the array has no elements...

Fixes #3385
2024-03-23 12:16:57 +01:00
Paranoid93
52cfbacd4d Changes the layout of the current weather module, targetting indoor values (#3397)
Hi,

this PR should change the layout of the indoor values in the
current_weather module.

Since the Indoor values are being passed into the module via a
notification, I sadly do not know exactly how to write a test for this.
Can you link me an example or tell me, how I can mock indoor values into
this test?

Before:

![grafik](https://github.com/MagicMirrorOrg/MagicMirror/assets/6515818/b1b2afcc-0a35-48c3-9cf8-3e7b041c7727)

After:

![grafik](https://github.com/MagicMirrorOrg/MagicMirror/assets/6515818/311d3051-45e9-450d-afd5-c90a4d4ffd63)
2024-03-23 10:53:42 +01:00
sam detweiler
6de578edb3 move suncalc dependency out of dev, as it is used by the clock module (#3401)
user reported problem with clock module, checking code found dependency
on suncalc library, but it is not loaded in production mode.. move
dependency

---------

Co-authored-by: veeck <michael.veeck@nebenan.de>
2024-03-22 19:49:40 +01:00
vppencilsharpener
d970214a0e Fix for #3345 - precipitation probability not displayed when it is 0% (#3346)
Fixes issue #3345. 

I think I submitted this correctly, but don't do this often so let me
know if anything needs to be corrected.

---------

Co-authored-by: Veeck <github@veeck.de>
2024-03-21 14:11:23 +01:00
Bugsounet - Cédric
c5f90501ef [calendar] deny fetch interval < 60000 and set 60000 in this case (prevent fetch loop failed) (#3382)
Hi, I had the case of some users who set a very small fetchinterval (10
sec for example)
in some cases, it may be that the request did not have time to complete
correctly and that the next one has already been sent (generally on
start of MM²)
I think that lock min fetchInterval to 60000 is a good idea
2024-03-21 13:43:04 +01:00
Bugsounet - Cédric
16af809559 Update .npmrc (#3399)
Don't display `npm WARN <....>`  on install

Only Error will be displayed
2024-03-16 13:06:27 +01:00
jkriegshauser
1a745cfb92 Fix issue 3393 (#3395)
Fix for #3393
2024-03-13 20:59:21 +01:00
dependabot[bot]
90ff3402cb Bump node-ical from 0.17.2 to 0.18.0 (#3387)
Bumps [node-ical](https://github.com/jens-maus/node-ical) from 0.17.2 to
0.18.0.
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a
href="https://github.com/jens-maus/node-ical/commits/0.18.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=node-ical&package-manager=npm_and_yarn&previous-version=0.17.2&new-version=0.18.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-01 20:05:37 +01:00
dependabot[bot]
e5678f0291 Bump playwright from 1.41.2 to 1.42.0 (#3388)
Bumps [playwright](https://github.com/microsoft/playwright) from 1.41.2
to 1.42.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/microsoft/playwright/releases">playwright's
releases</a>.</em></p>
<blockquote>
<h2>v1.42.0</h2>
<h2>New APIs</h2>
<ul>
<li>
<p><strong>Test tags</strong></p>
<p><a href="https://playwright.dev/docs/test-annotations#tag-tests">New
tag syntax</a> for adding tags to the tests (@-tokens in the test title
are still supported).</p>
<pre lang="js"><code>test('test customer login', { tag: ['@fast',
'@login'] }, async ({ page }) =&gt; {
  // ...
});
</code></pre>
<p>Use <code>--grep</code> command line option to run only tests with
certain tags.</p>
<pre lang="sh"><code>npx playwright test --grep @fast
</code></pre>
</li>
<li>
<p><strong>Annotating skipped tests</strong></p>
<p><a
href="https://playwright.dev/docs/test-annotations#annotate-tests">New
annotation syntax</a> for test annotations allows annotating the tests
that do not run.</p>
<pre lang="js"><code>test('test full report', {
  annotation: [
{ type: 'issue', description:
'https://github.com/microsoft/playwright/issues/23180' },
{ type: 'docs', description:
'https://playwright.dev/docs/test-annotations#tag-tests' },
  ],
}, async ({ page }) =&gt; {
  // ...
});
</code></pre>
</li>
<li>
<p><strong>page.addLocatorHandler()</strong></p>
<p>New method <a
href="https://playwright.dev/docs/api/class-page#page-add-locator-handler">page.addLocatorHandler()</a>
registers a callback that will be invoked when specified element becomes
visible and may block Playwright actions. The callback can get rid of
the overlay. Here is an example that closes a cookie dialog when it
appears.</p>
<pre lang="js"><code>// Setup the handler.
await page.addLocatorHandler(
page.getByRole('heading', { name: 'Hej! You are in control of your
cookies.' }),
    async () =&gt; {
      await page.getByRole('button', { name: 'Accept all' }).click();
    });
// Write the test as usual.
await page.goto('https://www.ikea.com/');
await page.getByRole('link', { name: 'Collection of blue and white'
}).click();
await expect(page.getByRole('heading', { name: 'Light and easy'
})).toBeVisible();
</code></pre>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="e7f0635c17"><code>e7f0635</code></a>
cherry-pick(<a
href="https://redirect.github.com/microsoft/playwright/issues/29692">#29692</a>):
docs: better addLocatorHandler example in release notes ...</li>
<li><a
href="8709a3a24b"><code>8709a3a</code></a>
cherry-pick(<a
href="https://redirect.github.com/microsoft/playwright/issues/29687">#29687</a>):
chore: fix docs roll for functions without args follow-u...</li>
<li><a
href="aa9f6fb718"><code>aa9f6fb</code></a>
cherry-pick(<a
href="https://redirect.github.com/microsoft/playwright/issues/29669">#29669</a>):
chore: strengthen linting (<a
href="https://redirect.github.com/microsoft/playwright/issues/29674">#29674</a>)</li>
<li><a
href="f5899c1556"><code>f5899c1</code></a>
chore: set version to 1.42.0 (<a
href="https://redirect.github.com/microsoft/playwright/issues/29671">#29671</a>)</li>
<li><a
href="77e1b02552"><code>77e1b02</code></a>
docs: 1.42 release notes (<a
href="https://redirect.github.com/microsoft/playwright/issues/29666">#29666</a>)</li>
<li><a
href="c1421bc9f2"><code>c1421bc</code></a>
docs: typescript compiler invocation before tests (<a
href="https://redirect.github.com/microsoft/playwright/issues/29667">#29667</a>)</li>
<li><a
href="bd8d044433"><code>bd8d044</code></a>
feat(uimode) uses relative paths to establish websocket connection (<a
href="https://redirect.github.com/microsoft/playwright/issues/29617">#29617</a>)</li>
<li><a
href="56028269bb"><code>5602826</code></a>
devops: add a hint how to create a repro (<a
href="https://redirect.github.com/microsoft/playwright/issues/29665">#29665</a>)</li>
<li><a
href="015a1bcc1c"><code>015a1bc</code></a>
feat(ct): double unmounting component throws error (<a
href="https://redirect.github.com/microsoft/playwright/issues/29650">#29650</a>)</li>
<li><a
href="303d7fdac9"><code>303d7fd</code></a>
chore(ct): vue resolve internal type errors (<a
href="https://redirect.github.com/microsoft/playwright/issues/29649">#29649</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/microsoft/playwright/compare/v1.41.2...v1.42.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=playwright&package-manager=npm_and_yarn&previous-version=1.41.2&new-version=1.42.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-01 20:05:23 +01:00
dependabot[bot]
c7d94a069e Bump express from 4.18.2 to 4.18.3 (#3389)
Bumps [express](https://github.com/expressjs/express) from 4.18.2 to
4.18.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/expressjs/express/releases">express's
releases</a>.</em></p>
<blockquote>
<h2>4.18.3</h2>
<h2>Main Changes</h2>
<ul>
<li>Fix routing requests without method</li>
<li>deps: body-parser@1.20.2
<ul>
<li>Fix strict json error message on Node.js 19+</li>
<li>deps: content-type@~1.0.5</li>
<li>deps: raw-body@2.5.2</li>
</ul>
</li>
</ul>
<h2>Other Changes</h2>
<ul>
<li>Use https: protocol instead of deprecated git: protocol by <a
href="https://github.com/vcsjones"><code>@​vcsjones</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5032">expressjs/express#5032</a></li>
<li>build: Node.js@16.18 and Node.js@18.12 by <a
href="https://github.com/abenhamdine"><code>@​abenhamdine</code></a> in
<a
href="https://redirect.github.com/expressjs/express/pull/5034">expressjs/express#5034</a></li>
<li>ci: update actions/checkout to v3 by <a
href="https://github.com/armujahid"><code>@​armujahid</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5027">expressjs/express#5027</a></li>
<li>test: remove unused function arguments in params by <a
href="https://github.com/raksbisht"><code>@​raksbisht</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5124">expressjs/express#5124</a></li>
<li>Remove unused originalIndex from acceptParams by <a
href="https://github.com/raksbisht"><code>@​raksbisht</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5119">expressjs/express#5119</a></li>
<li>Fixed typos by <a
href="https://github.com/raksbisht"><code>@​raksbisht</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5117">expressjs/express#5117</a></li>
<li>examples: remove unused params by <a
href="https://github.com/raksbisht"><code>@​raksbisht</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5113">expressjs/express#5113</a></li>
<li>fix: parameter str is not described in JSDoc by <a
href="https://github.com/raksbisht"><code>@​raksbisht</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5130">expressjs/express#5130</a></li>
<li>fix: typos in History.md by <a
href="https://github.com/raksbisht"><code>@​raksbisht</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5131">expressjs/express#5131</a></li>
<li>build : add Node.js@19.7 by <a
href="https://github.com/abenhamdine"><code>@​abenhamdine</code></a> in
<a
href="https://redirect.github.com/expressjs/express/pull/5028">expressjs/express#5028</a></li>
<li>test: remove unused function arguments in params by <a
href="https://github.com/raksbisht"><code>@​raksbisht</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5137">expressjs/express#5137</a></li>
<li>use random port in test so it won't fail on already listening by <a
href="https://github.com/rluvaton"><code>@​rluvaton</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5162">expressjs/express#5162</a></li>
<li>tests: use cb() instead of done() by <a
href="https://github.com/kristof-low"><code>@​kristof-low</code></a> in
<a
href="https://redirect.github.com/expressjs/express/pull/5233">expressjs/express#5233</a></li>
<li>examples: remove multipart example by <a
href="https://github.com/riddlew"><code>@​riddlew</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5195">expressjs/express#5195</a></li>
<li>Update support Node.js@18 in the CI by <a
href="https://github.com/UlisesGascon"><code>@​UlisesGascon</code></a>
in <a
href="https://redirect.github.com/expressjs/express/pull/5490">expressjs/express#5490</a></li>
<li>Fix favicon-related bug in cookie-sessions example by <a
href="https://github.com/DmytroKondrashov"><code>@​DmytroKondrashov</code></a>
in <a
href="https://redirect.github.com/expressjs/express/pull/5414">expressjs/express#5414</a></li>
<li>Release 4.18.3 by <a
href="https://github.com/UlisesGascon"><code>@​UlisesGascon</code></a>
in <a
href="https://redirect.github.com/expressjs/express/pull/5505">expressjs/express#5505</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/vcsjones"><code>@​vcsjones</code></a>
made their first contribution in <a
href="https://redirect.github.com/expressjs/express/pull/5032">expressjs/express#5032</a></li>
<li><a
href="https://github.com/abenhamdine"><code>@​abenhamdine</code></a>
made their first contribution in <a
href="https://redirect.github.com/expressjs/express/pull/5034">expressjs/express#5034</a></li>
<li><a href="https://github.com/armujahid"><code>@​armujahid</code></a>
made their first contribution in <a
href="https://redirect.github.com/expressjs/express/pull/5027">expressjs/express#5027</a></li>
<li><a href="https://github.com/raksbisht"><code>@​raksbisht</code></a>
made their first contribution in <a
href="https://redirect.github.com/expressjs/express/pull/5124">expressjs/express#5124</a></li>
<li><a href="https://github.com/rluvaton"><code>@​rluvaton</code></a>
made their first contribution in <a
href="https://redirect.github.com/expressjs/express/pull/5162">expressjs/express#5162</a></li>
<li><a
href="https://github.com/kristof-low"><code>@​kristof-low</code></a>
made their first contribution in <a
href="https://redirect.github.com/expressjs/express/pull/5233">expressjs/express#5233</a></li>
<li><a href="https://github.com/riddlew"><code>@​riddlew</code></a> made
their first contribution in <a
href="https://redirect.github.com/expressjs/express/pull/5195">expressjs/express#5195</a></li>
<li><a
href="https://github.com/DmytroKondrashov"><code>@​DmytroKondrashov</code></a>
made their first contribution in <a
href="https://redirect.github.com/expressjs/express/pull/5414">expressjs/express#5414</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/expressjs/express/compare/4.18.2...4.18.3">https://github.com/expressjs/express/compare/4.18.2...4.18.3</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/expressjs/express/blob/master/History.md">express's
changelog</a>.</em></p>
<blockquote>
<h1>4.18.3 / 2024-02-26</h1>
<ul>
<li>Fix routing requests without method</li>
<li>deps: body-parser@1.20.2
<ul>
<li>Fix strict json error message on Node.js 19+</li>
<li>deps: content-type@~1.0.5</li>
<li>deps: raw-body@2.5.2</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="1b51edac7c"><code>1b51eda</code></a>
4.18.3</li>
<li><a
href="b625132864"><code>b625132</code></a>
build: pin Node 21.x to minor</li>
<li><a
href="e3eca80584"><code>e3eca80</code></a>
build: pin Node 21.x to minor</li>
<li><a
href="23b44b3ddd"><code>23b44b3</code></a>
build: support Node.js 21.6.2</li>
<li><a
href="b9fea12245"><code>b9fea12</code></a>
build: support Node.js 21.x in appveyor</li>
<li><a
href="c259c3407f"><code>c259c34</code></a>
build: support Node.js 21.x</li>
<li><a
href="fdeb1d3176"><code>fdeb1d3</code></a>
build: support Node.js 20.x in appveyor</li>
<li><a
href="734b281900"><code>734b281</code></a>
build: support Node.js 20.x</li>
<li><a
href="0e3ab6ec21"><code>0e3ab6e</code></a>
examples: improve view count in cookie-sessions</li>
<li><a
href="59af63ac2e"><code>59af63a</code></a>
build: Node.js@18.19</li>
<li>Additional commits viewable in <a
href="https://github.com/expressjs/express/compare/4.18.2...4.18.3">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~ulisesgascon">ulisesgascon</a>, a new
releaser for express since your current version.</p>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=express&package-manager=npm_and_yarn&previous-version=4.18.2&new-version=4.18.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-01 20:05:12 +01:00
dependabot[bot]
2f2d84bb5c Bump electron from 29.0.1 to 29.1.0 (#3390)
Bumps [electron](https://github.com/electron/electron) from 29.0.1 to
29.1.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/electron/electron/releases">electron's
releases</a>.</em></p>
<blockquote>
<h2>electron v29.1.0</h2>
<h1>Release Notes for v29.1.0</h1>
<h2>Features</h2>
<ul>
<li>Added proxy configuring support for requests made with net module
from utility process. <a
href="https://redirect.github.com/electron/electron/pull/41416">#41416</a>
<!-- raw HTML omitted -->(Also in <a
href="https://redirect.github.com/electron/electron/pull/41417">30</a>)<!--
raw HTML omitted --></li>
</ul>
<h2>Fixes</h2>
<ul>
<li>Ensured ScreenCaptureKit is used exclusively on macOS 14.4 and
higher to avoid permission prompts. <a
href="https://redirect.github.com/electron/electron/pull/41403">#41403</a>
<!-- raw HTML omitted -->(Also in <a
href="https://redirect.github.com/electron/electron/pull/41404">30</a>)<!--
raw HTML omitted --></li>
</ul>
<h2>Other Changes</h2>
<ul>
<li>Updated Chromium to 122.0.6261.70. <a
href="https://redirect.github.com/electron/electron/pull/41446">#41446</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="2d9c5a62c6"><code>2d9c5a6</code></a>
chore: bump chromium to 122.0.6261.70 (29-x-y) (<a
href="https://redirect.github.com/electron/electron/issues/41446">#41446</a>)</li>
<li><a
href="23f690ffd0"><code>23f690f</code></a>
chore: bump chromium to 122.0.6261.69 (29-x-y) (<a
href="https://redirect.github.com/electron/electron/issues/41425">#41425</a>)</li>
<li><a
href="8f4e94694e"><code>8f4e946</code></a>
chore: fix import from patches.py in script/lib/git.py (<a
href="https://redirect.github.com/electron/electron/issues/41437">#41437</a>)</li>
<li><a
href="af47434dc8"><code>af47434</code></a>
feat: add support for configuring system network context proxies (<a
href="https://redirect.github.com/electron/electron/issues/41416">#41416</a>)</li>
<li><a
href="8ab99e2d8e"><code>8ab99e2</code></a>
refactor: prefer using <code>base::NoDestructor</code> to
`base::{Singleton,LazyInstance...</li>
<li><a
href="ffcccdcf37"><code>ffcccdc</code></a>
perf: omit unnecessary work from
`ElectronRenderFrameObserver::ShouldNotifyCl...</li>
<li><a
href="ce2ac1c0c2"><code>ce2ac1c</code></a>
fix: use ScreenCaptureKit exclusively on macOS 14.4 and higher (<a
href="https://redirect.github.com/electron/electron/issues/41403">#41403</a>)</li>
<li><a
href="1c3feddef8"><code>1c3fedd</code></a>
docs: update breaking changes language (<a
href="https://redirect.github.com/electron/electron/issues/41398">#41398</a>)</li>
<li>See full diff in <a
href="https://github.com/electron/electron/compare/v29.0.1...v29.1.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=electron&package-manager=npm_and_yarn&previous-version=29.0.1&new-version=29.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-01 20:04:56 +01:00
dependabot[bot]
313531d623 Bump @stylistic/eslint-plugin from 1.6.2 to 1.6.3 (#3391)
Bumps
[@stylistic/eslint-plugin](https://github.com/eslint-stylistic/eslint-stylistic/tree/HEAD/packages/eslint-plugin)
from 1.6.2 to 1.6.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/eslint-stylistic/eslint-stylistic/releases"><code>@​stylistic/eslint-plugin</code>'s
releases</a>.</em></p>
<blockquote>
<h2>v1.6.3</h2>
<h3>   🐞 Bug Fixes</h3>
<ul>
<li>Type error on <code>UnprefixedRuleOptions</code>  -  by <a
href="https://github.com/JstnMcBrd"><code>@​JstnMcBrd</code></a> in <a
href="https://redirect.github.com/eslint-stylistic/eslint-stylistic/issues/284">eslint-stylistic/eslint-stylistic#284</a>
<a
href="https://github.com/eslint-stylistic/eslint-stylistic/commit/f7bc3a9"><!--
raw HTML omitted -->(f7bc3)<!-- raw HTML omitted --></a></li>
</ul>
<h5>    <a
href="https://github.com/eslint-stylistic/eslint-stylistic/compare/v1.6.2...v1.6.3">View
changes on GitHub</a></h5>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="413d1bba7d"><code>413d1bb</code></a>
chore: release v1.6.3</li>
<li><a
href="f7bc3a9817"><code>f7bc3a9</code></a>
fix: type error on <code>UnprefixedRuleOptions</code> (<a
href="https://github.com/eslint-stylistic/eslint-stylistic/tree/HEAD/packages/eslint-plugin/issues/284">#284</a>)</li>
<li>See full diff in <a
href="https://github.com/eslint-stylistic/eslint-stylistic/commits/v1.6.3/packages/eslint-plugin">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=@stylistic/eslint-plugin&package-manager=npm_and_yarn&previous-version=1.6.2&new-version=1.6.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-01 20:04:42 +01:00
Karsten Hassel
73140cdf37 update electron to v29 and other deps (#3386) 2024-02-24 13:04:43 +01:00
sam detweiler
08f8a5107a add error message if config.js appears empty after loading w require() in app.js (#3383)
from forum,
https://forum.magicmirror.builders/topic/18493/node_helper-js-is-not-working
user created own config.js, did not copy the module exports line..

this caused the js/defaults.js list of modules to be processed for
node_helpers
but the physical config.js to be loaded for the web page (hard coded in
index.html)

so user modules needing node_helper didn't have that ..

this adds a warning message in npm start output to help user resolve..
took two days to debug without message
2024-02-13 08:02:02 +01:00
dependabot[bot]
88a96fb529 Bump husky from 9.0.7 to 9.0.10 (#3379)
Bumps [husky](https://github.com/typicode/husky) from 9.0.7 to 9.0.10.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/typicode/husky/releases">husky's
releases</a>.</em></p>
<blockquote>
<h2>v9.0.10</h2>
<ul>
<li>fix: rename index.d.ts to index.d.mts by <a
href="https://github.com/mrkjdy"><code>@​mrkjdy</code></a> in <a
href="https://redirect.github.com/typicode/husky/pull/1379">typicode/husky#1379</a></li>
</ul>
<h2>v9.0.9</h2>
<ul>
<li>refactor: rename files by <a
href="https://github.com/typicode"><code>@​typicode</code></a> in <a
href="https://redirect.github.com/typicode/husky/pull/1378">typicode/husky#1378</a></li>
</ul>
<h2>v9.0.8</h2>
<ul>
<li>docs: update index.md by <a
href="https://github.com/khaledYS"><code>@​khaledYS</code></a> in <a
href="https://redirect.github.com/typicode/husky/pull/1369">typicode/husky#1369</a></li>
<li>Fix tab detection on install command by <a
href="https://github.com/glensc"><code>@​glensc</code></a> in <a
href="https://redirect.github.com/typicode/husky/pull/1376">typicode/husky#1376</a></li>
<li>refactor: reduce file size by <a
href="https://github.com/typicode"><code>@​typicode</code></a> in <a
href="https://redirect.github.com/typicode/husky/pull/1377">typicode/husky#1377</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="c042d9b4d4"><code>c042d9b</code></a>
9.0.10</li>
<li><a
href="e5293680b9"><code>e529368</code></a>
fix: rename index.d.ts to index.d.mts (<a
href="https://redirect.github.com/typicode/husky/issues/1379">#1379</a>)</li>
<li><a
href="6219cac421"><code>6219cac</code></a>
9.0.9</li>
<li><a
href="d8377feddc"><code>d8377fe</code></a>
refactor: rename files (<a
href="https://redirect.github.com/typicode/husky/issues/1378">#1378</a>)</li>
<li><a
href="211b80ada3"><code>211b80a</code></a>
9.0.8</li>
<li><a
href="a5a45fc3ce"><code>a5a45fc</code></a>
refactor: reduce file size (<a
href="https://redirect.github.com/typicode/husky/issues/1377">#1377</a>)</li>
<li><a
href="d09132834b"><code>d091328</code></a>
fix: tab detection on install command (<a
href="https://redirect.github.com/typicode/husky/issues/1376">#1376</a>)</li>
<li><a
href="798f1ad7b5"><code>798f1ad</code></a>
docs: update list</li>
<li><a
href="b98985d411"><code>b98985d</code></a>
test: expect init to exit with 0</li>
<li><a
href="3e1365614b"><code>3e13656</code></a>
docs: fix links</li>
<li>Additional commits viewable in <a
href="https://github.com/typicode/husky/compare/v9.0.7...v9.0.10">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=husky&package-manager=npm_and_yarn&previous-version=9.0.7&new-version=9.0.10)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 20:40:12 +01:00
Veeck
db65cd60eb Bundle all Dependabot updates (#3378)
and also node-ical

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-01 18:57:18 +01:00
illimarkangur
5fb5ef6cc7 Improved, fixed and added translations for estonian (#3371)
Improved wording, fixed grammatical errors and added new translations to
the et.json file.

---------

Co-authored-by: Veeck <github@veeck.de>
2024-02-01 12:16:55 +01:00
Ross Younger
57de389e01 [cosmetic] Weather module humidity positioning (#3330)
This PR adds an option to tweak the layout of the weather module. When
set, the humidity appears alongside the temperature:

![Screenshot from 2024-01-03
11-56-55](https://github.com/MagicMirrorOrg/MagicMirror/assets/551990/2a9fdf9a-21e4-49f5-8a48-68ea21902592)
2024-01-29 07:45:49 +01:00
Kristjan ESPERANTO
431bf22adb Update husky and let lint-staged fix ESLint issues (#3370)
The new version of husky makes it possible to simplify the pre-commit
hook a little.

And since prettier no longer takes care of the JavaScript files in our
project, it can no longer come into conflict with ESLint while running
lint-staged. Therefore we can activate the correction of ESLint issues
here.
2024-01-28 23:15:18 +01:00
Veeck
3bf848075d Correct apibase of weathergov weatherprovider to match documentation (#2927)
Fixes part of #2926
2024-01-27 22:31:50 +01:00
Veeck
fb5fab8145 Cleanups (#3369)
- Remove useless css class in clock
- Fix typo in calendar
- Changelog also got a little screwed after last merge
- updated dependencies
2024-01-27 21:11:57 +01:00
jkriegshauser
7f0b8e4054 Better fixes for #3291 and the underlying exdate issues (#3342)
* Worked around several issues in the RRULE library that were causing
deleted calender events to still show, some initial and recurring events
to not show, and some event times to be off an hour. (#3291)
* Renamed variables in *calendarfetcherutils.js* to be more clear about
use of `moment` and js's `Date` class.
* Added calendar config option `forceUseCurrentTime` (default:`false`)
which will ignore overridden `Date.now` in the config in order to keep
some tests consistent.
* Added several unit tests for crossing DST in different timezones with
excluded events.
2024-01-27 07:56:54 +01:00
Karsten Hassel
27f3c86c41 remove all useless header comments (#3363)
see #3358

used command: `find ./ -type f -exec perl -i -0pe
's/\/\*\s*magicmirror.*?\*\/\s*//si' {} \;`

This is a first draft, I think we should preserve some of the comments.
2024-01-24 21:39:06 +01:00
Kristjan ESPERANTO
b0161fe011 Lint package.json files (#3368)
Notable changes in this context:

- simplification of the ESLint calls - there is no longer a combination
of two file/directory lists (one in `package.json` and one in
`.eslintignore`)
- removal of a non-existent path from the `.eslintignore`
- use shorthand declaration for GitHub repository

Normally the new plugin would also sort the scripts in the package.json
alphabetically, but I think the current order is fine, so I deactivated
it.

Is it overkill to introduce a linter plugin just for the `package.json`
files?

In other projects I have seen that such internal changes were marked
with "chore" in the changelog. That's what I've done here. These chore
changes are less interesting for "normal" users.

Please feel free to give me feedback.
2024-01-24 20:43:59 +01:00
dependabot[bot]
f88b92fb1f Bump follow-redirects from 1.15.3 to 1.15.5 (#3367)
Bumps
[follow-redirects](https://github.com/follow-redirects/follow-redirects)
from 1.15.3 to 1.15.5.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="b1677ce001"><code>b1677ce</code></a>
Release version 1.15.5 of the npm package.</li>
<li><a
href="d8914f7982"><code>d8914f7</code></a>
Preserve fragment in responseUrl.</li>
<li><a
href="65858205e5"><code>6585820</code></a>
Release version 1.15.4 of the npm package.</li>
<li><a
href="7a6567e16d"><code>7a6567e</code></a>
Disallow bracketed hostnames.</li>
<li><a
href="05629af696"><code>05629af</code></a>
Prefer native URL instead of deprecated url.parse.</li>
<li><a
href="1cba8e85fa"><code>1cba8e8</code></a>
Prefer native URL instead of legacy url.resolve.</li>
<li><a
href="72bc2a4229"><code>72bc2a4</code></a>
Simplify _processResponse error handling.</li>
<li><a
href="3d42aecdca"><code>3d42aec</code></a>
Add bracket tests.</li>
<li><a
href="bcbb096b32"><code>bcbb096</code></a>
Do not directly set Error properties.</li>
<li>See full diff in <a
href="https://github.com/follow-redirects/follow-redirects/compare/v1.15.3...v1.15.5">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=follow-redirects&package-manager=npm_and_yarn&previous-version=1.15.3&new-version=1.15.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/MagicMirrorOrg/MagicMirror/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-22 20:54:29 +01:00
dependabot[bot]
339aaf4c01 Bump actions/dependency-review-action from 3 to 4 (#3366)
Bumps
[actions/dependency-review-action](https://github.com/actions/dependency-review-action)
from 3 to 4.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/dependency-review-action/releases">actions/dependency-review-action's
releases</a>.</em></p>
<blockquote>
<h2>v4.0.0</h2>
<ul>
<li>Update action to Node 20 by <a
href="https://github.com/takost"><code>@​takost</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/639">actions/dependency-review-action#639</a></li>
<li>Dependabot updates, see the full changelog for more details.</li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/takost"><code>@​takost</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/639">actions/dependency-review-action#639</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/dependency-review-action/compare/v3.1.5...v4.0.0">https://github.com/actions/dependency-review-action/compare/v3.1.5...v4.0.0</a></p>
<h2>3.1.5</h2>
<h2>What's Changed</h2>
<ul>
<li>Smaller <code>per_page</code> when requesting diff by <a
href="https://github.com/hmaurer"><code>@​hmaurer</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/649">actions/dependency-review-action#649</a></li>
<li>Update dependencies:
<ul>
<li>Bump <code>@​typescript-eslint/parser</code> from 6.10.0 to 6.13.1
by <a href="https://github.com/dependabot"><code>@​dependabot</code></a>
in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/630">actions/dependency-review-action#630</a></li>
<li>Bump prettier from 3.0.3 to 3.1.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/629">actions/dependency-review-action#629</a></li>
<li>Bump <code>@​types/jest</code> from 29.5.8 to 29.5.11 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/637">actions/dependency-review-action#637</a></li>
<li>Bump nodemon from 3.0.1 to 3.0.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/636">actions/dependency-review-action#636</a></li>
<li>Replace pip -&gt; pypi in PURL examples by <a
href="https://github.com/febuiles"><code>@​febuiles</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/638">actions/dependency-review-action#638</a></li>
<li>Bump <code>@​typescript-eslint/eslint-plugin</code> from 6.12.0 to
6.15.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/644">actions/dependency-review-action#644</a></li>
<li>Bump eslint from 8.53.0 to 8.56.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/640">actions/dependency-review-action#640</a></li>
<li>Bump <code>@​typescript-eslint/parser</code> from 6.13.1 to 6.16.0
by <a href="https://github.com/dependabot"><code>@​dependabot</code></a>
in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/645">actions/dependency-review-action#645</a></li>
<li>Bump prettier from 3.1.0 to 3.1.1 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/646">actions/dependency-review-action#646</a></li>
</ul>
</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/dependency-review-action/compare/v3.1.4...v3.1.5">https://github.com/actions/dependency-review-action/compare/v3.1.4...v3.1.5</a></p>
<h2>3.1.4</h2>
<h2>What's Changed</h2>
<ul>
<li>
<p>Fixed a <a
href="https://redirect.github.com/actions/dependency-review-action/issues/618">bug</a>
with severity filtering when using the <code>allow_ghsas</code> option:
<a
href="https://redirect.github.com/actions/dependency-review-action/pull/623">actions/dependency-review-action#623</a>.</p>
</li>
<li>
<p>Updates dependencies:</p>
<ul>
<li>Bump <code>@​types/node</code> from 16.18.61 to 16.18.62 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/619">actions/dependency-review-action#619</a>
action/pull/620</li>
<li>Bump <code>@​typescript-eslint/eslint-plugin</code> from 6.11.0 to
6.12.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/625">actions/dependency-review-action#625</a></li>
<li>Bump typescript from 5.2.2 to 5.3.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/624">actions/dependency-review-action#624</a></li>
</ul>
</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/dependency-review-action/compare/v3...v3.1.4">https://github.com/actions/dependency-review-action/compare/v3...v3.1.4</a></p>
<h2>3.1.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Fixes purl &quot;version must be percent-encoded&quot; by <a
href="https://github.com/theztefan"><code>@​theztefan</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/617">actions/dependency-review-action#617</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/dependency-review-action/compare/v3...v3.1.3">https://github.com/actions/dependency-review-action/compare/v3...v3.1.3</a></p>
<h2>3.1.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix a regression for setups using self-hosted runners behind HTTP
proxies:<a
href="https://github.com/febuiles"><code>@​febuiles</code></a> in <a
href="https://redirect.github.com/actions/dependency-review-action/pull/611">actions/dependency-review-action#611</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="4cd9eb2d23"><code>4cd9eb2</code></a>
Updating docs to point to v4.</li>
<li><a
href="4901385134"><code>4901385</code></a>
bump to 4.0.0</li>
<li><a
href="dbf82a4a5e"><code>dbf82a4</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/dependency-review-action/issues/639">#639</a>
from takost/takost/update-to-node-20</li>
<li><a
href="78aeb2a948"><code>78aeb2a</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/dependency-review-action/issues/663">#663</a>
from actions/dependabot/npm_and_yarn/typescript-eslin...</li>
<li><a
href="4e510006f5"><code>4e51000</code></a>
Bump <code>@​typescript-eslint/parser</code> from 6.18.0 to 6.18.1</li>
<li><a
href="9560737c5e"><code>9560737</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/dependency-review-action/issues/661">#661</a>
from actions/dependabot/npm_and_yarn/typescript-eslin...</li>
<li><a
href="4125f47f7e"><code>4125f47</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/dependency-review-action/issues/660">#660</a>
from actions/dependabot/npm_and_yarn/types/node-16.18.70</li>
<li><a
href="07cc93e0c8"><code>07cc93e</code></a>
Bump <code>@​typescript-eslint/eslint-plugin</code> from 6.18.0 to
6.18.1</li>
<li><a
href="e2c203b8b7"><code>e2c203b</code></a>
Bump <code>@​types/node</code> from 16.18.62 to 16.18.70</li>
<li><a
href="f0b304d0bc"><code>f0b304d</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/dependency-review-action/issues/653">#653</a>
from actions/dependabot/npm_and_yarn/got-14.0.0</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/dependency-review-action/compare/v3...v4">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/dependency-review-action&package-manager=github_actions&previous-version=3&new-version=4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-22 19:04:32 +01:00
Bugsounet - Cédric
c75b7d4a70 pm2 update ;) (#3364)
`pm2` just updated to v5.3.1 with `0 vulnerabilities`

let's delete `allow-ghsas` in depsreview and update dependencies
2024-01-20 22:55:01 +01:00
Bugsounet - Cédric
c96ced9137 updatenotification: update_helper.js recode with pm2 library (v2.27.x) (#3332)
#3285

Because there is so many conflit with package,
I have rewrite the code with v2.27.0-develop

For remember:

 * recode: `update_helper.js` with `pm2` library
 * fix: default config -> `updates` is a array
 * delete: `command-exists` library (not used)
 * delete: `PM2_GetList()`  function (not used)
 * add: check `updates.length` (prevent crash)
 * add: `[PM2]` tag in log (for better visibility)
 * add: `pm2` library
 
advantage:
  * we use the pm2 library directly
* avoids weird returns from child_process.exec when requesting a json
format from pm2
  * simplified the code

inconvenient:
  * we have vulnerabilities with axios

240120 Fix:
* use `pm2_env.pm_cwd` instead of `pm2_env.PWD` : prevent using `pm2
restart <id> --update-env` in other directory (for enable GPU rendering
for exemple)
 * resolve packages (again)
2024-01-20 17:38:22 +01:00
dependabot[bot]
995b61b689 Bump follow-redirects from 1.15.3 to 1.15.5 (#3356)
Bumps
[follow-redirects](https://github.com/follow-redirects/follow-redirects)
from 1.15.3 to 1.15.5.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="b1677ce001"><code>b1677ce</code></a>
Release version 1.15.5 of the npm package.</li>
<li><a
href="d8914f7982"><code>d8914f7</code></a>
Preserve fragment in responseUrl.</li>
<li><a
href="65858205e5"><code>6585820</code></a>
Release version 1.15.4 of the npm package.</li>
<li><a
href="7a6567e16d"><code>7a6567e</code></a>
Disallow bracketed hostnames.</li>
<li><a
href="05629af696"><code>05629af</code></a>
Prefer native URL instead of deprecated url.parse.</li>
<li><a
href="1cba8e85fa"><code>1cba8e8</code></a>
Prefer native URL instead of legacy url.resolve.</li>
<li><a
href="72bc2a4229"><code>72bc2a4</code></a>
Simplify _processResponse error handling.</li>
<li><a
href="3d42aecdca"><code>3d42aec</code></a>
Add bracket tests.</li>
<li><a
href="bcbb096b32"><code>bcbb096</code></a>
Do not directly set Error properties.</li>
<li>See full diff in <a
href="https://github.com/follow-redirects/follow-redirects/compare/v1.15.3...v1.15.5">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=follow-redirects&package-manager=npm_and_yarn&previous-version=1.15.3&new-version=1.15.5)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts
page](https://github.com/MagicMirrorOrg/MagicMirror/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-20 17:35:49 +01:00
Karsten Hassel
c09338ab80 changed log.debug to log.log in app.js (#3362)
where logLevel is not set because config is not loaded at this time, see
#3353
2024-01-18 19:18:58 +01:00
Ross Younger
b005a8f30e [newsfeed] Fix bug where the newsfeed sometimes stops (#3361)
It appears that #3336 introduced a bug where a newsfeed with >1 items
would stop updating after a while (usually after `activeItem` wraps
around the end of the list). Sorry! My bad, I hadn't tested that case
well enough.
2024-01-18 12:05:26 +01:00
Kristjan ESPERANTO
35e4dfb3fe Ignore all custom css files (#3359)
For experimenting, I sometimes work with different CSS files. I can
imagine that others do this too.

This setting for the css folder corresponds to the setting we already
have for the config folder.
2024-01-16 23:16:47 +01:00
Kristjan ESPERANTO
6dbacbb773 Rework logging colors (#3350)
- Replacing old package `colors` by drop-in replacement `ansis`
- Rework `console-stamp` config to show all Log outputs in same color
(errors = red, warnings = yellow, debug = blue background (only for the
label), info = blue)
- This also fixes `npm run config:check` (broken since
6097547c10)

Feel free to let me know if the PR is too big and you want me to do
individual PRs for the changes.

Before:

![before](https://github.com/MagicMirrorOrg/MagicMirror/assets/35647502/88e48ec3-102c-40f3-9e9b-5d14fe446a43)

After:

![after](https://github.com/MagicMirrorOrg/MagicMirror/assets/35647502/4c8c4bad-08c9-46a3-92c9-14b996c13a7d)

---------

Co-authored-by: Veeck <github@veeck.de>
2024-01-16 21:54:55 +01:00
Karsten Hassel
098757f248 update dependencies including electron to v28 (#3357) 2024-01-16 21:45:04 +01:00
Kristjan ESPERANTO
58bc14e8c0 Request only required information instead of all (#3338)
Hopefully this solves the problem with arm64 (reported in PR #3337).
2024-01-14 09:15:30 +01:00
Karsten Hassel
f890f14df7 ignore strange errors from systeminformation under aarch64 (#3349)
by excluding them from global error handling, see discussions in
https://github.com/MagicMirrorOrg/MagicMirror/pull/3337
2024-01-14 09:13:01 +01:00
Ross Younger
dadc7ba0a2 [newsfeed] Suppress unsightly animation edge cases when there are 0 or 1 active news items (#3336)
When the newsfeed module has an items list of size 1, every
`updateInterval` the animation runs to transition from the active story
to itself. This is unsightly. This PR suppresses that.

To reproduce: configure newsfeed with a single news source,
`ignoreOldItems` true, a short `updateInterval` (e.g. 3000), and a
carefully-chosen small `ignoreOlderThan` lining up with the current
contents of your news source.
2024-01-14 09:12:32 +01:00
Kristjan ESPERANTO
b47600e0d8 Remove lodash (#3339)
Removing lodash dependency by replacing merge by spread operator.

I have also split the return into two variables to make it easier to
understand what is happening.
2024-01-08 20:16:26 +01:00
Kristjan ESPERANTO
4bbd35fa6a Use node prefix for build-in modules (#3340)
It is basically a cosmetic thing, but has the following advantages:

1. Consistency with the official node documentation. The prefix is used
there.
2. It is easier to recognize the build-in modules.
2024-01-08 17:45:54 +01:00
Kristjan ESPERANTO
407072d12d Update system information (#3337)
- Add ELECTRON_ENABLE_GPU
- Remove docker version
- Differentiation between installed and used node version
- Highlight "Ready to go!" for server mode (Since we display system
information in the console, it is easy to overlook this important line.)

## Electron mode

### Before

```bash
[07.01.2024 16:37.30.591] [INFO]  System information:
 ### SYSTEM:   manufacturer: Notebook; model: N650DU; raspberry: undefined; virtual: false
 ### OS:       platform: linux; distro: Debian GNU/Linux; release: 12; arch: x64; kernel: 5.10.0-20-amd64
 ### VERSIONS: electron: 27.2.0; node: 18.17.1; npm: 10.2.4; pm2: 5.3.0; docker: 20.10.24+dfsg1
 ### OTHER:    timeZone: Europe/Berlin
```

### After

```bash
[07.01.2024 16:39.04.736] [INFO]  System information:
### SYSTEM:   manufacturer: Notebook; model: N650DU; raspberry: undefined; virtual: false
### OS:       platform: linux; distro: Debian GNU/Linux; release: 12; arch: x64; kernel: 5.10.0-20-amd64
### VERSIONS: electron: 27.2.0; used node: 18.17.1; installed node: 21.1.0; npm: 10.2.4; pm2: 5.3.0
### OTHER:    timeZone: Europe/Berlin; ELECTRON_ENABLE_GPU: undefined
```

## server mode

### Before

```bash
[07.01.2024 16:36.49.106] [LOG]   
Ready to go! Please point your browser to: http://localhost:8080
[07.01.2024 16:36.49.287] [INFO]  System information:
 ### SYSTEM:   manufacturer: Notebook; model: N650DU; raspberry: undefined; virtual: false
 ### OS:       platform: linux; distro: Debian GNU/Linux; release: 12; arch: x64; kernel: 5.10.0-20-amd64
 ### VERSIONS: electron: undefined; node: 21.1.0; npm: 10.2.4; pm2: 5.3.0; docker: 20.10.24+dfsg1
 ### OTHER:    timeZone: Europe/Berlin
```

### After

```bash
[2024-01-07 16:33:53.804] [INFO]  
>>>   Ready to go! Please point your browser to: http://localhost:8080   <<< 
[2024-01-07 16:33:53.997] [INFO]  System information:
### SYSTEM:   manufacturer: Notebook; model: N650DU; raspberry: undefined; virtual: false
### OS:       platform: linux; distro: Debian GNU/Linux; release: 12; arch: x64; kernel: 5.10.0-20-amd64
### VERSIONS: electron: undefined; used node: 21.1.0; installed node: 21.1.0; npm: 10.2.4; pm2: 5.3.0
### OTHER:    timeZone: Europe/Berlin; ELECTRON_ENABLE_GPU: undefined 
```
2024-01-07 17:28:17 +01:00
Kristjan ESPERANTO
6097547c10 Add systeminfo (#3331)
This is a first attempt to bring additional system information into the
console (see #3328). It's certainly not yet perfect, but with the PR we
have a better basis for discussion.

I tried to keep the output small so that we get as much information as
possible in screenshots.

This is how it looks on my development system.

```bash
[03.01.2024 00:50.19.226] [INFO] System information:
 ### SYSTEM:   manufacturer: Notebook; model: N650DU; raspberry: undefined; virtual: false
 ### OS:       platform: linux; distro: Debian GNU/Linux; release: 12
 ### VERSIONS: MagicMirror: 2.27.0-develop; electron: 27.2.0; kernel: 5.10.0-20-amd64; node: 21.1.0; npm: 10.2.4; pm2: 5.3.0; docker: 20.10.24+dfsg1
 ```
 
 Why is it still a draft:
- [x] I have doubts that utils.js is the right place for the function. What do you think?
=> Update: As long as there is no better idea, it stays there.
- [x] Instead of working through all wishes you expressed in the issue #3328, I only implemented what was easy to achieve. And wanted to hear what you think about this approach.
=> Update: Some added. Of course, more information could be added later, as soon as experience has been gained in productive use.
- [x] I don't quite like the introductory line ("The following lines provide information..."). Should I perhaps simply replace it with "System information:"?
=> Update: Changed to "System information:"
 
 [Here](https://github.com/sebhildebrandt/systeminformation#function-reference-and-os-support) you can see what information we could easily add with the systeminformation package.
 
 It would be interesting how the raspberry field is filled on a raspi system and with docker there should be another line, but I can't easily test that now.
2024-01-04 22:38:53 +01:00
dependabot[bot]
5f7b56e645 Bump eslint-plugin-jsdoc from 46.9.1 to 47.0.2 (#3315)
Bumps
[eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) from
46.9.1 to 47.0.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/gajus/eslint-plugin-jsdoc/releases">eslint-plugin-jsdoc's
releases</a>.</em></p>
<blockquote>
<h2>v47.0.2</h2>
<h2><a
href="https://github.com/gajus/eslint-plugin-jsdoc/compare/v47.0.1...v47.0.2">47.0.2</a>
(2024-01-01)</h2>
<h3>Bug Fixes</h3>
<ul>
<li><strong>TS:</strong> use flat config; fixes <a
href="https://redirect.github.com/gajus/eslint-plugin-jsdoc/issues/1130">#1130</a>
(<a
href="3677e43322">3677e43</a>)</li>
</ul>
<h2>v47.0.1</h2>
<h2><a
href="https://github.com/gajus/eslint-plugin-jsdoc/compare/v47.0.0...v47.0.1">47.0.1</a>
(2023-12-31)</h2>
<h3>Bug Fixes</h3>
<ul>
<li><strong>TS:</strong> make configs explicit (<a
href="47f316160d">47f3161</a>)</li>
</ul>
<h2>v47.0.0</h2>
<h1><a
href="https://github.com/gajus/eslint-plugin-jsdoc/compare/v46.10.1...v47.0.0">47.0.0</a>
(2023-12-31)</h1>
<h3>Features</h3>
<ul>
<li>expose TS types for index file; fixes <a
href="https://redirect.github.com/gajus/eslint-plugin-jsdoc/issues/1130">#1130</a>
(<a
href="dd9e71daa2">dd9e71d</a>)</li>
</ul>
<h3>BREAKING CHANGES</h3>
<ul>
<li>Adds types</li>
</ul>
<h2>v46.10.1</h2>
<h2><a
href="https://github.com/gajus/eslint-plugin-jsdoc/compare/v46.10.0...v46.10.1">46.10.1</a>
(2023-12-30)</h2>
<h3>Bug Fixes</h3>
<ul>
<li>revert change to engines for now (<a
href="5e6280ffd4">5e6280f</a>)</li>
</ul>
<h2>v46.10.0</h2>
<h1><a
href="https://github.com/gajus/eslint-plugin-jsdoc/compare/v46.9.1...v46.10.0">46.10.0</a>
(2023-12-30)</h1>
<h3>Features</h3>
<ul>
<li>support ESLint 9 (<a
href="eec9d9532b">eec9d95</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3677e43322"><code>3677e43</code></a>
fix(TS): use flat config; fixes <a
href="https://redirect.github.com/gajus/eslint-plugin-jsdoc/issues/1130">#1130</a></li>
<li><a
href="5f61575951"><code>5f61575</code></a>
chore(lint): handle disable directives in config</li>
<li><a
href="47f316160d"><code>47f3161</code></a>
fix(TS): make configs explicit</li>
<li><a
href="dd9e71daa2"><code>dd9e71d</code></a>
feat: expose TS types for index file; fixes <a
href="https://redirect.github.com/gajus/eslint-plugin-jsdoc/issues/1130">#1130</a></li>
<li><a
href="eb3f4b47e1"><code>eb3f4b4</code></a>
chore(linting): add ignores properly and disable directives for now</li>
<li><a
href="5e6280ffd4"><code>5e6280f</code></a>
fix: revert change to engines for now</li>
<li><a
href="eec9d9532b"><code>eec9d95</code></a>
feat: support ESLint 9</li>
<li><a
href="5c4ccb9752"><code>5c4ccb9</code></a>
chore: update devDeps.</li>
<li>See full diff in <a
href="https://github.com/gajus/eslint-plugin-jsdoc/compare/v46.9.1...v47.0.2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=eslint-plugin-jsdoc&package-manager=npm_and_yarn&previous-version=46.9.1&new-version=47.0.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-01 22:36:34 +01:00
Karsten Hassel
bcab8ebd26 skip changelog requirement when running tests for dependency updates (#3326)
solution for #3320
2024-01-01 22:14:05 +01:00
dependabot[bot]
ae1f9d0468 Bump moment-timezone from 0.5.43 to 0.5.44 in /vendor (#3317)
Bumps [moment-timezone](https://github.com/moment/moment-timezone) from
0.5.43 to 0.5.44.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/moment/moment-timezone/releases">moment-timezone's
releases</a>.</em></p>
<blockquote>
<h2>Release 0.5.44</h2>
<ul>
<li>Updated data to IANA TZDB <code>2023d</code>.</li>
<li>Fixed <code>.valueOf()</code> to return <code>NaN</code> for invalid
zoned objects (matching default <code>moment</code>) <a
href="https://redirect.github.com/moment/moment-timezone/pull/1082">#1082</a>.</li>
<li>Performance improvements:
<ul>
<li>Use binary search when looking up zone information <a
href="https://redirect.github.com/moment/moment-timezone/pull/720">#720</a>.</li>
<li>Avoid redundant checks in <code>tz.guess()</code>.</li>
<li>Avoid redundant <code>getZone()</code> calls in
<code>.tz()</code>.</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/moment/moment-timezone/blob/develop/changelog.md">moment-timezone's
changelog</a>.</em></p>
<blockquote>
<h3><code>0.5.44</code> <em>2023-12-29</em></h3>
<ul>
<li>Updated data to IANA TZDB <code>2023d</code>.</li>
<li>Fixed <code>.valueOf()</code> to return <code>NaN</code> for invalid
zoned objects (matching default <code>moment</code>) <a
href="https://redirect.github.com/moment/moment-timezone/pull/1082">#1082</a>.</li>
<li>Performance improvements:
<ul>
<li>Use binary search when looking up zone information <a
href="https://redirect.github.com/moment/moment-timezone/pull/720">#720</a>.</li>
<li>Avoid redundant checks in <code>tz.guess()</code>.</li>
<li>Avoid redundant <code>getZone()</code> calls in
<code>.tz()</code>.</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="25f19b6190"><code>25f19b6</code></a>
Build moment-timezone 0.5.44</li>
<li><a
href="4734cb2515"><code>4734cb2</code></a>
Bump version to 0.5.44</li>
<li><a
href="585fabfcbd"><code>585fabf</code></a>
Merge pull request <a
href="https://redirect.github.com/moment/moment-timezone/issues/1085">#1085</a>
from moment/data/2023d</li>
<li><a
href="ece926a59f"><code>ece926a</code></a>
Add test for valueOf behaviour with invalid moments (<a
href="https://redirect.github.com/moment/moment-timezone/issues/1075">#1075</a>)</li>
<li><a
href="341beac0fb"><code>341beac</code></a>
Ensure valueOf returns NaN for invalid instances (<a
href="https://redirect.github.com/moment/moment-timezone/issues/1082">#1082</a>)</li>
<li><a
href="69d856d5aa"><code>69d856d</code></a>
data: Add 2023d</li>
<li><a
href="dc53e6cdec"><code>dc53e6c</code></a>
build(deps): bump <code>@​babel/traverse</code> (<a
href="https://redirect.github.com/moment/moment-timezone/issues/1076">#1076</a>)</li>
<li><a
href="dffed7a8a9"><code>dffed7a</code></a>
perf: Reduce unnecessary getZone() calls in moment.tz()</li>
<li><a
href="f7d8fc2d42"><code>f7d8fc2</code></a>
docs: Add note about maintenance mode in contributing guide</li>
<li><a
href="4b1419b51f"><code>4b1419b</code></a>
docs: Update contributing guide to reflect the latest data process</li>
<li>Additional commits viewable in <a
href="https://github.com/moment/moment-timezone/compare/0.5.43...0.5.44">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=moment-timezone&package-manager=npm_and_yarn&previous-version=0.5.43&new-version=0.5.44)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-01 22:03:25 +01:00
Kristjan ESPERANTO
367d02f1b6 Update URLs to MagicMirrorOrg (#3321) 2024-01-01 21:56:13 +01:00
Michael Teeuw
5e346e7c0a Start of 2.27.0 develop branch. 2024-01-01 15:43:38 +01:00
Michael Teeuw
118e21238c Merge branch 'develop' of https://github.com/MichMich/MagicMirror 2024-01-01 15:40:44 +01:00
veeck
d20d9a7ef8 Merge branch 'master' into develop 2024-01-01 15:33:31 +01:00
Michael Teeuw
b8e0e2a791 Release 2.26.0 2024-01-01 15:01:38 +01:00
Karsten Hassel
a927eb20d9 fix variable problems (#3304)
related to #3302

- fix MM_PORT variable not used in electron
- fix to allow full path for MM_CONFIG_FILE variable
2023-12-28 21:58:31 +01:00
Karsten Hassel
aad3eefc62 update node-ical to v0.17.1 (and other deps) (#3309)
- update `node-ical` to `v0.17.1` (and other deps)
- remove `luxon` (not needed anymore with new `node-ical` version)
- fix `navigator is not defined` errors in e2e tests when running with
Node `v20`
2023-12-28 19:54:49 +01:00
Karsten Hassel
ee1960ced0 change rule exceptions in .eslintrc (#3305)
for all files beginning with `config/config.js` so e.g. `config.js` and
`config.js.template` are included.

Otherwise the test will always fail locally if someone has renamed
`config.js.sample` to `config.js`.
2023-12-25 23:35:30 +01:00
Kristjan ESPERANTO
0b70274a1a Replace prettier by stylistic to lint JavaScript (#3303)
In the latest versions of ESLint, more and more formatting rules were
removed or declared deprecated. These rules have been integrated into
the new Stylistic package (https://eslint.style/guide/why) and expanded.

Stylistic acts as a better formatter  for JavaScript as Prettier.

With this PR there are many changes that make the code more uniform, but
it may be difficult to review due to the large amount. Even if I have no
worries about the changes, perhaps this would be something for the
release after next.

Let me know what you think.
2023-12-25 08:17:11 +01:00
Kristjan ESPERANTO
4e7b68a69d Remove some unused variables (#3301)
I have noticed unused variables that seem superfluous.
2023-12-23 07:27:02 +01:00
Veeck
786ea86e0e Cleanup calendar module (#3300)
- Update default calendar config to use customEvents
- Update url that is displayed when old authentication is used
2023-12-22 19:34:06 +01:00
Karsten Hassel
d397568062 fix calendar config (#3299)
params `fetchInterval` and `excludedEvents` were never used from single
calendar config.

Fixes #3297
2023-12-21 21:44:17 +01:00
Karsten Hassel
a7af76b619 fix calendar test exdate check (#3293)
fixes #3291
2023-12-17 07:19:15 +01:00
Karsten Hassel
319a921f75 start electron with --disable-gpu flag (#3290)
can be overriden with env var ELECTRON_ENABLE_GPU=1.

see #3226 

Tests will fail as long as
https://github.com/MichMich/MagicMirror/pull/3289 is not merged.
2023-12-13 22:49:35 +01:00
Karsten Hassel
d5406f4900 update deps and fix style issue in js/class.js (#3289)
see title, should be merged because style tests are failing, see
https://github.com/MichMich/MagicMirror/pull/3284#issuecomment-1854513673
2023-12-13 22:48:23 +01:00
Ben Nitkin
55cd03576f Show moon phase in clock module (#3284)
This change replaces the font-awesome moon icon and percent-lit with an
icon showing the current lunar phase.

It uses emoji, which may not be installed on all machines. The fallback
text version is backwards (the dark part of the moon is text-color,
which is normally black but white in MagicMirror).

---------

Co-authored-by: veeck <michael.veeck@nebenan.de>
2023-12-13 09:43:07 +01:00
Kristjan ESPERANTO
9d97724401 Fix missing typeof in calendar module (#3286)
I think comparing here with "undefined" (as a string) makes only sense
with typeof.
2023-12-07 08:11:56 +01:00
Bugsounet - Cédric
74854387cd Fix updatenotification (#3281)
Sometime, `pm2 jlist` don't send an json reponse
Catch error if happen

---------

Co-authored-by: bugsounet <bugsounet@bugsounet.fr>
2023-12-04 07:34:14 +01:00
Veeck
e77f10b86d Update dependencies (#3280)
Took the ones from dependabot and updated the rest...

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-01 19:14:37 +01:00
Karsten Hassel
6ffdc7b55b enable eslint jest/expect-expect and jest/no-done-callback (#3272)
follow up to https://github.com/MichMich/MagicMirror/pull/3270
2023-11-22 23:37:17 +01:00
Kristjan ESPERANTO
7098f1e41f Enable and apply ESLint Jest rules (#3270)
Jest was in the plugin array of the ESLint configuration, but no rules
were enabled. So ESLint hasn't checked any Jest rules yet.

So I activated the recommended Jest rules and added a few more. Then I
fixed the issues (mostly automatically). I have deactivated the rules
"jest/expect-expect" and "jest/no-done-callback" for the time being, as
they would have entailed major changes. I didn't want to make the PR too
big.

I'm not a Jest expert, but the changes so far look good to me. What do
you think of that @khassel? 🙂
2023-11-20 20:11:41 +01:00
Kristjan ESPERANTO
679a413788 Review eslint config (#3269)
- Remove "prettier" from plugin array, because it's already enabled by
"plugin:prettier/recommended"
- Remove "jsdoc" from plugin array, because it's already enabled by
"plugin:jsdoc/recommended"
- Enable recommended import rules
- Add two additional import rules

Note: To avoid overloading this PR I'll tackle the jest part with
another PR after this one has been dealt with.
2023-11-20 08:03:29 +01:00
sam detweiler
247115d2e4 fix electron start loadurl on windows when address="0.0.0.0" (#3268)
> - Does the pull request solve a **related** issue?
Fixes #2550 

> - What does the pull request accomplish? Use a list if needed.

changes the loadUrl to use localhost, as electron and MM are on this
same system
the mm 'server' is still listening on all adapters, including localhost
2023-11-15 19:44:08 +01:00
Bugsounet - Cédric
70ddd80632 Use html-to-text instead of regex for transform description (#3264)
I try to use only `html-to-text` library

it's will solve issue #3235 

@rejas, @sdetweil, @khassel: Can you do tests with your own feeds?

Thanks for feedbacks
2023-11-11 09:13:16 +01:00
Bugsounet - Cédric
203e8647d4 3rd party modules updater for updatenotification (#3150)
Added my (modified) updater main core into updatenotification default
module

Missing: callback display in MM² (i will code it after)

new part of configuration added:

```
		updates: [
			// array of module update commands
			{
				// with embed npm script
				"MMM-Test": "npm run update"
			},
			{
				// with "complex" process
				"MMM-OtherSample": "rm -rf package-lock.json && git reset --hard && git pull && npm install"
			},
			{
				// with git pull && npm install
				"MMM-OtherSample2": "git pull && npm install"
			},
			{
				// with a simple git pull
				"MMM-OtherSample3": "git pull"
			}
		],
		updateTimeout: 2 * 60 * 1000, // max update duration
		updateAutorestart: false // autoRestart MM when update done ?
```

@khassel: i need your help
I don't use docker, maybe you can help me for this:
How can i check if MM² is running inside a docker ? (from MM² main core)
Actually, I check if we use pm2 or not.
I have to check if docker is used or not too
last time you tell me: "you can't use updater with docker", so I want to
check and deny any update if docker used

---------

Co-authored-by: bugsounet <bugsounet@bugsounet.fr>
2023-11-10 12:43:34 +01:00
Karsten Hassel
3fe5ad4b3d remove failing unit test (#3265)
see
https://github.com/MichMich/MagicMirror/issues/3254#issuecomment-1800120812
2023-11-09 22:57:15 +01:00
sam detweiler
b300191609 fix crash on rrule.between returned bad dates #3256 (#3257)
Fixes: #3256 

BUT.. the testcase is inconclusive.. as the code FAILS without the fix,
BUT somehow RETURNS 0 entries..
in real life run the node helper fails, and all calendar processing
stops.
2023-11-07 19:48:00 +01:00
dependabot[bot]
296df06c21 Bump eslint-plugin-jest from 27.4.3 to 27.6.0 (#3260)
Bumps
[eslint-plugin-jest](https://github.com/jest-community/eslint-plugin-jest)
from 27.4.3 to 27.6.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/jest-community/eslint-plugin-jest/releases">eslint-plugin-jest's
releases</a>.</em></p>
<blockquote>
<h2>v27.6.0</h2>
<h1><a
href="https://github.com/jest-community/eslint-plugin-jest/compare/v27.5.0...v27.6.0">27.6.0</a>
(2023-10-26)</h1>
<h3>Features</h3>
<ul>
<li>include plugin <code>meta</code> information for ESLint v9 (<a
href="https://redirect.github.com/jest-community/eslint-plugin-jest/issues/1454">#1454</a>)
(<a
href="4d57146763">4d57146</a>)</li>
</ul>
<h2>v27.5.0</h2>
<h1><a
href="https://github.com/jest-community/eslint-plugin-jest/compare/v27.4.3...v27.5.0">27.5.0</a>
(2023-10-26)</h1>
<h3>Features</h3>
<ul>
<li><strong>valid-title:</strong> allow ignoring tests with non-string
titles (<a
href="https://redirect.github.com/jest-community/eslint-plugin-jest/issues/1460">#1460</a>)
(<a
href="ea89da9b4e">ea89da9</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/jest-community/eslint-plugin-jest/blob/main/CHANGELOG.md">eslint-plugin-jest's
changelog</a>.</em></p>
<blockquote>
<h1><a
href="https://github.com/jest-community/eslint-plugin-jest/compare/v27.5.0...v27.6.0">27.6.0</a>
(2023-10-26)</h1>
<h3>Features</h3>
<ul>
<li>include plugin <code>meta</code> information for ESLint v9 (<a
href="https://redirect.github.com/jest-community/eslint-plugin-jest/issues/1454">#1454</a>)
(<a
href="4d57146763">4d57146</a>)</li>
</ul>
<h1><a
href="https://github.com/jest-community/eslint-plugin-jest/compare/v27.4.3...v27.5.0">27.5.0</a>
(2023-10-26)</h1>
<h3>Features</h3>
<ul>
<li><strong>valid-title:</strong> allow ignoring tests with non-string
titles (<a
href="https://redirect.github.com/jest-community/eslint-plugin-jest/issues/1460">#1460</a>)
(<a
href="ea89da9b4e">ea89da9</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="6dfbf15d02"><code>6dfbf15</code></a>
chore(release): 27.6.0 [skip ci]</li>
<li><a
href="4d57146763"><code>4d57146</code></a>
feat: include plugin <code>meta</code> information for ESLint v9 (<a
href="https://redirect.github.com/jest-community/eslint-plugin-jest/issues/1454">#1454</a>)</li>
<li><a
href="55ad33675d"><code>55ad336</code></a>
chore: update <code>moduleResolution</code> and <code>module</code> to
<code>node16</code> (<a
href="https://redirect.github.com/jest-community/eslint-plugin-jest/issues/1455">#1455</a>)</li>
<li><a
href="9cc95920ea"><code>9cc9592</code></a>
chore: replace <code>eslint-plugin-node</code> with
<code>eslint-plugin-n</code> (<a
href="https://redirect.github.com/jest-community/eslint-plugin-jest/issues/1462">#1462</a>)</li>
<li><a
href="1d5bdd1391"><code>1d5bdd1</code></a>
chore(release): 27.5.0 [skip ci]</li>
<li><a
href="ea89da9b4e"><code>ea89da9</code></a>
feat(valid-title): allow ignoring tests with non-string titles (<a
href="https://redirect.github.com/jest-community/eslint-plugin-jest/issues/1460">#1460</a>)</li>
<li><a
href="f2af5194bd"><code>f2af519</code></a>
chore: run CI on Node 21 (<a
href="https://redirect.github.com/jest-community/eslint-plugin-jest/issues/1461">#1461</a>)</li>
<li><a
href="d8b10b47e7"><code>d8b10b4</code></a>
chore: update permissions granted on CI</li>
<li><a
href="4295882c21"><code>4295882</code></a>
chore(deps): lock file maintenance</li>
<li>See full diff in <a
href="https://github.com/jest-community/eslint-plugin-jest/compare/v27.4.3...v27.6.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=eslint-plugin-jest&package-manager=npm_and_yarn&previous-version=27.4.3&new-version=27.6.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-01 19:48:50 +01:00
jkriegshauser
fe882bf92a Fix issue #3250: Respect deleted (excluded) calendar events (#3251)
Hello and thank you for wanting to contribute to the MagicMirror²
project

**Please make sure that you have followed these 4 rules before
submitting your Pull Request:**

> 1. Base your pull requests against the `develop` branch.
> 2. Include these infos in the description:
>
> - Does the pull request solve a **related** issue?
> - If so, can you reference the issue like this `Fixes
#<issue_number>`?
> - What does the pull request accomplish? Use a list if needed.
> - If it includes major visual changes please add screenshots.
>
> 3. Please run `npm run lint:prettier` before submitting so that
>    style issues are fixed.
> 4. Don't forget to add an entry about your changes to
>    the CHANGELOG.md file.

**Note**: Sometimes the development moves very fast. It is highly
recommended that you update your branch of `develop` before creating a
pull request to send us your changes. This makes everyone's lives
easier (including yours) and helps us out on the development team.

Thanks again and have a nice day!
2023-11-01 07:42:47 +01:00
kaennchenstruggle
2a6e2aacdc Calendar translate (#3249)
Hello and thank you for wanting to contribute to the MagicMirror²
project

**Please make sure that you have followed these 4 rules before
submitting your Pull Request:**

> 1. Base your pull requests against the `develop` branch.

DONE ;D

> 2. Include these infos in the description:
> - Does the pull request solve a **related** issue?

NO
> - What does the pull request accomplish? Use a list if needed.

For calendar entries containing a year (e.g. DOB) in the title, the age
can be calculated.

Example before:

![grafik](https://github.com/MichMich/MagicMirror/assets/54073894/67ca65f4-24c3-46a8-bee8-0519e4bba3f5)
after:

![grafik](https://github.com/MichMich/MagicMirror/assets/54073894/0b4af07d-d3d9-4644-a4a6-e8c402598208)

Achieved by adding a new keyword `transform` to customEvents
```
customEvents: [
                        {keyword: 'Geburtstag', symbol: 'birthday-cake', color: 'Gold', transform: { search: '^([^\']*) \'(\\d{4})$' , replace: '$1 ($2.)', yearmatchgroup: 2}},
                        {keyword: 'in Hamburg', transform: { search: ' in Hamburg$' , replace: ''}} 
		],
```

and therewith obsoleting `titleReplace`; a backward compatibility part
is already included.

If `yearmatchgroup` is unset, behaviour is as in previous code (some
additions to which RegExes are accepted, though)

If `yearmatchgroup` is set, it is considered the RegEx match group id,
which will be used for calculating the age.



> - If it includes major visual changes please add screenshots.

NO

> 3. Please run `npm run lint:prettier` before submitting so that style
issues are fixed.

DONE

> 4. Don't forget to add an entry about your changes to the CHANGELOG.md
file.

DONE

> Thanks again and have a nice day!

You too and if any questions, feel free to let me know.

---------

Co-authored-by: veeck <michael.veeck@nebenan.de>
2023-11-01 00:07:56 +01:00
Karsten Hassel
3a01acd389 fix for failing unit test, use UTC as timezone (#3254) (#3259)
fixes #3254
2023-11-01 00:02:53 +01:00
Karsten Hassel
a8d06ae74e hotfix for failing unit test (#3258)
I know this isn't a real solution, but it's the quickest way to get it
working again.

A real solution must be found later.
2023-10-31 19:37:34 +01:00
Veeck
04f0df269a Fix yr weather provider api version (#3248)
Fixes #3227 once more
2023-10-24 00:46:25 +02:00
Veeck
f80889d953 Update github test action (#3247)
... add node 21 to the tests and also update dependencies
2023-10-23 21:37:52 +02:00
Karsten Hassel
6815dfa02b fix ISSUE_TEMPLATE (#3243)
fix for #3167
2023-10-21 21:17:24 +02:00
Bugsounet - Cédric
bbc27f5ae2 Avoid fade out/in on updateDom when many calendars are used (#3220)
related to #3185 

* I have limited updated dom to one update
-> `updateDom()` is activated by a timer which resets when a new event
arrives (`CALENDAR_EVENTS`)

* I have set no speed to self update. I think it's not necessary
-> update it directly

If somebody can test and tell me result
In all case, I will patch my prod mirror for testing
2023-10-21 19:41:17 +02:00
Karsten Hassel
f46b226940 fix newsfeed module for feeds using "a10:updated" tag (#3242)
solves  #3238
2023-10-20 06:41:31 +02:00
Karsten Hassel
764ca3ac5c update electron to v27 (#3241)
and 
- update other deps
- update package-lock.json version to v3 in /vendor and /fonts
2023-10-19 23:44:31 +02:00
Karsten Hassel
0e2da630d5 fix cloneObject() function to respect RegExp (#3240)
fixes #3237
2023-10-19 22:31:02 +02:00
Veeck
a0b444d6c4 Fix API version in yr weather provider call (#3223)
Fixes #3227 

and also
- removes unused code
- de-duplicates code fragments
- fixes typos
- inlines code
- adds more weather util tests

@martingron and @Justheretoreportanissue would you be so kind to check
if I didnt mess anything up?
2023-10-15 13:25:44 +02:00
Karsten Hassel
5d2ddbd3dd removed Codecov workflow (not working anymore, other workflow required) (#3230)
see #3107
2023-10-13 07:41:35 +02:00
Teddy
b067711ede Event class bugfix (#3218)
Hello,

Bugfix. :-) The "break" line did not allow the "eventClass" option to
execute.
2023-10-03 12:24:50 +02:00
Michael Teeuw
66b29ec26e Prepare v2.26.0-develop 2023-10-01 20:17:06 +02:00
Michael Teeuw
6ea94e4512 Release v2.25.0 2023-10-01 20:01:14 +02:00
Bugsounet - Cédric
290b350856 Update last Dependencies before release and add dependabot to vendor/fonts directory (#3213)
Last check before release:

* update to electron: v2.26.4
* update eslint-plugins-jest: v27.4.2
* renew `package-lock.json`
* add dependabot to `vendor` and `fonts` directory (monthly check)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-30 15:18:56 +02:00
Bugsounet - Cédric
9566d6c9a0 Add npm dependabot (#3210)
Like mentioned
[there](https://github.com/MichMich/MagicMirror/pull/3207#issuecomment-1736181753)

I open an PR with npm dependabot (every monthly)

It might be interesting to have an overview every month

---------

Co-authored-by: Veeck <github@veeck.de>
2023-09-27 23:43:13 +02:00
Karsten Hassel
6b204cda25 calendar: add url to broadcast logging (#3211)
minimal solution for #3110
2023-09-27 23:37:10 +02:00
Bugsounet - Cédric
e530c783f8 Update Electron based on a severity vulnerability (develop) (#3207)
I just see `electron` package used in develop branch have `1 high
severity vulnerability`

Detail is [there](https://github.com/advisories/GHSA-j7hp-h8jx-5ppr)

We can patch it with electron v26.2.2 (last version at this day) and
will correct it

(ChangeLog is not needed in this case)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: veeck <michael.veeck@nebenan.de>
2023-09-26 23:12:09 +02:00
dgoth
a3c2e7b816 Fixed probability of precipitation in weathergov.js (#3195)
Fixes https://github.com/MichMich/MagicMirror/issues/3182

Fixed issue with probability of precipitation not showing up on hourly
or daily forecast

---------

Co-authored-by: veeck <michael.veeck@nebenan.de>
2023-09-25 22:42:27 +02:00
Bugsounet - Cédric
ad665a7a33 AnimateCSS integration in tests suite (#3206)
Hi,

Just because, i never try to code a test
I purpose to supervise this work

After, perhaps it is not necessary to integrate it in develop branch. 
It's up to you to decide
2023-09-25 22:27:52 +02:00
Karsten Hassel
95ec3096e0 avoid overriding config.js when running tests (#3205)
solves #3201
2023-09-22 14:45:46 +02:00
Teddy
a67a0b677c Add eventClass for customEvents in calendar (#3193)
Hello,
This pull request allows you to add a class to the tr of the event
sought in customEvents. You must enter the class with the "eventClass"
option.

---------

Co-authored-by: TeddyStarinvest <teddy.payet@starinvest.com>
2023-09-20 22:04:41 +02:00
martingron
8b1c279c07 Update yr provider to new api (#3197)
Some changes after yr api was deprecated and replaced with a new one.

Fixes #3189
2023-09-20 11:37:01 +02:00
Bugsounet - Cédric
4eccce3f77 Fix: AnimateCSS merge hide() and show() animated css class when we do multiple call (#3200)
PR: #3113  

I see this bugs:

AnimateCSS merge hide() and show() animated css class when we do
multiple call
--> result it will stay en hide state

I think event listener (is animateCSS file) is not a proper solution

I correct it with like traditional code with timer

Fix too: AnimateIn on first start
2023-09-19 20:14:35 +02:00
Bugsounet - Cédric
af0fe37f70 Fix: Uncaught SyntaxError: Identifier 'getCorsUrl' has already been declared (#3204)
Issue #3202 

move shared modules/default/utils.js file to index.html
2023-09-19 07:14:11 +02:00
Teddy
e5adbea49c Update french translation (#3194)
Updated the French translation according to the English file.

---------

Co-authored-by: TeddyStarinvest <teddy.payet@starinvest.com>
2023-09-14 15:32:24 +02:00
Karsten Hassel
7127979c6f electron: add missing fullscreen option (#3192)
follow up for https://github.com/MichMich/MagicMirror/pull/3187

@bugsounet can you please confirm that this now works for you?
2023-09-14 08:01:50 +02:00
Karsten Hassel
fa7c7fc8cf respect width/height (no fullscreen) if set in electronOptions... (#3187)
... in `config.js`.

Solves #3174 

With getting width/heigt from
`electron.screen.getPrimaryDisplay().workAreaSize` introduced with
https://github.com/MichMich/MagicMirror/pull/3161 the solution was to
remove the `setFullscreen` line.

So per default the fullscreen resolution is used but when someone now
uses `electronOptions.width`/`electronOptions.height` in `config.js`
these parameters are used and so "no fullscreen" is possible.
2023-09-13 22:59:36 +02:00
Bugsounet - Cédric
91fd931a58 Convert HTML entities, codes and tag (#3191)
related to PR [#3092](https://github.com/MichMich/MagicMirror/pull/3092)

maybe best way is using `html-to-text` library

sample: `&quotHello World&quot` will be transformed to `"Hello World"`
2023-09-13 22:47:07 +02:00
Karsten Hassel
7a1591b2d6 added automatic client page reload (#3188)
solution for #3105 

~~not sure if updatenotification is the right place, so opinions?~~

now impleneted in `main.js`
2023-09-13 22:46:17 +02:00
Karsten Hassel
f2957f90df use internal fetch as replacement for node-fetch (#3184)
related to #2649

I was able to move to internal fetch and all tests seems fine so far.

But we have one problem with the calendar module. In the docs we have
several authentication methods and one of them is `digest`. For this we
used `digest-fetch` which needs `node-fetch` (this is not so clear from
code but I was not able to get it working).

So we have 3 options:
- remove `digest` as authentication method for calendar module (this is
what this PR does at the moment)
- find an alternative npm package or implement the digest stuff
ourselves
- use `digest-fetch` and `node-fetch` for calendar module (so they would
remain as dependencies in `package.json`)

Opinions? @KristjanESPERANTO @rejas @sdetweil @MichMich
2023-09-09 21:12:31 +02:00
Bugsounet - Cédric
ffdf321e23 Mistake on Changelog (#3186)
Move AnimateCSS changeLog from  v2.24 to  v2.25
2023-09-09 10:38:19 +02:00
J. Kenzal Hunter
79e99e18ea Cross UTC time fix (#3175)
Update calendarfetcherutils.js to force recurrence date time to be the
same as event datetime

I found an issue with one of my calendars displaying the wrong time for
certain recurring events. Each event was set up by someone in a
different timezone (Central European) than my own (Eastern US). I traced
the issue back to the `Rrule.between()` method generating odd time
portions under certain circumstances.

The fix I found was to set the UTC time portion of the recurrence
datetime to be the same as the UTC time portion of the event start date.

This resolved the issues with the maladjusted event times, and had no
effect on other event times. While there may be edge cases that are
affected, I have been unable to locate any.

---------

Co-authored-by: Veeck <github@veeck.de>
2023-09-08 07:44:49 +02:00
Bugsounet - Cédric
a92b3d3f71 Add AnimateCSS (#3113)
Hi,

This is my testing code for AnimateCSS for `show()`, `hide()`,
`updateDom()`

Naturally, we have to do better !

I voluntarily modify `newsfeed` and `compliments` in order to test

Note: I will correct checks later... it's a test...

---------

Co-authored-by: bugsounet <bugsounet@bugsounet.fr>
Co-authored-by: veeck <michael.veeck@nebenan.de>
2023-09-08 07:43:39 +02:00
NolanKingdon
5cbdd28db3 Added Override Notification Option to Weather Module (#3178)
Fixes #3126 

Added the option `allowOverrideNotification` to `weather.js`. This
allows the module to receive the `CURRENT_WEATHER_OVERRIDE`
notification. The expected payload for this notification is a
full/partial `weatherObject` that is used to supplement/replace the
existing `weatherObject` returned by whichever weather provider is in
use.

No visual changes.

First time contributing - let me know if I've missed something
🙂

---------

Co-authored-by: veeck <michael.veeck@nebenan.de>
2023-09-08 07:41:20 +02:00
Kristjan ESPERANTO
9d49196e69 Fix ipWhiteList test (#3181)
Port change seems to fix a timing issue.
2023-09-06 23:53:02 +02:00
Veeck
ef20fe2d11 Update dependencies and actions (#3179)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-05 22:15:45 +02:00
Veeck
c0a5f35a00 Cleanup nunjuck templates (#3109)
Ran a linter over it (djlint) which fixed intendation and a few errors

---------

Co-authored-by: veeck <michael@veeck.de>
2023-09-02 22:18:57 +02:00
Paranoid93
2ad463b6c7 fix calendar not showing events with the same name and start date but different calendar url (#3166)
I fixed the calendar module, which did not show calendar entries from
different calendars that share the same name and start date.

My use case: We have each office days documented in each an own
calendar. If both "Office" Calendar entries start at the same date just
one was shown

Google Calendar (each Office event in an own calendar)

![260753381-c8d5aedf-3c11-4d91-83e8-8549eb261e58](https://github.com/MichMich/MagicMirror/assets/6515818/0cb0ecbd-65bb-4ec4-b5e6-b011cb1c9c6b)

Before

![260751994-b308d549-fcb9-406e-9419-cdd2fed96dc6](https://github.com/MichMich/MagicMirror/assets/6515818/ed4d4645-0852-4e19-99ed-fec3f25d547a)

After

![260753208-3278e32b-9ca5-483a-bc6f-745cbf3964fc](https://github.com/MichMich/MagicMirror/assets/6515818/41b70843-af9f-47fc-baed-91c3c63e9acb)
2023-08-26 13:53:41 +02:00
Veeck
200db181d5 Update typescript definition (#3173) 2023-08-22 20:52:10 +01:00
Bugsounet - Cédric
7ba96aeb98 Add Npmrc (#3135)
Fix engines check on npm install

it will alow to check engine requirement of `package.json`

actually:
```js
	"engines": {
		"node": ">=16"
	}
```

if requirements are not suitable, it's break installer

```sh
bugsounet@Kubuntu:~/MagicMirror-dev$ npm install
npm ERR! code EBADENGINE
npm ERR! engine Unsupported engine
npm ERR! engine Not compatible with your version of node/npm: magicmirror@2.24.0-develop
npm ERR! notsup Not compatible with your version of node/npm: magicmirror@2.24.0-develop
npm ERR! notsup Required: {"node":">=16"}
npm ERR! notsup Actual:   {"npm":"x.y.z","node":"v14.xx.yy"}
```

actually, it's just a warn:
```sh
bugsounet@KUbuntu:~/MagicMirror-dev$ npm install
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: 'magicmirror@2.24.0-develop',
npm WARN EBADENGINE   required: { node: '>=16' },
npm WARN EBADENGINE   current: { node: 'v14.xx.yy', npm: 'x.y.z' }
npm WARN EBADENGINE }
...
```
and don't break installation, this can causes errors in the main core of
MM²

---------

Co-authored-by: veeck <michael.veeck@nebenan.de>
2023-08-20 13:14:21 +02:00
Kristjan ESPERANTO
7c64d8fce6 Minimum node version v18 (#3170)
When the next MagicMirror version is released, node v16 will have
reached its end of life.
2023-08-20 12:55:17 +02:00
Kristjan ESPERANTO
7dcea98e99 Handle pretty-quick issue (#3169)
- Replace pretty-quick by lint-staged (to fix:
<https://github.com/azz/pretty-quick/issues/164>)
- Update prettier dependencies
- Handle prettier issues
2023-08-16 14:21:02 +02:00
Karsten Hassel
59e9d765e2 update to electron v26 (#3168)
- tested on rpi4
- electron tests are fine
2023-08-16 00:05:32 +02:00
Karsten Hassel
156db32c76 fix electron width/heigth when using xrandr under bullseye (#3161)
This PR uses `electron.screen.getPrimaryDisplay().workAreaSize` under
electron to get the screen size.

If this fails the current defaults (800x600) are used.

This solves some problems with xrandr under bullseye where the sreen
comes up with 800x600 instead of fullscreen, e.g. described
[here](https://khassel.gitlab.io/magicmirror/pi-modules/).

Tested this on my pi setup.

By the way, the Issue #1919 is back on my side (not related to this PR)
...
2023-08-12 22:57:42 +02:00
Karsten Hassel
58cdfa3cb1 update dependencies (except prettier v3) (#3160) 2023-08-12 22:55:09 +02:00
Veeck
49c72d8dfc Update dependencies (#3155)
Takes https://github.com/MichMich/MagicMirror/pull/3153 (why does that
always base against master despite the yaml configuring it against
develop?) and updates othe rminor dependencies (not prettier v3 that
will take a little time)

---------

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-16 23:16:53 +02:00
sam detweiler
1bd146f52e fix clientOnly not starting up after async startup added in 2.23 (#3154)
Fixes #3151 

app.whenReady() was removed when async changes made, needed for
clientonly in electron.js
2023-07-16 23:04:58 +02:00
Karsten Hassel
948910d304 add section for foreign modules in issue template (#3149) 2023-07-05 20:22:19 +02:00
Karsten Hassel
0b97639341 update roboto fonts to v5 (#3121)
there are no "all" files in the v5 versions of roboto-fonts anymore so I
used the content of their css files in `roboto.css`.

~~PR is set to draft because @rejas wants to wait until next release is
done.~~
2023-07-03 00:01:12 +02:00
Veeck
f802c85a38 Fix undefined error for showSunTime / showMoonTime in clock module (#3146)
Fixes #3143 and adds tests for showSunTime / showMoonTime
2023-07-02 22:10:58 +02:00
Knapoc
62eb23ba6a Add openweathermap UV index support (#3145)
This PR adds UV index support to the openweathermap provider for the One
Call api.
2023-07-02 21:47:25 +02:00
Michael Teeuw
4b0e0aa48f Prepare 2.25.0-develop branch. 2023-07-01 21:24:52 +02:00
Michael Teeuw
e9f1bd9d7a Merge branch 'master' into develop 2023-07-01 21:18:12 +02:00
Michael Teeuw
46bca1bc6d Merge branch 'master' into develop 2023-07-01 20:59:34 +02:00
Michael Teeuw
2b6720e6e5 Prepare 2.24.0 release. 2023-07-01 20:34:43 +02:00
Veeck
ea818bf899 Fix fetchInterval for sample calendar (#3139)
fixes #3138 just in case #3137 doesnt get worked on until the next
release

- inc fetchInterval for sample calender
- add fetchInterval config per calendar
2023-06-30 20:13:07 +02:00
Karsten Hassel
0e00e64493 update dependencies (#3140)
last dependency update before next release
2023-06-29 22:59:43 +02:00
Karsten Hassel
3c35d346ee fix updatenotification where no branch is checked out ... (#3136)
... but e.g. a version tag

fixes #3130 

This happens e.g. in my docker image where I use the version tag to get
the mm sources.

With this PR the error message is avoided and there will be never an
updatenotification when using a tag. This is o.k. because a tag should
never be moved.
2023-06-27 11:18:16 +02:00
Veeck
675e4d4f67 Update dependencies and fix dependabot issues (#3134)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-25 20:12:55 +02:00
Bugsounet - Cédric
c1850f2577 Remote force check update (#3127)
updatenotification: 

allow force scanning with `SCAN_UPDATES` notification from other modules
2023-06-18 14:33:03 +02:00
Bugsounet - Cédric
e985e99036 Updates notification (#3119)
Hi,

Like some default modules, I propose to send an `UPDATES` notification
in an array with the git information of these modules

This allows developers to create their own auto-update system (which
I've been using in my case since 3 years, with automatic things)

Of course, for security reasons `MagicMirror` is excluded

---------

Co-authored-by: bugsounet <bugsounet@bugsounet.fr>
2023-06-08 22:41:48 +02:00
Karsten Hassel
b7371538bc update deps and remove stylelint fix (#3120)
~~there are no "all" files in the v5 versions of roboto-fonts anymore so
I used the content of their css files in `roboto.css`~~

coming with separate PR
2023-06-08 22:40:23 +02:00
Karsten Hassel
a56b92990d update deps incl. electron to v25, fix stylelint segmentation dump (#3118)
- update electron to v25
- added `overrides:` section to `package.json` to fix
https://github.com/stylelint/stylelint/issues/6898 (must be removed when
fixed upstream, fixing the version to `v15.6.2` did not fix the problem)
- update other deps
2023-06-06 10:16:24 +02:00
Veeck
c7405b76b3 Split install and run commands in github actions (#3112)
... makes looking at the checks a little easier in case they fail

---------

Co-authored-by: veeck <michael@veeck.de>
2023-05-27 22:22:26 +02:00
OWL4C
eceec8285d Adding experimental UV Index support for weather module (#3108)
This pr adds (config.js toggleable) showUV_Index to the hourly and
current weather modules, with right now only openmeteo configured to
supply the data. Other providers could have support too by adding
`uv_index` to current and hourly.

For example the current weather looks like
![image](https://github.com/MichMich/MagicMirror/assets/124401812/00fdf5db-c0d5-4797-9a31-1d72dd970d26)
positioned after sunset in the top row.



The following "hacks" are included and could be fixed to make it
cleaner, but the functionality is wanted and it works without problem.
- To hide entries where the UV Index is 0 i added an if statement to the
`hourly.njk` which is not how precipitation is handled.
The following are minor things that might not need fixing:
- The forecast option does not have UV support. This might not be
relevant since UV changes throughout the day but i tried to implement a
"max_UV" to openmeteo.js, but am not confident enough in JS to
accomplish that.
- The UV Icon is wi-hot and manually added to the `.njk`'s. This could
be made changeable by a config but does not seem relevant since wi-hot
is not used by anything else as far as i can tell.

---------

Co-authored-by: veeck <michael@veeck.de>
2023-05-22 10:57:48 +02:00
Eddie Hung
0573d6e772 Fix envcanada today pop (#3106)
Fix for today's probability-of-precipitation weather module's envcanada
provider.

Without which, requesting `showPrecipitationProbability` causes
"undefined" to be shown.

Consistent with method used elsewhere in the file:

abe5c08a52/modules/default/weather/providers/envcanada.js (L395-L399)
2023-05-21 10:51:13 +02:00
Jørgen Veum-Wahlberg
babd22b04f Bug fix: adding date to the analog clock if showDate is true (#3101)
Adding date to the clock module when displayType is "analog" and
"showDate" is true. The setting in analogShowDate is respected.

Fixes #3100

---------

Co-authored-by: Michael Teeuw <michael@xonaymedia.nl>
Co-authored-by: Veeck <github@veeck.de>
2023-05-19 14:52:59 +02:00
Veeck
432d900ecd Add tests for some weather utils (#3103)
Co-authored-by: veeck <michael@veeck.de>
2023-05-15 21:04:50 +02:00
Ismar Slomic
83315f1fed fix: don't filter out ongoing full day events in Calendar module (#3095) (#3096)
Fixes #3095.

Param `hideOngoing` is by default set to `false`, but the event
filtering handles `full day` & `non-full day` events inconsistently. For
`non-full day` _ongoing_ and _upcoming_ events are returned, while for
`full day` only _upcoming_ events where returned.
2023-05-15 20:16:33 +02:00
Oscar Björkman
e09d60d1d1 Use single config backup file when config.template is used (#3104)
Copy `config.js` to a single `config.js-old` file whenever a
`config.template` is present, instead of using `Date()` as a suffix.
Creating files with a timestamp suffix means that whenever Magic Mirror
is restarted or recreated a new file is written into the config
directory.

Benefits:
* Single backup file will avoid excessive writing of files
* Saves space and usage on SD cards.
* Makes the folder cleaner and easier to overview, compared to ending up
with something like this as time goes on:

![image](https://github.com/MichMich/MagicMirror/assets/17575446/9b66a99c-e760-471e-884c-9daa19689702)
2023-05-15 20:11:23 +02:00
OWL4C
d832d795df Add openmeteo precipitation probability (#3099)
Due to the size of the commit there is no need for a long explanation:
Openmeteo supports precipitation probability in api, but the weather
provider .js had no support for it. After adding 4 lines it works as
expected. This should have no consequences on other files but improves
usability for (imo) the best weather provider.

---------

Co-authored-by: veeck <michael@veeck.de>
2023-05-13 09:29:00 +02:00
Karsten Hassel
a41aa48dd1 add .gitattributes and fix prettier/js warnings (#3094)
see title, as discussed in
https://github.com/MichMich/MagicMirror/pull/3093
2023-04-22 09:29:51 +02:00
Karsten Hassel
b80485b52f use node v20 in github workflow (replacing v19) (#3093)
additional:

- update deps
- suppress more unwanted log errors in e2e tests
- add .gitattributes
- fix prettier/js warnings
2023-04-22 09:29:23 +02:00
Veeck
7e58b38ddf Add no-param-reassign from eslint (#3089)
While waiting for the easterbunny I cleaned up some bad coding practice
:-)

Very open for comments especially regarding the places I commented
myself...

---------

Co-authored-by: veeck <michael@veeck.de>
2023-04-16 17:38:39 +02:00
Karsten Hassel
979f4ec664 fix electron not running under windows (after async changes) (#3091)
fixes #3083 

tested under windows 11 and linux.
2023-04-12 08:25:07 +02:00
Veeck
4e3369062e Fix envcanada hourly forecast time (#3090)
Fixes #3080

---------

Co-authored-by: veeck <michael@veeck.de>
2023-04-09 19:23:44 +02:00
Veeck
77f9c86774 Refactor calendar methods into util class (#3088)
Refactored some methods in calendar module:
- move methods into own file 
- dont call shorten method from titelTransform because why? just call
them after each other.
- added tests for util methods
- cleaned up other tests

---------

Co-authored-by: veeck <michael@veeck.de>
2023-04-09 12:49:50 +02:00
JakeBinney
dee3cd3da7 Fixed clock module sunrise/sunset timezone bug (#3070)
Updated sunrise/sunset times to display user-requested timezone rather
than system timezone.

Note: rebase of  #3069 against develop rather than master

Co-authored-by: Veeck <github@veeck.de>
2023-04-09 09:19:51 +02:00
Karsten Hassel
09f117c3d9 set Timezone Europe/Berlin in unit tests (#3087)
needed for new formatTime unit tests.

Avoiding ugly TZ setting in github workflows, see
https://github.com/MichMich/MagicMirror/pull/3073
2023-04-08 08:55:43 +02:00
Veeck
32192d1698 Refactor formatTime into util class (#3073)
While looking at https://github.com/MichMich/MagicMirror/pull/3070 I
noticed that the weather and clock module do some formatTime stuff, so
why not use a common function for that?

---------

Co-authored-by: veeck <michael@veeck.de>
2023-04-07 23:11:54 +02:00
Karsten Hassel
2c7beeaaaf added test for serveronly (#3086)
- add test for serveronly, fixes #3076 
- use template literals in port_variable.js.template
2023-04-07 19:42:46 +02:00
Kristjan ESPERANTO
0d3ad9812c Drop node v14 support (#3085)
node v14 will have reached end-of-life by the next release.

From April 18th we can use node v20 instead of v19 for testing.
2023-04-07 19:24:27 +02:00
Karsten Hassel
b7eb21e48f removed unneeded (and unwanted) '.' (#3084)
after the year in calendar repeatingCountTitle (#2896, second attempt
...)
2023-04-07 14:54:19 +02:00
Karsten Hassel
9703226c73 Update electron to v24, remove th.json from root dir (#3079)
- current electron v22 has end of life 07 Jul 2023 so it has to be
upgraded before next release
- removed th.json from root dir (came back with latest release)
- updated other dependencies
2023-04-05 07:43:42 +02:00
Michael Teeuw
cc11b77f24 Prepare v2.24.0-develop 2023-04-04 20:56:49 +02:00
Michael Teeuw
c5a8b85f4e Merge branch 'master' into develop 2023-04-04 20:34:31 +02:00
Michael Teeuw
fa40a3e8e8 Prepare release 2.23.0 2023-04-04 20:13:45 +02:00
Veeck
6223584392 Add sendNotifications option to clock module (#3059)
Fixes #3056 

One question here would be if the default for this new option should be
true or false.

True: keeps the current behaviour, nobody needs to change his config if
they rely on this option

False: keeps the clock notifications quiet, doesnt waste time/resources,
keeps the noise low

Maybe the original author @cybex-dev can weigh in on this, and why he
added this notification.

---------

Co-authored-by: veeck <michael@veeck.de>
2023-04-01 21:40:32 +02:00
Veeck
b5a22bc09b Add sendNotifications option to clock module (#3059)
Fixes #3056 

One question here would be if the default for this new option should be
true or false.

True: keeps the current behaviour, nobody needs to change his config if
they rely on this option

False: keeps the clock notifications quiet, doesnt waste time/resources,
keeps the noise low

Maybe the original author @cybex-dev can weigh in on this, and why he
added this notification.

---------

Co-authored-by: veeck <michael@veeck.de>
2023-04-01 21:40:05 +02:00
Kristjan ESPERANTO
4ef030af5f Fix import order in serveronly (#3072)
To fix issue caused by #3071

In order to still fulfill the new linter rule `import/order`, I replaced
the alias with the path.

I also see two other approaches, but I opted for the simplest one here
for now.

The other approaches:
1. Also create an alias for `app`.
2. Use new `imports` (like in PR #2934), but let `_moduleAliases`
untouched to stay compatible to 3rd party modules.

**Edit**: Oh, I thought of another option:
- Add `require("module-alias/register");`
2023-03-25 10:59:57 +01:00
Kristjan ESPERANTO
5f38c53260 Revise require imports (#3071)
- order (external first)
- remove superfluous file extensions
- new line after imports
- deconstruct (only one time (in `check_config.js`))
- fix path (only one time (in `global-setup.js`))
2023-03-22 23:53:10 +01:00
Karsten Hassel
d5395ee3f8 update dependencies and main.css to match new stylelint rules (#3067)
On `develop` my css test failed because I was already on newest
dependencies.

- update deps
- update `main.css` because of stylelint issue

Co-authored-by: Veeck <github@veeck.de>
2023-03-20 22:30:04 +01:00
Kristjan ESPERANTO
ab0876f07a Update Eslint config, add new rule and handle issue (#3068) 2023-03-20 22:18:58 +01:00
Kristjan ESPERANTO
d276a7ddb9 Use template literals instead of string concatenation (#3066)
We have used it inconsistently till now. Template literals are more
modern and easier to maintain in my opinion.

Because that's a large amount of changes, here's a way to reproduce it:
I added the rule `"prefer-template": "error"` to the `.eslintrc.json`
and did an autofix. Since this caused a new problem in line 409 of
`newsfeed.js`, I reversed it in that line and also removed the rule from
the eslint config file.

The rule is described here:
https://eslint.org/docs/latest/rules/prefer-template

Note: I've played around with some other linter rules as well, and some
seem to point to some specific, non-cosmetic, issues. But before I dive
even deeper and then introduce even bigger and hardly understandable
changes at once, I thought I'd start with this simple cosmetic rule.
2023-03-19 14:32:23 +01:00
Nicholas Fogal
8f8945d418 Issue#3064 html alert title message (#3065)
Fixes [#3064](https://github.com/MichMich/MagicMirror/issues/3064)

- Fixes default alert module nunjucks templates to render HTML by
default unless 'titleType' and 'messageType' are set to 'text' in the
payload data

e.g. 

Display Text:
`this.sendNotification('SHOW_ALERT', {type: "notification", title:
"<u>YoLink LeakSensor</u>", titleType: "text", message: "<b>" +
deviceName + "</b> reported an alarm that needs attention.",
messageType: "text"});`

Display HTML:
`this.sendNotification('SHOW_ALERT', {type: "notification", title:
"<u>YoLink LeakSensor</u>", message: "<b>" + deviceName + "</b> reported
an alarm that needs attention."});`
2023-03-19 13:23:37 +01:00
Karsten Hassel
6d779235cf fix e2e tests (failed after async changes) (#3063)
by running calendar and newsfeed tests last.

Additional change: allow unit tests to run parallel

This is no fix of the real issue of calendar and newsfeed tests but I
moved them to the end of the tests so other tests are not failing
anymore.

There are coming follow up PR's for the real fixes (when I find the
culprits).

With these change we can stay with the async changes done by @rejas and
https://github.com/MichMich/MagicMirror/pull/3060 is obsolete.
2023-03-12 10:22:23 +01:00
buxxi
beea754514 Fix empty news feed stopping the feed from ever updating again (#3062)
If a news feed returns an empty file it will cause the feed to only show
the previous entries forever since no new fetch is scheduled.
2023-03-11 16:42:13 +01:00
Karsten Hassel
c6db22524a set all calendar colums to vertical align top (#3055)
The title column was vertical centered before.

Fixes #3053
2023-03-06 22:59:37 +01:00
Andrés Vanegas Jiménez
23ee155ded Fixed wind speed units for Open-Meteo Weather Provider (#3054)
Resolved technical debt for
[2964](https://github.com/MichMich/MagicMirror/pull/2964):

- Set wind speed unit to m/s
- Rename parameter `past_days` to `pastDays` to be consistent with all
configs
2023-03-01 09:38:38 +01:00
Veeck
1b2785cc56 Cleanup more callback things (#3051)
Looks quite stable on my computers, so maybe we give it a try?

---------

Co-authored-by: veeck <michael@veeck.de>
2023-02-26 18:36:47 +01:00
Veeck
b5b61246e6 Convert load callbacks to async/await (#3050)
Another one of these PRs....
2023-02-22 20:03:05 +01:00
Veeck
498b440174 Convert module-start to async (#3049)
Similar to the node_helper async start PR...

---------

Co-authored-by: veeck <michael@veeck.de>
2023-02-22 18:58:29 +01:00
Veeck
fe0b915a5d Convert app-start/-stop callbacks to async/await (#3035)
supersedes https://github.com/MichMich/MagicMirror/pull/3027 and just
touches the start/stop calls.

---------

Co-authored-by: veeck <michael@veeck.de>
2023-02-22 18:58:00 +01:00
Veeck
2b792cdbb8 Convert translator callbacks to async/await (#3048)
Co-authored-by: veeck <michael@veeck.de>
2023-02-21 22:58:18 +01:00
Thomas Hirschberger
a23769156e Show events of a configurable amount of past days (#3046)
Hi,

want to include a birthday calendar to my mirror which shows upcoming
birthdays and as a reminder birthdays of the last two days.
I used
[MMM-CalendarExt2](https://github.com/MMM-CalendarExt2/MMM-CalendarExt2)
for this job in the past but the module is not supported any more and
very complicated to configure.
I managed to style the default calendar module to my needs but what i am
missing is to display already past events within a configurable time
range.

I included the translations of "YESTERDAY" and "DAYBEFOREYESTERDAY" to
all translation files and modified the code to accept a new option
`pastDaysCount` which controls of how many days past events should be
displayed.

---------

Co-authored-by: Veeck <github@veeck.de>
2023-02-21 22:39:21 +01:00
Veeck
6d86ffade4 Fix rounding in precipitation percentage (#3045)
Percentage should be always rounded so that we dont get something like
"47.0000000001 %"

Some small typo and naming fixes also while I am here

---------

Co-authored-by: veeck <michael@veeck.de>
2023-02-20 20:04:40 +01:00
Veeck
390e5d6490 Update thai language (#3044)
actually add it to the tanslation list
and also add the alert translations from
https://github.com/MichMich/MagicMirror/pull/3029 since the OP didnt
seem to work on it (yet)

---------

Co-authored-by: veeck <michael@veeck.de>
Co-authored-by: Suthep Yonphimai <tomzt@users.noreply.github.com>
2023-02-20 20:03:42 +01:00
Kristjan ESPERANTO
b08a4737af Update stylelint (#3042)
1. Update `stylelint` dependencies
- As of stylelint v15, we do not need `stylelint-config-prettier`
anymore:
https://github.com/prettier/stylelint-config-prettier/releases/tag/v9.0.5
2. Switch to `stylelint-config-standard`:
`stylelint-prettier/recommended` has not been updated for a long time
and still needs the old `stylelint-config-prettier`
3. Handle new `stylelint` issues
2023-02-19 21:36:50 +01:00
Kristjan ESPERANTO
bf28e63709 Move th.json to translations folder (#3043) 2023-02-19 10:51:32 +01:00
Veeck
fb22a76796 Fix precipitation styles (#3041)
They weren't applied to wrong classnames, this PR fixes that and also
expands the weather util tests

---------

Co-authored-by: veeck <michael@veeck.de>
2023-02-18 18:24:11 +01:00
Veeck
81244d961e Update config sample and collab doc (#3039)
removing some old example and add info about the mastermerge label

---------

Co-authored-by: veeck <michael@veeck.de>
2023-02-17 19:49:36 +01:00
Veeck
65aa1b0ddc Update coverage and jest settings (#3038)
Co-authored-by: veeck <michael@veeck.de>
2023-02-16 22:29:43 +01:00
Veeck
88c7e42368 Enforce PRs to be based against develop branch (#3031)
"Inspired" by my mistake in
https://github.com/MichMich/MagicMirror/pull/3028 this PR will add a
worfklow check for the branch a PR is based against.

Open question is if this prevents @MichMich from preparing a release?

---------

Co-authored-by: veeck <michael@veeck.de>
2023-02-16 18:18:18 +01:00
CarJem Generations (Carter Wallace)
e24dfa6b1a Calendar Module QOL Features and Adjustments (#3033)
This commit adds several QOL features and adjustments to the calendar
module including:
- **New Options**
- ``coloredText``: ``(default: false)`` Determines if you want your
entry text to be colored based on the calendar's color
- ``coloredBorder``: ``(default: false)`` Determines if you want entry
borders to be colored based on the calendar's color
- ``coloredSymbol``: ``(default: false)`` Determines if you want entry
symbols to be colored based on the calendar's color
- ``coloredBackground``: ``(default: false)`` Determines if you want
entry backgrounds to be colored based on the calendar's color
> These new colored options allows for more out-of-box styling options
for the calendar module. With this the ``coloredSymbolOnly`` option has
been removed due to redundancy
- ``limitDaysNeverSkip``: ``(default: false)`` show every event for
every day regardless of if the day only has a single full day event
- ``flipDateHeaderTitle``: ``(default: false)`` determines if the title
for the date header in the ``dateheaders`` time format should align to
the left ``[eg: false]`` or right ``[eg: true]``
- **Layout Changes** 
- ``dateheader`` is now a class avaliable for date headers in the
``dateheaders`` time format.
- Event entries have been better *container-ized* for better styling
(using the ``event-container`` class)
- ``repeatingCountTitle`` now has a seperator between the ``yearDiff``
and ``repeatingCountTitle``
    - ``endDate`` in ``dateheaders`` now capitalizes it's first letter
2023-02-15 21:53:24 +01:00
Karsten Hassel
a65ee86501 Introduce envsubst for config.js, update deps (#3032)
This is the implemenation of envsubst discussed in #1756 

Documentation update will follow after merge.
2023-02-12 22:34:57 +01:00
Suthep Yonphimai
4b478a5a5e Create Thai Language file (#3028)
Create Thai Language file. 
Translation from English to Thai.

Co-authored-by: veeck <michael@veeck.de>
2023-02-07 09:25:18 +01:00
Veeck
1dc0a0d5b5 Update some tests (#3024)
Co-authored-by: veeck <michael@veeck.de>
2023-02-07 00:03:08 +01:00
Magnus
bf279d9a57 Tidy up precipitation (#3023)
Fixes #2953

This is an attempt to fix the issue with precipitation amount and
percentage mixup. I have created a separate
`precipitationPercentage`-variable where the probability of rain can be
stored.

The config options now has the old `showPrecipitationAmount` in addition
to a new setting: `showPrecipitationProbability` (shows the likelihood
of rain).

<details>
  <summary>Examples</summary>
  
  ### Yr

I tested the Yr weather provider for a Norwegian city Bergen that has a
lot of rain. I have removed properties that are irrelevant for this demo
from the config-samples below.

Config:
  ```js
{
	module: "weather",
	config: {
			weatherProvider: "yr",
			type: "current",
			showPrecipitationAmount: true,
			showPrecipitationProbability: true
	}
},
{
	module: "weather",
	config: {
			weatherProvider: "yr",
			type: "hourly",
			showPrecipitationAmount: true,
			showPrecipitationProbability: true
	}
},
{
	module: "weather",
	config: {
			weatherProvider: "yr",
			type: "daily",
			showPrecipitationAmount: true,
			showPrecipitationProbability: true
	}
}
  ```

Result:<br/>
<img width="444" alt="screenshot"
src="https://user-images.githubusercontent.com/34011212/216775423-4e37345c-f915-47e5-8551-7c544ebd24b1.png">

</details>

---------

Co-authored-by: Magnus Marthinsen <magmar@online.no>
Co-authored-by: Veeck <github@veeck.de>
2023-02-04 19:02:55 +01:00
Karsten Hassel
42d42ef452 Prevent electron flashing white screen on startup (#3001)
see #1919

thanks @dfanica for providing the solution in [this
comment](https://github.com/MichMich/MagicMirror/issues/1919#issuecomment-1369898385)

tested this on a pi4 with bullseye 32-bit and 64-bit
2023-01-26 22:16:50 +01:00
Veeck
ed90f0546f Fix async node_helper stopping electron start (#3021)
Async node_helper dont have to finish immediately in loadModules. So the
start callback in the app.js with the config isnt called for some time.
But the electron ready event can already be fired in the meantime.

This lead to the electron app starting but without a config (which is
provded by the node_helper callback) therefor crashing.

This PR fixes #2487 by moving the callback call out of the loadModules
block, therefor the config is provided in time.

If any new async node_helper doesnt like this, we will see it :-)

Co-authored-by: veeck <michael@veeck.de>
2023-01-26 19:44:54 +01:00
Veeck
a8dc563a31 Update weather tests (#3008)
Added a few tests for sunset/sunrise and feelsLike 
Lets see if they run through first...

Co-authored-by: veeck <michael@veeck.de>
2023-01-26 19:43:34 +01:00
Karsten Hassel
58b9ddcd9f updatenotification: only notify mm-repo for master if tag present (#3004)
see discussion here:
https://github.com/MichMich/MagicMirror/pull/2991#issuecomment-1376372720

I still see a need for updating `master` in special cases (e.g. correct
errors in README.md which would otherwise be present up to 3 month until
next release) so with this PR **only for MagicMirror repo** and **only
for `master` branch** updatenotifications are only triggered if at least
one of the new commits has a tag.

May @MichMich must decide if this is wanted.

Co-authored-by: Veeck <github@veeck.de>
2023-01-26 13:21:30 +01:00
Piotr Rajnisz
7198ae5eae Add (in Alert module) templateName parameter (#3009)
This simple change allows to use your own templates (under "templates"
directory). The parameter `templateName` is optional (ignored on falsy
value - undefined, null, empty string, etc.) and independent of `type`.

Co-authored-by: Veeck <github@veeck.de>
2023-01-26 13:00:49 +01:00
Patrick
f6dcfb5ca3 Refresh the Calendar DOM every minute (#3016)
This keeps relative dates accurate when the calendar's fetch frequency
is much larger than a minute.
As fetching incurs network traffic and load on servers and most
calendars don't update that often, simply refreshing locally is enough.

When using relative for today's events, dates will show as "in X
minutes" or "ends in X minutes" for events within an hour and this goes
out of date quickly. It's weird to see that the time is, say, 16:30 and
an event that you know ends at 16:45 is shown to "ends in 23 minutes"
because that's when the last fetch happened.

Please forgive me if there's style issue, I don't have npm set up on my
machine to run the formatter.
2023-01-26 12:55:34 +01:00
Karsten Hassel
157e74ce7c added error message if <modulename>.js file is missing … (#3015)
… in module folder to get a hint in the logs

fixes #2403
2023-01-26 12:45:17 +01:00
Magnus
67e4dbaacd Point wind arrow in the direction the wind is flowing (#3022)
Fixes #3019

The previous implementation had the arrow pointing in to the wind. When
the wind blows from the north (0 degrees), the arrow should point
straight down. In other words, no rotation of the arrow-down symbol.
When the wind blows from the south (180 degrees), the arrow should point
straight up (I.e. the arrow down symbol rotated 180 degrees).

Co-authored-by: Magnus Marthinsen <magmar@online.no>
2023-01-22 11:41:19 +01:00
Magnus
2e2962d492 Fix yr weather direction (#3020)
Fixes so the Yr weather direction is not inverted. This error was
[reported in the
community](https://forum.magicmirror.builders/topic/17561/wind-direction-180-degrees-twisted-at-yr).

I misunderstood when developing the module because of the wind direction
arrow was pointing opposite to the arrow displayed on Yr.no. I renamed
the variable to help other developers in the future.

Co-authored-by: Magnus Marthinsen <magmar@online.no>
Co-authored-by: veeck <michael@veeck.de>
2023-01-21 22:40:08 +01:00
grenagit
cd4ba428da [Alert Module] Fix HTML message (#3018)
Solve #2828 by adding nunjucks safe filter to the message

Co-authored-by: Grena <grena@grenabox.fr>
Co-authored-by: Veeck <github@veeck.de>
2023-01-21 12:46:03 +01:00
grenagit
ee8695637b Fix typo into french translation (#3017)
French translation: Removes unnecessary spaces
2023-01-21 12:40:20 +01:00
Dave Child
4244c05764 Fix calendar.js missing default symbol prefix (#3007)
Symbols provided in customEvents don't get the "fas fa-fw fa-" prefix,
which according to the docs they should. This fixes that.

Hello and thank you for wanting to contribute to the MagicMirror²
project

**Please make sure that you have followed these 4 rules before
submitting your Pull Request:**

> 1. Base your pull requests against the `develop` branch.
>
> 2. Include these infos in the description:
>
> - Does the pull request solve a **related** issue?
> - If so, can you reference the issue like this `Fixes
#<issue_number>`?
> - What does the pull request accomplish? Use a list if needed.
> - If it includes major visual changes please add screenshots.
>
> 3. Please run `npm run lint:prettier` before submitting so that
>    style issues are fixed.
>
> 4. Don't forget to add an entry about your changes to
>    the CHANGELOG.md file.

**Note**: Sometimes the development moves very fast. It is highly
recommended that you update your branch of `develop` before creating a
pull request to send us your changes. This makes everyone's lives
easier (including yours) and helps us out on the development team.

Thanks again and have a nice day!

Co-authored-by: veeck <michael@veeck.de>
2023-01-16 22:33:05 +01:00
Veeck
c714399b4d Fix weathergov provider hourly weather forecast (#3011)
Hourly forecast wasnt converted properly during the last release cycle,
one fix and two cleanups were necessary.

Fixes #3010

Co-authored-by: veeck <michael@veeck.de>
2023-01-16 21:52:11 +01:00
Karsten Hassel
8d9f132666 add Pirate Weather as new weather provider (#3006)
solves #3005 

- same api as former dark sky provider
- website: https://pirateweather.net/
2023-01-15 11:12:55 +01:00
Karsten Hassel
d2327d3d6f removed unneeded (and unwanted) '.' in calendar (#3003)
- removed unneeded (and unwanted) '.' after the year in calendar
repeatingCountTitle (fixes #2896)
- update Collaboration.md
2023-01-14 13:47:32 +01:00
Karsten Hassel
29e3ec06cb added possibility to ignore MagicMirror repo in updatenotification (#3002)
was [requested in the
forum](https://forum.magicmirror.builders/topic/17519/updatenotification).

- added possibility to exclude MagicMirror Repo and renamed it from
`default` to `MagicMirror`
- improved getting `behind` in case a hard `git fetch` was already done
- removed test "excludes repo if refs don't match regex" because of
above improvement this case is obsolete
- improved `git fetch --dry-run` with `-n` option to exclude tags (noise
reduction)
2023-01-12 09:14:20 +01:00
Veeck
877f8ad380 Refactor mock-data for weather-tests generation (#3000)
Refactored the mock data generation for the tests so we can use plain
JSON files for the data and read it in a more general way.

Comments welcome!

Co-authored-by: veeck <michael@veeck.de>
2023-01-11 21:47:20 +01:00
Veeck
6e80e5a295 Add option to show hourly forecast in increments (#2998)
Adds new config option to show weather forecast for every X hour
(default value is 1 which reflects the current behaviour)
Also adds tests for hourly forecast
Fixes #2996

Co-authored-by: veeck <michael@veeck.de>
2023-01-10 18:55:07 +01:00
Karsten Hassel
7bc91a742f Fix badge status (#2991) 2023-01-07 20:40:36 +01:00
Veeck
fc303146a5 Remove darksky weather provider (#2993)
since the web api gets shut down end of march, see
https://darksky.net/dev

Co-authored-by: veeck <michael@veeck.de>
2023-01-07 20:14:03 +01:00
Veeck
2908c15ea6 Cleanup md files (#2994)
Update the issue template and the contributing guidelines

Co-authored-by: veeck <michael@veeck.de>
2023-01-07 20:13:25 +01:00
Veeck
a975b44fbb Fix wrong day labels in envcanada forecast (#2992)
Fixes #2987

lastDate isnt a unix date, but just a normal moment-date

Co-authored-by: veeck <michael@veeck.de>
2023-01-07 20:12:23 +01:00
Veeck
4fc38bd5bb Update dependabot action (#2985)
Supersedes https://github.com/MichMich/MagicMirror/pull/2984 
and tell dependabot to base its PRs against develop
2023-01-02 20:11:26 +01:00
Michael Teeuw
c99f660d98 Prepare 2.23.0 develop branch. 2023-01-01 18:19:30 +01:00
Michael Teeuw
cd739b6912 Merge branch 'master' into develop 2023-01-01 18:02:15 +01:00
Michael Teeuw
0ebedd0fb8 Prepare Release 2.22.0 2023-01-01 17:57:13 +01:00
Andrés Vanegas Jiménez
e9be668d1b Added a WeatherProvider for Open-Meteo (#2964)
## Added Weather Provider for Open-Meteo.

I've found a completely free weather REST API (event with option of
self-hosting) after having problems with API keys from all MagicMirror
weather providers currently implemented (the remote services, not the
providers themselves).

This API doesn't return information about reverse geocode from latitude
and longitude options like others. I solved that issue using another
free API.

### APIs used
- [Open-Meteo Weather Forecast API](https://open-meteo.com/en/docs)
- [BigDataCloud’s Free Client-Side Reverse Geocoding
API](https://www.bigdatacloud.com/docs/api/free-reverse-geocode-to-city-api)

### Considerations
- This provider is config reliable so, be free to use the same config
you can found in the official MagicMirror Weather module documentation.
- This module config skips the `apiKey` parameter. It's not used at all.
Only `latitude` and `longitude` are required.

#### Config examples:
```
modules: [
  {
    module: "weather",
    position: "top_right",
    header: "Weather Forecast",
    config: {
      updateInterval: <number here>, 
      weatherProvider: "openmeteo",
      type: "current",
      lat: <number here>,
      lon: <number here>,
      showHumidity: true,
      showWindDirectionAsArrow: true,
      showWindDirection: true,
      degreeLabel: true,
    }
  },
  {
    module: "weather",
    position: "top_right",
    header: "Weather Forecast",
    config: {
      updateInterval: <number here>,
      weatherProvider: "openmeteo",
      type: "daily",
      lat: <number here>,
      lon: <number here>
      colored: true,
      maxNumberOfDays: <number here>,
      showPrecipitationAmount: true,
      appendLocationNameToHeader: true
    }
  },
  {
    module: "weather",
    position: "top_right",
    header: "Weather Forecast",
    config: {
      updateInterval: <number here>,
      weatherProvider: "openmeteo",
      type: "hourly",
      lat: <number here>,
      lon: <number here>,
      maxEntries: <number here>,
      showPrecipitationAmount: true,
      degreeLabel: true,
      appendLocationNameToHeader: true
    }
  },
]
```

Co-authored-by: Michael Teeuw <michael@xonaymedia.nl>
2022-12-26 11:56:01 +01:00
Karsten Hassel
76d9042e60 update playwright to v1.29.1 and other dependencies (#2980)
see title, fixes https://github.com/MichMich/MagicMirror/issues/2969
2022-12-22 16:40:53 +01:00
Karsten Hassel
2fec314ff5 improve electron tests (avoid errors in github workflows) (#2977)
Fix electron tests failing sometimes in github workflow.
2022-12-12 21:43:22 +01:00
Kristjan ESPERANTO
3124b0a9c5 Replace &hellip; with (#2973)
I think it is clearer if we don't use the HTML entity.

Co-authored-by: Karsten Hassel <hassel@gmx.de>
2022-12-10 21:50:56 +01:00
Veeck
a2624442cc Cleanup compliments module (#2965)
Lots of small fixes and cleanups:
- only render something when there is a compliment
- cleanup naming
- use es6 notations
- use fetch instead of XMLHttpRequest in compliments

Co-authored-by: veeck <michael@veeck.de>
Co-authored-by: Karsten Hassel <hassel@gmx.de>
2022-12-10 21:23:00 +01:00
Veeck
eee289aee8 Only add clock type wrappers to DOM when they are used (#2971)
Fixes a layout gap when digital clock is displayd on the left

Reported via discord:
https://discord.com/channels/545884423703494657/545884914982322177/1044376412997562418

Co-authored-by: veeck <michael@veeck.de>
2022-12-10 21:17:29 +01:00
Karsten Hassel
abbae90a8f update dependencies: electron to v22, fix playwright to v1.27.1 (#2976)
Changes:
- as discussed in #2903: update to electron v22 (we can revert it before
next release if we find any problems)
- update other dependencies
- set playwright to version v1.27.1 until #2969 is solved
2022-12-08 21:30:05 +01:00
Magnus
bd0b3c00ad New weather provider: Yr.no (#2948)
# Added Yr.no as a weather provider

Yr.no is a free Norwegian weather service. The configuration is quite
simple:
```js
{
    weatherProvider: "yr",
    lat: 59.9171,
    lon: 10.7276,
    altitude: 30
}
```
The latitude and longitude cannot have more than 4 decimals, but that
should be plenty. To quote yr: "There is no need to ask for weather
forecasts with nanometer precision!". The altitude should be meters
above sea level and defaults to 0. If `type` is set to `current` the
symbol can display the next 1, 6 or 12 hours by setting
`currentForecastHours` (default is 1).

It states in [Getting
started-guide](https://developer.yr.no/doc/GettingStarted/) that users
of the API should cache the results and use the `Expires`-header to know
when to ask for new data. By using the `If-Modified-Since`-header we can
avoid downloading the same data over and over again. I chose not to
override the `User-Agent`-header set in
[`server.js`](https://github.com/MichMich/MagicMirror/blob/a328ce5/js/server.js#L97)
even though it does not comply with [the terms of
service](https://developer.yr.no/doc/TermsOfService/). It currently
works with the default header, and by searching the web for MagicMirror
the GitHub-repo should be easy to find without an explicit link.

I also had to make some minor changes to `server.js` and
`weatherprovider.js` to be able to send and return HTTP headers. To
handle the HTTP 304 response without body I chose to return `undefined`
so we easily can use the response as a condition: `if (response) ...`.

The documentation for the API is available here:
- [API Reference overview](https://api.met.no/weatherapi/)
-
[Locationforecast](https://api.met.no/weatherapi/locationforecast/2.0/)
- Used to get the weather forecast
- [Sunrise](https://api.met.no/weatherapi/sunrise/2.0/documentation) -
used to find sunrise and sunset times

Co-authored-by: Veeck <github@veeck.de>
2022-11-08 06:18:47 +01:00
Thomas Hirschberger
b9b7d2c95d Add option to remove "x-frame-options" and "content-security-policy" response headers (#2963)
Many users like me do have the problem that they want to embed other
sites to their mirror by "iframe".
As some developers set the "x-frame-options" and
"content-security-policy" for security reasons these sites can not be
embedded.
Electron provides the "webview" element additionally to "iframe" which
allows to embed these sites although. The main difference is that a new
process is started which handles the "webview" element.
BUT: As the "webview" process needs to be started and is isolated
"webview" is slower and the elements can not be accessed from the
embedding website.

As an alternative i implemented a small callback function in electron.js
which removes the response headers that forbid the embedding.

The removing can be controlled with the new config options:
* ignoreXOriginHeader
* ignoreContentSecurityPolicy
2022-11-07 07:42:27 +01:00
veeck
0b01e9dbe0 Fix jsdoc error 2022-11-06 17:51:15 +01:00
Karsten Hassel
4fecffc3df Add Collaboration.md (#2954)
As already discussed here the first shot of the collaboration rules.

We can discuss this in the comments until ready to merge.

Co-authored-by: Veeck <github@veeck.de>
2022-10-31 14:27:31 +01:00
Magnus
4d47c0837f Support HTTP headers with CORS-method (#2957)
Adds support for sending and receiving HTTP-headers when using the
CORS-method.

This change is required for the Yr weather-provider introduced in
https://github.com/MichMich/MagicMirror/pull/2948.

To make it easier to add unit tests I moved the server-functions into a
separate file.
2022-10-30 18:14:02 +01:00
Veeck
3879949f58 Switch back to third party fetch lib for all node versions (#2961)
As discussed in https://github.com/MichMich/MagicMirror/pull/2952

Co-authored-by: veeck <michael@veeck.de>
2022-10-29 23:10:25 +02:00
buxxi
f25abfd2f8 Make the e2e tests wait for the app to start and close before running next test (#2952)
When trying to debug why the tests broke for
https://github.com/MichMich/MagicMirror/pull/2946 I found that the tests
does not wait for the app to start and close. So if the startup isn't
blocking that would fail.

So I added a callback for `close()` too and converted them to promises
for the `startApplication()` and `stopApplication()` and updated all the
e2e tests to await both. Will try to refactor all these callbacks to
promises in a later PR.
2022-10-29 22:34:17 +02:00
Veeck
7058fc5fd8 Update dependencies (#2960)
Co-authored-by: veeck <michael@veeck.de>
2022-10-28 21:51:18 +02:00
Naveen
00bc6eb28c Add dependency review action (#2862)
> Dependency Review GitHub Action in your repository to enforce
dependency
> reviews on your pull requests.
> The action scans for vulnerable versions of dependencies introduced by
package version
> changes in pull requests,
> and warns you about the associated security vulnerabilities.
> This gives you better visibility of what's changing in a pull request,
> and helps prevent vulnerabilities being added to your repository.


https://docs.github.com/en/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#dependency-review-enforcement
Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com>

Signed-off-by: naveen <172697+naveensrinivasan@users.noreply.github.com>
Co-authored-by: Karsten Hassel <hassel@gmx.de>
2022-10-28 21:16:42 +02:00
Veeck
f79d3f007d Cleanup jest config (#2959)
Some small cleanups with regards to jest
- call jest directly (nyc is integrated in jest these days)
- move jest config into seperate file so we dont clutter up the
package.json
- remove empty test file for newsletter-unit-tests
- update dependencies that touch jest
- try out v8 as coverageProvider

Co-authored-by: veeck <michael@veeck.de>
2022-10-28 20:57:08 +02:00
Veeck
c191ff0032 Refactor common weather methods into utils class (#2958)
Co-authored-by: veeck <michael@veeck.de>
2022-10-28 19:56:55 +02:00
Veeck
dde88601a6 Make sure smhi provider api only gets a maximimum of 6 digits coordinates (#2956)
Fixes #2955

Co-authored-by: veeck <michael@veeck.de>
2022-10-24 20:27:18 +02:00
Veeck
2d3940a4ff Use metric units internally in all weatherproviders (#2849)
So finally I think this refactorin is ready to be reviewed :-)

DONE:
- [x] Removed all conversion functions for wind and temperature from
specific weatherproviders
- [x] Use internally only metric units: celsius for temperature, meters
per seconds for wind
- [x] Convert temp and wind into the configured units when displaying
data on the UI
- [x] look how beaufort calculation uses metrics, added knots as new
windunit
- [x] add more e2e tests 

Checked providers:
- [x] Darksky
- [x] EnvCanada
- [x] OpenWeatherMap
- [x] SMHI provider 
- [x] UK Met Office
- [x] UK Met Office DataHub
- [x] WeatherBit
- [x] WeatherFlow
- [x] WeatherGov

TODO in different tickets:
- check weatherproviders for usage of weatherEndpoint (as seen in
https://github.com/MichMich/MagicMirror-Documentation/issues/131) -> see
#2926
- cleanup precipations -> #2953

Co-authored-by: veeck <michael@veeck.de>
2022-10-24 19:41:34 +02:00
Veeck
64ed5a54cb Add error handling to node_helper startup sequence (#2945)
Fixes https://github.com/MichMich/MagicMirror/issues/2944

Also splits the Server js into a constrcutor and an open call to remove
one callback parameter :-)

Co-authored-by: veeck <michael@veeck.de>
2022-10-19 21:40:43 +02:00
Karsten Hassel
7bd944391e fix cors problems with newsfeed articles (#2940)
solves #2840 as far as possible. There could still be errors on the
embedded iframe when the owner of the site has set `X-Frame-Options` or
`Access-Control-Allow-Origin` headers (as already mentioned in the
docs).
2022-10-17 21:38:08 +02:00
Karsten Hassel
ad4dbd786a added new electron tests supporting date mocking (#2947)
first PR for #2942 

- added new electron tests for calendar which test new css classes from
https://github.com/MichMich/MagicMirror/pull/2939
- moved some compliments tests from `e2e` to `electron` because of date
mocking
- removed mock stuff from compliments module
2022-10-17 07:20:23 +02:00
Veeck
fc59ed20e3 Convert moment(..., "X") to moment.unix(...) (#2950)
because I thought it was more readable and I found a little bug when
calculatin suntimes on the way....

Co-authored-by: veeck <michael@veeck.de>
2022-10-16 23:37:50 +02:00
Magnus
835c893205 Support for configuring FontAwesome class in calendar-module: (#2949)
Some icons in FontAwesome, like the Facebook-logo, requires a different
class than `fas fa-fw fa-`. Added support for specifying the
`className`:
```js
{
    symbol: "facebook-square",
    symbolClassName: "fab fa-",
    url: "https://www.facebook.com/events/ical/upcoming/?uid=<some_uid>"
}
```
2022-10-16 21:48:57 +02:00
Veeck
7bbf8c19db Wait till all node_helper are started before finishing startup (#2928)
In response to #2487 this implements a Promise.all for the node_helper
start calls

Co-authored-by: veeck <michael@veeck.de>
2022-10-13 21:38:04 +02:00
Dario Mratovich
1eb2965b2b Ensure updatenotification module isn't shown when local is *ahead* of remote (#2943)
This PR resolves a small bug in the updatenotification module if a local
git repo is ahead of the remote (for example I have made local commits
for my personal needs).

Currently, if `git status -sb` reports a status like: `##
master...origin/master [ahead 2]` then updatenotification treats this as
though it's "behind".

This PR uses a single Regex to match `git status -sb` output and uses
capture groups to extract info to populate the `gitInfo` object to avoid
needing to do string manipulation to extract this information.

Co-authored-by: Dario Mratovich <dario.mratovich@outlook.com>
2022-10-12 20:23:42 +02:00
Johan
85a9f14178 Added css class names "today" and "tomorrow" for calendar (#2939)
Added class names "today" and "tomorrow" on the calendar module tr
elements (i.e. calendar items).
This way you can for example color your events today and/or tomorrow to
more easily see what's happening in the near future.

Implemented by adding an event.tomorrow variable (similar to
event.today) that can be used for other things in the future. Also
replaced a few hardcoded values (hours, seconds etc.) with constants to
make the code more consistent.

Edit: tested with normal events, split day events and events with
locations.
2022-10-11 21:05:11 +02:00
Veeck
a328ce537f Cleanup test directory (#2937)
Moves files around and renames some so that the structure is cleaner and
more consistent
2022-10-07 12:16:37 -05:00
dWoolridge
21ae79b386 weathergov.js: Removed weatherEndpoint definition (#2936)
Removed weatherEnpoint definition in defaults. It is not used in the
weathergov.js provider.
2022-10-07 19:03:52 +02:00
Veeck
d5e855dd6d Use fetch instead of XMLHttpRequest in weatherprovider (#2935)
small update to the fetchData method to use the fetch helper instead of
the old XCMLHttpRequest.
Also fixes some typos :-)

Co-authored-by: veeck <michael@veeck.de>
2022-10-06 19:44:16 +02:00
dWoolridge
a86e27a12c Added fetchWeatherHourly functionality to Weather.gov provider (#2933)
Added fetchWeatherHourly functionality to:
 modules/default/weather/providers/weathergov.js
2022-10-06 09:56:32 +02:00
Veeck
f434be3d44 Update da.json (#2930)
as proposed in
05f0d1855c (commitcomment-85730050)

Co-authored-by: veeck <michael@veeck.de>
2022-10-06 09:41:52 +02:00
Veeck
ce4906d13b Add test in compliments module for remotFile option (#2932)
nothing fancy here, just a simple test after @khassel's changes to the
test setup :-)

Co-authored-by: veeck <michael@veeck.de>
2022-10-04 14:26:31 +02:00
Malte Hallström
8212d30c4c fix(weather/smhi) Correctly reference apparent temp method (#2931)
This PR addresses [this
comment](48756e8774 (commitcomment-85772193)),
which points out an issue with #2902.

Looks like the apparent temp calculation method was incorrectly
referenced 😅
2022-10-04 11:07:40 +02:00
Karsten Hassel
f04d578704 improve tests (#2923)
use es6 syntax in all tests, split weather tests, remove callbacks
2022-10-04 10:15:24 +02:00
Michael Teeuw
7694d6fa86 Prepare 2.22.0-develop 2022-10-01 20:14:26 +02:00
323 changed files with 16546 additions and 7469 deletions

View File

@@ -1 +0,0 @@
modules/default/calendar/vendor/*

View File

@@ -1,83 +0,0 @@
{
"extends": ["eslint:recommended", "plugin:@stylistic/all-extends", "plugin:import/recommended", "plugin:jest/recommended", "plugin:jsdoc/recommended"],
"plugins": [],
"env": {
"browser": true,
"es2023": true,
"jest/globals": true,
"node": true
},
"globals": {
"config": true,
"Log": true,
"MM": true,
"Module": true,
"moment": true
},
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 2023,
"ecmaFeatures": {
"globalReturn": true
}
},
"rules": {
"eqeqeq": "error",
"import/order": "error",
"import/extensions": "error",
"import/newline-after-import": "error",
"jest/consistent-test-it": "warn",
"jest/expect-expect": "warn",
"jest/no-done-callback": "warn",
"jest/prefer-expect-resolves": "warn",
"jest/prefer-mock-promise-shorthand": "warn",
"jest/prefer-to-be": "warn",
"jest/prefer-to-have-length": "warn",
"no-param-reassign": "error",
"no-prototype-builtins": "off",
"no-throw-literal": "error",
"no-unused-vars": "off",
"no-useless-return": "error",
"object-shorthand": ["error", "methods"],
"prefer-template": "error",
"@stylistic/array-element-newline": ["error", "consistent"],
"@stylistic/arrow-parens": ["error", "always"],
"@stylistic/brace-style": "off",
"@stylistic/comma-dangle": ["error", "never"],
"@stylistic/dot-location": ["error", "property"],
"@stylistic/function-call-argument-newline": ["error", "consistent"],
"@stylistic/function-paren-newline": ["error", "consistent"],
"@stylistic/implicit-arrow-linebreak": ["error", "beside"],
"@stylistic/max-statements-per-line": ["error", { "max": 2 }],
"@stylistic/multiline-ternary": ["error", "always-multiline"],
"@stylistic/newline-per-chained-call": ["error", { "ignoreChainWithDepth": 4 }],
"@stylistic/no-extra-parens": "off",
"@stylistic/no-tabs": "off",
"@stylistic/object-curly-spacing": ["error", "always"],
"@stylistic/object-property-newline": ["error", { "allowAllPropertiesOnSameLine": true }],
"@stylistic/operator-linebreak": ["error", "before"],
"@stylistic/padded-blocks": "off",
"@stylistic/quote-props": ["error", "as-needed"],
"@stylistic/quotes": ["error", "double"],
"@stylistic/indent": ["error", "tab"],
"@stylistic/semi": ["error", "always"],
"@stylistic/space-before-function-paren": ["error", "always"],
"@stylistic/spaced-comment": "off"
},
"overrides": [
{
"files": ["config/config.js*"],
"rules": {
"@stylistic/comma-dangle": "off",
"@stylistic/indent": "off",
"@stylistic/no-multi-spaces": "off"
}
},
{
"files": ["tests/configs/modules/weather/*.js"],
"rules": {
"@stylistic/quotes": "off"
}
}
]
}

137
.github/CODE_OF_CONDUCT.md vendored Normal file
View File

@@ -0,0 +1,137 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
- Demonstrating empathy and kindness toward other people
- Being respectful of differing opinions, viewpoints, and experiences
- Giving and gracefully accepting constructive feedback
- Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
- Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
- The use of sexualized language or imagery, and sexual attention or advances of
any kind
- Trolling, insulting or derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or email address,
without their explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official email address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement:
Contact [Rejas](https://forum.magicmirror.builders/user/rejas),
[Karsten](https://forum.magicmirror.builders/user/karsten13),
[Sam](https://forum.magicmirror.builders/user/sdetweil) or
[Kristjan](https://forum.magicmirror.builders/user/kristjanesperanto)
via private message in the forum.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View File

@@ -6,55 +6,33 @@ We hold our code to standard, and these standards are documented below.
## Linters
We use prettier for automatic linting of all our files: `npm run lint:prettier`.
We use [prettier](https://prettier.io/) for automatic formatting a lot all our files. The configuration is in our `prettier.config.mjs` file.
To run prettier, use `node --run lint:prettier`.
### JavaScript: Run ESLint
We use [ESLint](https://eslint.org) on our JavaScript files.
We use [ESLint](https://eslint.org) to lint our JavaScript files. The configuration is in our `eslint.config.mjs` file.
Our ESLint configuration is in our `.eslintrc.json` and `.eslintignore` files.
To run ESLint, use `npm run lint:js`.
To run ESLint, use `node --run lint:js`.
### CSS: Run StyleLint
We use [StyleLint](https://stylelint.io) to lint our CSS. Our configuration is in our `.stylelintrc` file.
We use [StyleLint](https://stylelint.io) to lint our CSS. The configuration is in our `stylelint.config.mjs` file.
To run StyleLint, use `npm run lint:css`.
To run StyleLint, use `node --run lint:css`.
### Markdown: Run markdownlint
We use [markdownlint-cli2](https://github.com/DavidAnson/markdownlint-cli2) to lint our markdown files. The configuration is in our `.markdownlint.json` file.
To run markdownlint, use `node --run lint:markdown`.
## Testing
We use [Jest](https://jestjs.io) for JavaScript testing.
To run all tests, use `npm run test`.
To run all tests, use `node --run test`.
The specific test commands are defined in `package.json`.
So you can also run the specific tests with other commands, e.g. `npm run test:unit` or `npx jest tests/e2e/env_spec.js`.
## Submitting Issues
Please only submit reproducible issues.
If you're not sure if it's a real bug or if it's just you, please open a topic on the forum: [https://forum.magicmirror.builders/category/15/bug-hunt](https://forum.magicmirror.builders/category/15/bug-hunt)
Problems installing or configuring your MagicMirror? Check out: [https://forum.magicmirror.builders/category/10/troubleshooting](https://forum.magicmirror.builders/category/10/troubleshooting)
When submitting a new issue, please supply the following information:
**Platform**: Place your platform here... give us your web browser/Electron version _and_ your hardware (Raspberry Pi 2/3/4, Windows, Mac, Linux, System V UNIX).
**Node Version**: Make sure it's version 18 or later (recommended is 20).
**MagicMirror² Version**: Please let us know which version of MagicMirror² you are running. It can be found in the `package.json` file.
**Description**: Provide a detailed description about the issue and include specific details to help us understand the problem. Adding screenshots will help describing the problem.
**Steps to Reproduce**: List the step by step process to reproduce the issue.
**Expected Results**: Describe what you expected to see.
**Actual Results**: Describe what you actually saw.
**Configuration**: What does the used config.js file look like? Don't forget to remove any sensitive information!
**Additional Notes**: Provide any other relevant notes not previously mentioned. This is optional.
So you can also run the specific tests with other commands, e.g. `node --run test:unit` or `npx jest tests/e2e/env_spec.js`.

View File

@@ -1,52 +0,0 @@
Hello and thank you for opening an issue.
**⚠️ Please make sure that you have read the following lines before submitting your Issue:**
## I'm not sure if this is a bug
If you're not sure if it's a real bug or if it's just you, please open a topic on the forum: [https://forum.magicmirror.builders/category/15/bug-hunt](https://forum.magicmirror.builders/category/15/bug-hunt)
## I'm having troubles installing or configuring MagicMirror
Problems installing or configuring your MagicMirror? Check out: [https://forum.magicmirror.builders/category/10/troubleshooting](https://forum.magicmirror.builders/category/10/troubleshooting)
A common problem is that your config file could be invalid. Please run in your MagicMirror² directory: `npm run config:check` and see if it reports an error.
## I found a bug in the MagicMirror² installer
If you are facing an issue or found a bug while trying to install MagicMirror² via the installer please report it in the respective GitHub repository:
[https://github.com/sdetweil/MagicMirror_scripts](https://github.com/sdetweil/MagicMirror_scripts)
## I found a bug in the MagicMirror² Docker image
If you are facing an issue or found a bug while running MagicMirror² inside a Docker container please create an issue in the corresponding repository:
[https://gitlab.com/khassel/magicmirror](https://gitlab.com/khassel/magicmirror)
## I'm having troubles installing or configuring foreign modules
Please open an issue in the module repository or ask for help in the [forum](https://forum.magicmirror.builders/)
---
## I found a bug in MagicMirror
Please make sure to only submit reproducible issues. You can safely remove everything above the dividing line.
When submitting a new issue, please supply the following information:
**Platform**: Place your platform here... give us your web browser/Electron version _and_ your hardware (Raspberry Pi 2/3/4, Windows, Mac, Linux, System V UNIX).
**Node Version**: Make sure it's version 18 or later (recommended is 20).
**MagicMirror² Version**: Please let us know which version of MagicMirror² you are running. It can be found in the `package.json` file.
**Description**: Provide a detailed description about the issue and include specific details to help us understand the problem. Adding screenshots will help describing the problem.
**Steps to Reproduce**: List the step by step process to reproduce the issue.
**Expected Results**: Describe what you expected to see.
**Actual Results**: Describe what you actually saw.
**Configuration**: What does the used config.js file look like? Don't forget to remove any sensitive information!
**Additional Notes**: Provide any other relevant notes not previously mentioned. This is optional.

154
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,154 @@
name: 🐛 Report a problem
description: Report an issue with MagicMirror² 🚨
title: "[Bug] {{ brief description }}"
labels:
- bug
body:
- type: markdown
attributes:
value: |
Thanks for reporting a bug! Please fill in the following template to help us reproduce the issue.
Please only submit reproducible issues. If you're not sure if it's a real bug or if it's just you, please open a topic on the forum.
- type: textarea
id: environment
attributes:
label: Environment
description: |
Please tell us about how your MagicMirror² is set up.
Optimal would be the systeminformation from the logs, which looks like this:
```bash
[2025-01-14 20:05:03.529] [INFO] System information:
### SYSTEM: manufacturer: Raspberry Pi Foundation; model: Raspberry Pi 4 Model B Rev 1.5; virtual: false
### OS: platform: linux; distro: Debian GNU/Linux; release: 12; arch: arm64; kernel: 6.1.21-v8+
### VERSIONS: electron: 31.2.1; used node: 20.15.0; installed node: 22.4.1; npm: 10.8.1; pm2:
### OTHER: timeZone: Europe/Berlin; ELECTRON_ENABLE_GPU: undefined
```
If you can't provide this information, please provide the following:
- MagicMirror² version: Can be found in the `package.json` file. Please use the latest version before reporting a bug.
- Node version: Run `node -v` to find out. Make sure it's version 20 or later (recommended is 22).
- npm version: Run `npm -v` to find out.
- Platform: Are you using a Raspberry Pi (2/3/4/5), Windows, Mac, Linux, Docker, or something else?
value: |
MagicMirror² version:
Node version:
npm version:
Platform:
validations:
required: true
- type: dropdown
id: start-option
attributes:
label: Which start option are you using?
description: |
Please keep in mind that some problems are specific to certain start options.
options:
- "node --run start"
- "node --run start:wayland"
- "node --run start:windows"
- "node --run start:x11"
- "node --run server"
- "node clientonly --address ... --port ..."
validations:
required: true
- type: dropdown
id: pm2
attributes:
label: Are you using PM2?
options:
- "No"
- "Yes"
- "I don't know"
validations:
required: true
- type: dropdown
id: module
attributes:
label: Module
description: |
If the issue is related to a specific module, please provide the name of the module.
Note: Please don't report issues with 3rd party modules here. Report them on the module's repository.
options:
- "alert"
- "calendar"
- "clock"
- "compliments"
- "helloworld"
- "newsfeed"
- "updatenotification"
- "weather"
- type: checkboxes
id: module-disabled
attributes:
label: Have you tried disabling other modules?
options:
- label: "Yes"
- label: "No"
- type: checkboxes
id: search
attributes:
label: Have you searched if someone else has already reported the issue on the forum or in the issues?
options:
- label: "Yes"
required: true
- type: textarea
id: description
attributes:
label: What did you do?
description: |
Please include a *minimal* reproduction case. List the step by step process to reproduce the issue.
You can use Markdown in this field.
value: |
<details>
<summary>Configuration</summary>
```
<!-- Paste your configuration here. Don't forget to remove any sensitive information! -->
```
</details>
```js
<!-- Paste relevant code here -->
```
Steps to reproduce the issue:
validations:
required: true
- type: textarea
id: expectation
attributes:
label: What did you expect to happen?
description: |
You can use Markdown in this field.
validations:
required: true
- type: textarea
id: lint-output
attributes:
label: What actually happened?
description: |
Please copy-paste relevant log output or error messages.
You can use Markdown in this field.
validations:
required: true
- type: textarea
id: comments
attributes:
label: Additional comments
description: |
Is there anything else that's important for the team to know?
Fill out all fields and provide as much information as possible.
Adding screenshots might help us understand your problem better.
- type: checkboxes
attributes:
label: Participation
options:
- label: "I am willing to submit a pull request for this change."
required: false
- type: markdown
attributes:
value: Please **do not** open a pull request until this issue has been accepted by the team.

View File

@@ -0,0 +1,41 @@
name: 🔀 Request a change
description: Request a change that is not a bug fix, a feature request or a support request.
title: "[Change Request] {{ brief description }}"
labels:
- enhancement
- core
body:
- type: markdown
attributes:
value: Thanks for requesting a change! Please fill in the following template to help us understand your request.
- type: textarea
attributes:
label: What problem do you want to solve with this change?
description: |
Please explain your use case in as much detail as possible.
placeholder: |
Currently...
validations:
required: true
- type: textarea
attributes:
label: What do you think is the correct solution?
description: |
Please explain how you'd like to change MagicMirror² to address the problem.
placeholder: |
I'd like MagicMirror² to...
validations:
required: true
- type: checkboxes
attributes:
label: Participation
options:
- label: I am willing to submit a pull request for this change.
required: false
- type: markdown
attributes:
value: Please **do not** open a pull request until this issue has been accepted by the team.
- type: textarea
attributes:
label: Additional comments
description: Is there anything else that's important for the team to know?

14
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,14 @@
blank_issues_enabled: false
contact_links:
- name: 📚 Documentation
url: https://github.com/MagicMirrorOrg/MagicMirror-Documentation/issues
about: This issue tracker is not for documentation issues. Please file documentation issues on the docs repo.
- name: 🤔 Support Question
url: https://forum.magicmirror.builders/
about: Problems installing or configuring your MagicMirror? Please post your question on the MagicMirror² Forum.
- name: 💬 Exchange of ideas
url: https://discord.gg/AmGBBwPph5
about: This issue tracker is not for general discussion. Please use the Discord channel.
- name: 📦 Issues with a 3rd-party module
url: https://kristjanesperanto.github.io/MagicMirror-3rd-Party-Modules/
about: This issue tracker is not for 3rd-party module issues. Please file 3rd-party module issues on the module's repo.

View File

@@ -0,0 +1,67 @@
name: 🚀 Feature Request
description: Suggest a new feature for MagicMirror² 💡
title: "[Feature Request] {{ brief description }}"
body:
- type: checkboxes
id: prerequisites
attributes:
label: Prerequisites
description: Please ensure you have completed all of the following.
options:
- label: I am running the latest version of MagicMirror², and know that this feature is not available now.
required: true
- label: I know my issue is not related to a third-party module.
required: true
- label: I have searched for [existing issues](https://github.com/MagicMirrorOrg/MagicMirror/issues) that already include this feature request, without success.
required: true
- type: textarea
id: description
attributes:
label: Describe the Feature Request
description: A clear and concise description of what the feature does.
validations:
required: true
- type: textarea
id: use-case
attributes:
label: Describe the Use Case
description: A clear and concise use case for what problem this feature would solve.
validations:
required: true
- type: textarea
id: proposed-solution
attributes:
label: Describe Preferred Solution
description: A clear and concise description of how you want this feature to be added to MagicMirror².
- type: textarea
id: alternatives-considered
attributes:
label: Describe Alternatives
description: A clear and concise description of any alternative solutions or features you have considered.
- type: textarea
id: related-code
attributes:
label: Related Code
description: If you are able to illustrate the feature request with an example, please provide a sample here.
- type: textarea
id: additional-information
attributes:
label: Additional Information
description: List any other information that is relevant to your issue. Related issues, suggestions on how to implement, Stack Overflow links, forum links, etc.
- type: checkboxes
attributes:
label: Participation
options:
- label: I am willing to submit a pull request for this change.
required: false
- type: markdown
attributes:
value: Please **do not** open a pull request until this issue has been accepted by the team.

View File

@@ -1,4 +1,4 @@
Hello and thank you for wanting to contribute to the MagicMirror² project
Hello and thank you for wanting to contribute to the MagicMirror² project!
**Please make sure that you have followed these 4 rules before submitting your Pull Request:**
@@ -10,7 +10,7 @@ Hello and thank you for wanting to contribute to the MagicMirror² project
> - What does the pull request accomplish? Use a list if needed.
> - If it includes major visual changes please add screenshots.
>
> 3. Please run `npm run lint:prettier` before submitting so that
> 3. Please run `node --run lint:prettier` before submitting so that
> style issues are fixed.
> 4. Don't forget to add an entry about your changes to
> the CHANGELOG.md file.

10
.github/codecov.yaml vendored
View File

@@ -1,10 +0,0 @@
coverage:
status:
project:
default:
# advanced settings
informational: true
patch:
default:
threshold: 0%
target: 0

View File

@@ -5,21 +5,16 @@ updates:
schedule:
interval: "weekly"
target-branch: "develop"
labels:
- "Skip Changelog"
- "dependencies"
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "monthly"
target-branch: "develop"
- package-ecosystem: "npm"
directory: "/vendor"
schedule:
interval: "monthly"
target-branch: "develop"
- package-ecosystem: "npm"
directory: "/fonts"
schedule:
interval: "monthly"
target-branch: "develop"
labels:
- "Skip Changelog"
- "dependencies"
- "javascript"

19
.github/stale.yaml vendored
View File

@@ -1,19 +0,0 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
- under investigation
- pr welcome
# Label to use when marking an issue as stale
staleLabel: wontfix
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

View File

@@ -13,29 +13,57 @@ permissions:
contents: read
jobs:
test:
code-style-check:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: "Checkout code"
uses: actions/checkout@v5
- name: "Use Node.js"
uses: actions/setup-node@v4
with:
node-version: lts/*
cache: "npm"
- name: "Install dependencies"
run: |
node --run install-mm:dev
- name: "Run linter tests"
run: |
node --run test:prettier
node --run test:js
node --run test:css
node --run test:markdown
test:
runs-on: ubuntu-24.04
timeout-minutes: 30
strategy:
matrix:
node-version: [18.x, 20.x, 21.x]
node-version: [22.14.0, 22.x, 24.x]
steps:
- name: Install electron dependencies and labwc
run: |
sudo apt-get update
sudo apt-get install -y libnss3 libasound2t64 labwc
- name: "Checkout code"
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: "Use Node.js ${{ matrix.node-version }}"
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
check-latest: true
cache: "npm"
- name: "Install dependencies"
- name: "Install MagicMirror²"
run: |
npm run install-mm:dev
node --run install-mm:dev
- name: "Prepare environment for tests"
run: |
# Fix chrome-sandbox permissions:
sudo chown root:root ./node_modules/electron/dist/chrome-sandbox
sudo chmod 4755 ./node_modules/electron/dist/chrome-sandbox
# Start labwc
WLR_BACKENDS=headless WLR_LIBINPUT_NO_DEVICES=1 WLR_RENDERER=pixman labwc &
touch css/custom.css
- name: "Run tests"
run: |
Xvfb :99 -screen 0 1024x768x16 &
export DISPLAY=:99
touch css/custom.css
npm run test:prettier
npm run test:js
npm run test:css
npm run test
export WAYLAND_DISPLAY=wayland-0
node --run test

View File

@@ -13,6 +13,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: "Checkout code"
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: "Dependency Review"
uses: actions/dependency-review-action@v3
uses: actions/dependency-review-action@v4

32
.github/workflows/electron-rebuild.yaml vendored Normal file
View File

@@ -0,0 +1,32 @@
name: "Electron Rebuild Testing"
on: [pull_request]
jobs:
rebuild:
name: Run electron-rebuild
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22.14.0, 22.x, 24.x]
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: "Use Node.js ${{ matrix.node-version }}"
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
check-latest: true
- name: Install MagicMirror
run: node --run install-mm
- name: Install @electron/rebuild
run: npm install @electron/rebuild
- name: Install node-libgpiod deps
run: |
sudo apt-get update
sudo apt-get install gpiod libgpiod2 libgpiod-dev
- name: Install test library (node-libgpiod) to be rebuilded
run: npm install node-libgpiod
- name: Run electron-rebuild
run: npx electron-rebuild
continue-on-error: false

View File

@@ -5,7 +5,7 @@
name: "Enforce Pull-Request Rules"
on:
pull_request:
pull_request_target:
types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled]
jobs:
@@ -19,10 +19,10 @@ jobs:
changeLogPath: "CHANGELOG.md"
skipLabels: "Skip Changelog"
- name: "Enforce develop branch"
if: ${{ github.base_ref == 'master' && !contains(github.event.pull_request.labels.*.name, 'mastermerge') }}
if: ${{ github.event.pull_request.base.ref == 'master' && !contains(github.event.pull_request.labels.*.name, 'mastermerge') }}
run: |
echo "This PR is based against the master branch and not a release or hotfix."
echo "Please don't do this. Switch the branch to 'develop'."
exit 1
env:
BASE_BRANCH: ${{ github.base_ref }}
BASE_BRANCH: ${{ github.event.pull_request.base.ref }}

31
.github/workflows/spellcheck.yaml vendored Normal file
View File

@@ -0,0 +1,31 @@
# This workflow will run a spellcheck on the codebase.
# It runs a few days before each release. At 00:00 on day-of-month 27 in March, June, September, and December.
name: Run Spellcheck
on:
schedule:
- cron: "0 0 27 3,6,9,12 *"
permissions:
contents: read
jobs:
spellcheck:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
with:
ref: develop
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: lts/*
check-latest: true
cache: "npm"
- name: Install dependencies
run: |
node --run install-mm:dev
- name: Run Spellcheck
run: node --run test:spelling

22
.github/workflows/stale.yaml vendored Normal file
View File

@@ -0,0 +1,22 @@
name: "Close stale issues and PRs"
on:
workflow_dispatch: # needed for manually running this workflow
schedule:
- cron: "30 1 * * 6" # every Saturday at 1:30
permissions:
issues: write
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
stale-issue-message: "This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions."
days-before-issue-stale: 60
days-before-issue-close: 7
operations-per-run: 100
stale-issue-label: "wontfix"
exempt-issue-labels: "pinned,security,under investigation,pr welcome,ready (coming with next release)"

17
.gitignore vendored
View File

@@ -10,8 +10,6 @@ coverage
.lock-wscript
build/Release
/node_modules/**/*
fonts/node_modules/**/*
vendor/node_modules/**/*
!/tests/node_modules/**/*
jspm_modules
.npm
@@ -63,8 +61,12 @@ Temporary Items
!/modules/default/**
!/modules/README.md**
# Ignore changes to the custom css files.
/css/custom.css
# Ignore changes to the custom css files but keep the sample and main.
/css/*
!/css/custom.css.sample
!/css/main.css
!/css/roboto.css
!/css/font-awesome.css
# Ignore users config file but keep the sample.
/config/*
@@ -79,3 +81,10 @@ Temporary Items
*.orig
*.rej
*.bak
# Ignore positions file (#3518)
js/positions.js
# Ignore lock files other than package-lock.json
pnpm-lock.yaml
yarn.lock

View File

@@ -1,7 +1,5 @@
#!/bin/sh
[ -f "$(dirname "$0")/_/husky.sh" ] && . "$(dirname "$0")/_/husky.sh"
if command -v npm &> /dev/null; then
npm run lint:staged
if command -v npx &> /dev/null; then
npx lint-staged
fi

6
.markdownlint.json Normal file
View File

@@ -0,0 +1,6 @@
{
"line_length": false,
"no-duplicate-heading": false,
"no-inline-html": false,
"no-trailing-punctuation": false
}

1
.npmrc
View File

@@ -1,2 +1,3 @@
engine-strict=true
audit=false
loglevel="error"

View File

@@ -1,4 +1,6 @@
*.js
*.mjs
.husky/pre-commit
.prettierignore
/config
/coverage

View File

@@ -1,3 +0,0 @@
{
"trailingComma": "none"
}

View File

@@ -1,7 +0,0 @@
{
"extends": ["stylelint-config-standard"],
"plugins": ["stylelint-prettier"],
"rules": {
"prettier/prettier": true
}
}

View File

@@ -1,11 +1,336 @@
# MagicMirror² Change Log
# Changelog
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](https://semver.org/).
❤️ **Donate:** Enjoying MagicMirror²? [Please consider a donation!](https://magicmirror.builders/donate) With your help we can continue to improve the MagicMirror².
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2.26.0] - 01-01-2024
❤️ **Donate:** Enjoying MagicMirror²? [Please consider a donation!](https://magicmirror.builders/#donate) With your help we can continue to improve the MagicMirror².
## [2.33.0] - unreleased
planned for 2025-10-01
Thanks to: @dathbe.
### Changed
- [clock] Add CSS to prevent line breaking of sunset/sunrise time display (#3816)
- [core] Enhance system information logging format and include additional env and RAM details (#3839, #3843)
- [refactor] Add new file `js/module_functions.js` to move code used in several modules to one place (#3837)
- [tests] refactor: simplify jest config file (#3844)
- [tests] refactor: extract constants for weather electron tests (#3845)
- [tests] replace `console` with `Log` in calendar `debug.js` to avoid exception in eslint config (#3846)
- [tests] speed up e2e tests, cleanup and stabilize weather e2e tests (#3847, #3848)
### Updated
- [core] Update dependencies including electron to v37 as well as github actions (#3831, #3849, #3857, #3858)
### Fixed
- [calendar] Fixed broken unittest that only broke on the 1st of July and 1st of january (#3830)
- [clock] Fixed missing icons when no other modules with icons is loaded (#3834)
- [weather] Fixed handling of empty values in weathergov providers handling of precipitationAmount (#3859)
## [2.32.0] - 2025-07-01
Thanks to: @bughaver, @bugsounet, @khassel, @KristjanESPERANTO, @plebcity, @rejas, @sdetweil.
> ⚠️ This release needs nodejs version `v22.14.0 or higher`
### Added
- [config] Allow to change module order for final renderer (or dynamically with CSS): Feature `order` in config (#3762)
- [clock] Added option 'disableNextEvent' to hide next sun event (#3769)
- [clock] Implement short syntax for clock week (#3775)
### Changed
- [refactor] Simplify module loading process (#3766)
- Use `node --run` instead of `npm run` (#3764) and adapt `start:dev` script (#3773)
- [workflow] Run linter and spellcheck with LTS node version (#3767)
- [workflow] Split "Run test" step into two steps for more clarity (#3767)
- [linter] Review linter setup (#3783)
- Fix command to lint markdown in `CONTRIBUTING.md`
- Re-activate JSDoc linting and fix linting issues
- Refactor ESLint config to use `defineConfig` and `globalIgnores`
- Replace `eslint-plugin-import` with `eslint-plugin-import-x`
- Switch Stylelint config to flat format and simplify Stylelint scripts
- [workflow] Replace Node.js version v23 with v24 (#3770)
- [refactor] Replace deprecated constants `fs.F_OK` and `fs.R_OK` (#3789)
- [refactor] Replace `ansis` with built-in function `util.styleText` (#3793)
- [core] Integrate stuff from `vendor` and `fonts` folders into main `package.json`, simplifies install and maintaining dependencies (#3795, #3805)
- [l10n] Complete translations (with the help of translation tools) (#3794)
- [refactor] Refactored `calendarfetcherutils` in Calendar module to handle timezones better (#3806)
- Removed as many of the date conversions as possible
- Use `moment-timezone` when calculating recurring events, this will fix problems from the past with offsets and DST not being handled properly
- Added some tests to test the behavior of the refactored methods to make sure the correct event dates are returned
- [linter] Enable ESLint rule `no-console` and replace `console` with `Log` in some files (#3810)
- [tests] Review and refactor translation tests (#3792)
### Fixed
- [fix] Handle spellcheck issues (#3783)
- [calendar] fix fullday event rrule until with timezone offset (#3781)
- [feat] Add rule `no-undef` in config file validation to fix #3785 (#3786)
- [fonts] Fix `roboto.css` to avoid error message `Unknown descriptor 'var(' in @font-face rule.` in firefox console (#3787)
- [tests] Fix and refactor e2e test `Same keys` in `translations_spec.js` (#3809)
- [tests] Fix e2e tests newsfeed and calendar to exit without open handles (#3817)
### Updated
- [core] Update dependencies including electron to v36 (#3774, #3788, #3811, #3804, #3815, #3823)
- [core] Update package type to `commonjs`
- [logger] Review factory code part: use `switch/case` instead of `if/else if` (#3812)
## [2.31.0] - 2025-04-01
Thanks to: @Developer-Incoming, @eltociear, @geraki, @khassel, @KristjanESPERANTO, @MagMar94, @mixasgr, @n8many, @OWL4C, @rejas, @savvadam, @sdetweil.
> ⚠️ This release needs nodejs version `v22.14.0 or higher`
### Added
- Add CSS support to the digital clock hour/minute/second through the use of the classes `clock-hour-digital`, `clock-minute-digital`, and `clock-second-digital`.
- Add Arabic (#3719) and Esperanto translation (#3740)
- Mark option `secondsColor` as deprecated in clock module.
- Add Greek translation to Alerts module.
- [newsfeed] Add specific ignoreOlderThan value (override) per feed (#3360)
- [weather] Added option Humidity to hourly View
- [weather] Added option to hide hourly entries that are Zero, hiding the entire column if empty.
- [updatenotification] Added option to iterate over modules directory instead using modules defined in `config.js` (#3739)
### Changed
- [core] Starting clientonly now checks for needed env var `WAYLAND_DISPLAY` or `DISPLAY` and starts electron with needed parameters (if both are set Wayland is used) (#3677)
- [core] Optimize systeminformation calls and output (#3689)
- [core] Add issue templates for feature requests and bug reports (#3695)
- [core] Adapt `start:x11:dev` script
- [weather/yr] The Yr weather provider now enforces a minimum `updateInterval` of 600 000 ms (10 minutes) to comply with the terms of service. If a lower value is set, it will be automatically increased to this minimum.
- [weather/weatherflow] Fixed icons and added hourly support as well as UV, precipitation, and location name support.
- [workflow] Run `sudo apt-get update` before installing packages to avoid install errors
- [workflow] Exclude issues with label `ready (coming with next release)` from stale job
### Removed
### Updated
- [core] Update requirements and dependencies including electron to v35 and formatting (#3593, #3693, #3717)
- [core] Update prettier, ESLint and simplify config
- Update Greek translation
### Fixed
- [calendar] Fix clipping events being broadcast (#3678)
- [tests] Fix Electron tests by running them under new github image ubuntu-24.04, replace xserver with labwc, running under xserver and labwc depending on env variable WAYLAND_DISPLAY is set (#3676)
- [calendar] Fix arrayed symbols, #3267, again, add testcase, add testcase for #3678
- [weather] Fix wrong weatherCondition name in openmeteo provider which lead to n/a icon (#3691)
- [core] Fix wrong port in log message when starting server only (#3696)
- [calendar] Fix NewYork event processed on system in Central timezone shows wrong time #3701
- [weather/yr] The Yr weather provider is now able to recover from bad API responses instead of freezing (#3296)
- [compliments] Fix evening events being shown during the day (#3727)
- [weather] Fixed minor spacing issues when using UV Index in Hourly
- [workflow] Fix command to run spellcheck
## [2.30.0] - 2025-01-01
Thanks to: @xsorifc28, @HeikoGr, @bugsounet, @khassel, @KristjanESPERANTO, @rejas, @sdetweil.
> ⚠️ This release needs nodejs version `v20` or `v22 or higher`, minimum version is `v20.18.1`
### Added
- [core] Add Wayland and Windows start options to `package.json` (#3594)
- [docs] Add step for npm publishing in release process (#3595)
- [core] Add GitHub workflow to run spellcheck a few days before each release (#3623)
- [core] Add test flag to `index.html` to pass to module js for test mode detection (needed by #3630)
- [core] Add export on animation names (#3644)
- [compliments] Add support for refreshing remote compliments file, and test cases (#3630)
- [linter] Re-add `eslint-plugin-import`now that it supports ESLint v9 (#3586)
- [linter] Re-activate `eslint-plugin-package-json` to lint `package.json` (#3643)
- [linter] Add linting for markdown files (#3646)
- [linter] Add some handy ESLint rules (#3665)
- [calendar] Add ability to display end date for full date events, where end is not same day (showEnd=true) (#3650)
- [core] Add text to the config.js.sample file about the locale variable (#3654, #3655)
- [core] Add fetch timeout for all node_helpers (thru undici, forces node 20.18.1 minimum) to help on slower systems. (#3660) (3661)
### Changed
- [core] Run code style checks in workflow only once (#3648)
- [core] Fix animations export #3644 only on server side (#3649)
- [core] Use project URL in fallback config (#3656)
- [core] Fix Access Denied crash writing js/positions.js (on synology nas) #3651. new message, MM starts, but no modules showing (#3652)
- [linter] Switch to 'npx' for lint-staged in pre-commit hook (#3658)
### Removed
- [tests] Remove `node-pty` and `drivelist` from rebuilded test (#3575)
- [deps] Remove `@eslint/js` dependency. Already installed with `eslint` in deep (#3636)
### Updated
- [repo] Reactivate `stale.yaml` as GitHub action to mark issues as stale after 60 days and close them 7 days later (if no activity) (#3577, #3580, #3581)
- [core] Update electron dependency to v32 (test electron rebuild) and all other dependencies too (#3657)
- [tests] All test configs have been updated to allow full external access, allowing for easier debugging (especially when running as a container)
- [core] Run and test with node 23 (#3588)
- [workflow] delete exception `allow-ghsas: GHSA-8hc4-vh64-cxmj` in `dep-review.yaml` (#3659)
### Fixed
- [updatenotification] Fix pm2 using detection when pm2 script is inside or outside MagicMirror root folder (#3576) (#3605) (#3626) (#3628)
- [core] Fix loading node_helper of modules: avoid black screen, display errors and continue loading with next module (#3578)
- [weather] Change default value for weatherEndpoint of provider openweathermap to "/onecall" (#3574)
- [tests] Fix electron tests with mock dates, the mock on server side was missing (#3597)
- [tests] Fix testcases with hard coded Date.now (#3597)
- [core] Fix missing `basePath` where `location.host` is used (#3613)
- [compliments] croner library changed filenames used in latest version (#3624)
- [linter] Fix ESLint ignore pattern which caused that default modules not to be linted (#3632)
- [core] Fix module path in case of sub/sub folder is used and use path.resolve for resolve `moduleFolder` and `defaultModuleFolder` in app.js (#3653)
- [calendar] Update to resolve issues #3098 #3144 #3351 #3422 #3443 #3467 #3537 related to timezone changes
- [calendar] Fix #3267 (styles array), also fixes event with both exdate AND recurrence(and testcase)
- [calendar] Fix showEndsOnlyWithDuration not working, #3598, applies ONLY to full day events
- [calendar] Fix showEnd for Full Day events (#3602)
- [tests] Suppress "module is not defined" in e2e tests (#3647)
- [calendar] Fix #3267 (styles array, really this time!)
- [core] Fix #3662 js/positions.js created incorrectly
## [2.29.0] - 2024-10-01
Thanks to: @bugsounet, @dkallen78, @jargordon, @khassel, @KristjanESPERANTO, @MarcLandis, @rejas, @ryan-d-williams, @sdetweil, @skpanagiotis.
> ⚠️ This release needs nodejs version `v20` or `v22`, minimum version is `v20.9.0`
### Added
- [compliments] Added support for cron type date/time format entries mm hh DD MM dow (minutes/hours/days/months and day of week) see <https://crontab.cronhub.io> for construction (#3481)
- [core] Check config at every start of MagicMirror² (#3450)
- [core] Add spelling check (cspell): `npm run test:spelling` and handle spelling issues (#3544)
- [core] removed `config.paths.vendor` (could not work because `vendor` is hardcoded in `index.html`), renamed `config.paths.modules` to `config.foreignModulesDir`, added variable `MM_CUSTOMCSS_FILE` which - if set - overrides `config.customCss`, added variable `MM_MODULES_DIR` which - if set - overrides `config.foreignModulesDir`, added test for `MM_MODULES_DIR` (#3530)
- [core] elements are now removed from `index.html` when loading script or stylesheet files fails
- [core] Added `MODULE_DOM_UPDATED` notification each time the DOM is re-rendered via `updateDom` (#3534)
- [tests] added minimal needed node version to tests (currently v20.9.0) to avoid releases with wrong node version info
- [tests] Added `node-libgpiod` library to electron-rebuild tests (#3563)
### Removed
- [core] removed installer only files (#3492)
- [core] removed raspberry object from systeminformation (#3505)
- [linter] removed `eslint-plugin-import`, because it doesn't support ESLint v9. We will reenter it later when it does.
- [tests] removed `onoff` library from electron-rebuild tests (#3563)
### Updated
- [weather] Updated `apiVersion` default from 2.5 to 3.0 (#3424)
- [core] Updated dependencies including stylistic-eslint
- [core] nail down `node-ical` version to `0.18.0` with exception `allow-ghsas: GHSA-8hc4-vh64-cxmj` in `dep-review.yaml` (which should removed after next `node-ical` update)
- [core] Updated SocketIO catch all to new API
- [core] Allow custom modules positions by scanning index.html for the defined regions, instead of hard coded (PR #3518 fixes issue #3504)
- [core] Detail optimizations in `config_check.js`
- [core] Updated minimal needed node version in `package.json` (currently v20.9.0) (#3559) and except for v21 (no security updates) (#3561)
- [linter] Switch to ESLint v9 and flat config and replace `eslint-plugin-unicorn` by `@eslint/js`
- [core] Fix discovering module positions twice after #3450
### Fixed
- [docs] Fixed `checks` badge in README.md
- [weather] Fixed issue with the UK Met Office provider following a change in their API paths and header info.
- [core] Add check for node_helper loading for multiple instances of same module (#3502)
- [weather] Fixed issue for respecting unit config on broadcasted notifications
- [tests] Fixes calendar test by moving it from e2e to electron with fixed date (#3532)
- [calendar] fixed sliceMultiDayEvents getting wrong count and displaying incorrect entries, Europe/Berlin (#3542)
- [tests] ignore `js/positions.js` when linting (this file is created at runtime)
- [calendar] fixed sliceMultiDayEvents showing previous day without config enabled
## [2.28.0] - 2024-07-01
Thanks to: @btoconnor, @bugsounet, @JasonStieber, @khassel, @kleinmantara and @WallysWellies.
> ⚠️ This release needs nodejs version >= v20.9.0
### Added
- [calendar] Added config option "showEndsOnlyWithDuration" for default calendar
- [compliments] Added `specialDayUnique` config option, defaults to `false` (#3465)
- [weather] Provider weathergov: Use `precipitationLast3Hours` if `precipitationLastHour` is `null` (#3124)
### Removed
- [tests] delete node v18 support (#3462)
### Updated
- [core] Update dependencies including electron to v31
- [core] use node >= v20 (#3462)
- [core] Update `config.js.sample` to use openmeteo as weather provider which needs no api key
- [tests] Use latest@version of node for `automated-tests.yaml` (#3483)
- [updatenotification] Avoid using pm2 when running in docker container
### Fixed
- [core] Fixed crash possibility if `module: <name>` is not defined and on `position: <position>` mistake (#3445)
- [weather] Fixed precipitationProbability in forecast for provider openmeteo (#3446)
- [weather] Fixed type=daily for provider openmeteo having no data when running after 23:00 (#3449)
- [weather] Fixed type=daily for provider openmeteo showing nightly icons in forecast when current time is "nightly" (#3458)
- [weather] Fixed forecast and hourly weather for provider openmeteo to use real temperatures, not apparent temperatures (#3466)
- [tests] Fixed e2e tests running in docker container which needs `address: "0.0.0.0"` (#3479)
## [2.27.0] - 2024-04-01
Thanks to: @bugsounet, @crazyscot, @illimarkangur, @jkriegshauser, @khassel, @KristjanESPERANTO, @Paranoid93, @rejas, @sdetweil and @vppencilsharpener.
This release marks the first release without Michael Teeuw (@michmich). A very special thanks to him for creating MagicMirror and leading the project for so many years.
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
- Output of system information to the console for troubleshooting (#3328 and #3337), ignore errors under aarch64 (#3349)
- [core] Add `eslint-plugin-package-json` to lint the `package.json` files (#3368)
- [weather] `showHumidity` config is now a string describing where to show this element. Supported values: "wind", "temp", "feelslike", "below", "none". (#3330)
- electron-rebuild test suite for electron and 3rd party modules compatibility (#3392)
- Create MM² icon and attach it to electron process (#3407)
### Updated
- [updatenotification] Recode update_helper.js with pm2 library (#3332)
- Removing lodash dependency by replacing merge by spread operator (#3339)
- Use node prefix for build-in modules (#3340)
- Rework logging colors (#3350)
- Update pm2 to v5.3.1 with no allow-ghsas (#3364)
- [core] Update husky and let lint-staged fix ESLint issues
- [core] Update dependencies including electron to v29 (#3357) and node-ical
- Update translations for estonian (#3371)
- Update electron to v29 and update other dependencies
- [calendar] fullDay events over several days now show the left days from the first day on and 'today' on the last day
- Update layout of current weather indoor values
### Fixed
- [weather] Correct apiBase of weathergov weatherProvider to match documentation (#2926)
- Worked around several issues in the RRULE library that were causing deleted calender events to still show, some
initial and recurring events to not show, and some event times to be off an hour. (#3291)
- Skip changelog requirement when running tests for dependency updates (#3320)
- Display precipitation probability when it is 0% instead of blank/empty (#3345)
- [newsfeed] Suppress unsightly animation cases when there are 0 or 1 active news items (#3336)
- [newsfeed] Always compute the feed item URL using the same helper function (#3336)
- Ignore all custom css files (#3359)
- [newsfeed] Fix newsfeed stall issue introduced by #3336 (#3361)
- Changed `log.debug` to `log.log` in `app.js` where logLevel is not set because config is not loaded at this time (#3353)
- [calendar] deny fetch interval < 60000 and set 60000 in this case (prevent fetch loop failed) (#3382)
- added message in case where config.js is missing the module.export line PR #3383
- Fixed an issue where recurring events could extend past their recurrence end date (#3393)
- Don't display any `npm WARN <....>` on install (#3399)
- [core] Moved suncalc dependency to production from dev, as it is used by clock module
- [compliments] Fix mirror not responding anymore when no compliments are to be shown (#3385)
- [core] Fixed mastermerge workflow (#3415)
### Deleted
- Unneeded file headers (#3358)
- Removed codecov.yaml
## [2.26.0] - 2024-01-01
Thanks to: @bnitkin, @bugsounet, @dependabot, @jkriegshauser, @kaennchenstruggle, @KristjanESPERANTO and @Ybbet.
@@ -32,7 +357,7 @@ This release also marks the latest release by Michael Teeuw. For more info, plea
- 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
- Update 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)
@@ -48,8 +373,8 @@ This release also marks the latest release by Michael Teeuw. For more info, plea
- 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 electron loadURL locally on Windows when address "0.0.0.0" (#2550)
- Fix updatenotification (update_helper.js): catch error if response 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
@@ -124,8 +449,8 @@ Special thanks to @khassel, @rejas and @sdetweil for taking over most (if not al
- Added tests for serveronly
- Set Timezone `Europe/Berlin` in unit tests (needed for new formatTime tests)
- Added no-param-reassign eslint rule and fix warnings
- updatenotification: Added `sendUpdatesNotifications` feature. Broadcast update with `UPDATES` notification to other modules
- updatenotification: allow force scanning with `SCAN_UPDATES` notification from other modules
- [updatenotification] Added `sendUpdatesNotifications` feature. Broadcast update with `UPDATES` notification to other modules
- [updatenotification] Allow force scanning with `SCAN_UPDATES` notification from other modules
- Added per-calendar fetchInterval
### Removed
@@ -134,7 +459,7 @@ Special thanks to @khassel, @rejas and @sdetweil for taking over most (if not al
### Updated
- Added support for precipitation probability with openmeteo weather-provider
- [weather] Added support for precipitation probability with openmeteo weather-provider
- Update electron to v25.2 and other dependencies
- Use node v20 in github workflow (replacing v14)
- Refactor formatTime into common util function for default modules
@@ -307,7 +632,7 @@ Special thanks to the following contributors: @eouia, @khassel, @kolbyjack, @Kri
### Added
- Added a new config option `httpHeaders` used by helmet (see https://helmetjs.github.io/). You can now set own httpHeaders which will override the defaults in `js/defauls.js` which is useful e.g. if you want to embed MagicMirror into annother website (solves #2847).
- Added a new config option `httpHeaders` used by helmet (see <https://helmetjs.github.io/>). You can now set own httpHeaders which will override the defaults in `js/defaults.js` which is useful e.g. if you want to embed MagicMirror into another website (solves #2847).
- Show endDate for calendar events when dateHeader is enabled and showEnd is set to true (#2192).
- Added the notification emitting from the weather module on information updated.
- Use recommended file extension for YAML files (#2864).
@@ -356,7 +681,7 @@ Special thanks to the following contributors: @10bias, @CFenner, @JHWelch, @k1rd
- Fix minor console output issue for loading translations (#2814).
- Don't adjust startDate for full day events if endDate is in the past.
- Fix windspeed conversion error in openweathermap provider. (#2812)
- Fix conflicting parms turning off showEnd for full day events. (#2629)
- Fix conflicting parameter turning off showEnd for full day events. (#2629)
- Fix regression, calendar.maximumEntries not used to filter calendar level entries (#2868)
## [2.18.0] - 2022-01-01
@@ -388,7 +713,7 @@ Special thanks to the following contributors: @AmpioRosso, @eouia, @fewieden, @j
### Fixed
- Fixed wrong file `kr.json` to `ko.json`. Use language code 'ko' instead of 'kr' for Korean language.
- Fixed `feels_like` data from openweathermaps current weather being ignored (#2678).
- Fixed `feels_like` data from openweathermap's current weather being ignored (#2678).
- Fixed chaotic newsfeed display after network connection loss thanks to @jalibu (#2638).
- Fixed incorrect time zone correction of recurring full day events (#2632 and #2634).
- Fixed e2e tests by increasing testTimeout.
@@ -425,7 +750,7 @@ Special thanks to the following contributors: @apiontek, @eouia, @jupadin, @khas
- Updated github templates.
- Actually test all js and css files when lint script is run.
- Updated jsdocs and print warnings during testing too.
- Updated weathergov provider to try fetching not just current, but also foreacst, when API URLs available.
- Updated weathergov provider to try fetching not just current, but also forecast, when API URLs available.
- Refactored clock layout.
- Refactored methods from weather-providers into weatherobject (isDaytime, updateSunTime).
- Use of `logger.js` in jest tests.
@@ -652,12 +977,12 @@ Special thanks to the following contributors: @bryanzzhu, @bugsounet, @chamakura
### Fixed
- Fix backward compatibility issues for Safari < 11.
- Fix the use of "maxNumberOfDays" in the module "weatherforecast depending on the endpoint (forecast/daily or forecast)". [#2018](https://github.com/MichMich/MagicMirror/issues/2018)
- Fix calendar display. Account for current timezone. [#2068](https://github.com/MichMich/MagicMirror/issues/2068)
- Fix the use of "maxNumberOfDays" in the module "weatherforecast depending on the endpoint (forecast/daily or forecast)". [#2018](https://github.com/MagicMirrorOrg/MagicMirror/issues/2018)
- Fix calendar display. Account for current timezone. [#2068](https://github.com/MagicMirrorOrg/MagicMirror/issues/2068)
- Fix logLevel being set before loading config.
- Fix incorrect namespace links in svg clockfaces. [#2072](https://github.com/MichMich/MagicMirror/issues/2072)
- Fix weather/providers/weathergov for API guidelines. [#2045](https://github.com/MichMich/MagicMirror/issues/2045)
- Fix "undefined" in weather modules header. [#1985](https://github.com/MichMich/MagicMirror/issues/1985)
- Fix incorrect namespace links in svg clockfaces. [#2072](https://github.com/MagicMirrorOrg/MagicMirror/issues/2072)
- Fix weather/providers/weathergov for API guidelines. [#2045](https://github.com/MagicMirrorOrg/MagicMirror/issues/2045)
- Fix "undefined" in weather modules header. [#1985](https://github.com/MagicMirrorOrg/MagicMirror/issues/1985)
- Fix #2110, #2111, #2118: Recurring full day events should not use timezone adjustment. Just compare month/day.
## [2.12.0] - 2020-07-01
@@ -691,14 +1016,14 @@ Special thanks to the following contributors: @AndreKoepke, @andrezibaia, @bryan
### Fixed
- The broken modules due to Socket.io change from last release. [#1973](https://github.com/MichMich/MagicMirror/issues/1973)
- Add backward compatibility for old module code in socketclient.js. [#1973](https://github.com/MichMich/MagicMirror/issues/1973)
- Support multiple instances of calendar module with different config. [#1109](https://github.com/MichMich/MagicMirror/issues/1109)
- Fix the use of "maxNumberOfDays" in the module "weatherforecast". [#2018](https://github.com/MichMich/MagicMirror/issues/2018)
- Throw error when check_config fails. [#1928](https://github.com/MichMich/MagicMirror/issues/1928)
- Bug fix related to 'maxEntries' not displaying Calendar events. [#2050](https://github.com/MichMich/MagicMirror/issues/2050)
- Updated ical library to the latest version. [#1926](https://github.com/MichMich/MagicMirror/issues/1926)
- Fix config check after merge of prettier [#2109](https://github.com/MichMich/MagicMirror/issues/2109)
- The broken modules due to Socket.io change from last release. [#1973](https://github.com/MagicMirrorOrg/MagicMirror/issues/1973)
- Add backward compatibility for old module code in socketclient.js. [#1973](https://github.com/MagicMirrorOrg/MagicMirror/issues/1973)
- Support multiple instances of calendar module with different config. [#1109](https://github.com/MagicMirrorOrg/MagicMirror/issues/1109)
- Fix the use of "maxNumberOfDays" in the module "weatherforecast". [#2018](https://github.com/MagicMirrorOrg/MagicMirror/issues/2018)
- Throw error when check_config fails. [#1928](https://github.com/MagicMirrorOrg/MagicMirror/issues/1928)
- Bug fix related to 'maxEntries' not displaying Calendar events. [#2050](https://github.com/MagicMirrorOrg/MagicMirror/issues/2050)
- Updated ical library to the latest version. [#1926](https://github.com/MagicMirrorOrg/MagicMirror/issues/1926)
- Fix config check after merge of prettier [#2109](https://github.com/MagicMirrorOrg/MagicMirror/issues/2109)
## [2.11.0] - 2020-04-01
@@ -706,7 +1031,7 @@ Special thanks to the following contributors: @AndreKoepke, @andrezibaia, @bryan
In the past years the project has grown a lot. This came with a huge downside: poor maintainability. If I let the project continue the way it was, it would eventually crash and burn. More important: I would completely lose the drive and interest to continue the project. Because of this the decision was made to simplify the core by removing all side features like automatic installers and support for exotic platforms. This release (2.11.0) is the first real release that will reflect (parts) of these changes. As a result of this, some things might break. So before you continue make sure to backup your installation. Your config, your modules or better yet: your full MagicMirror² folder. In other words: update at your own risk.
For more information regarding this major change, please check issue [#1860](https://github.com/MichMich/MagicMirror/issues/1860).
For more information regarding this major change, please check issue [#1860](https://github.com/MagicMirrorOrg/MagicMirror/issues/1860).
### Deleted
@@ -736,8 +1061,8 @@ For more information regarding this major change, please check issue [#1860](htt
- Fix calendar time offset for recurring events crossing Daylight Savings Time (ISSUE #1798)
- Fix regression in currentweather module causing 'undefined' to show up when config.hideTemp is false
- Fix FEELS translation for Croatian
- Fixed weather tests [#1840](https://github.com/MichMich/MagicMirror/issues/1840)
- Fixed Socket.io can't be used with Reverse Proxy in serveronly mode [#1934](https://github.com/MichMich/MagicMirror/issues/1934)
- Fixed weather tests [#1840](https://github.com/MagicMirrorOrg/MagicMirror/issues/1840)
- Fixed Socket.io can't be used with Reverse Proxy in serveronly mode [#1934](https://github.com/MagicMirrorOrg/MagicMirror/issues/1934)
- Fix update checking skipping 3rd party modules the first time
### Changed
@@ -775,7 +1100,7 @@ Special thanks to @sdetweil for all his great contributions!
### Updated
- Updated lower bound of `lodash` and `helmet` dependencies for security patches.
- Updated compliments.js to handle newline in text, as textfields to not interpolate contents.
- Updated compliments.js to handle newline in text, as text fields to not interpolate contents.
- Updated raspberry.sh installer script to handle new platform issues, split node/npm, pm2, and screen saver changes.
- Improve handling for armv6l devices, where electron support has gone away, add optional serveronly config option.
- Improved run-start.sh to handle for serveronly mode, by choice, or when electron not available.
@@ -805,14 +1130,14 @@ Special thanks to @sdetweil for all his great contributions!
- Updatenotification module: Display update notification for a limited (configurable) time.
- Enabled e2e/vendor_spec.js tests.
- The css/custom.css will be renamed after the next release. We've added into `run-start.sh` an instruction by GIT to ignore with `--skip-worktree` and `rm --cached`. [#1540](https://github.com/MichMich/MagicMirror/issues/1540)
- The css/custom.css will be renamed after the next release. We've added into `run-start.sh` an instruction by GIT to ignore with `--skip-worktree` and `rm --cached`. [#1540](https://github.com/MagicMirrorOrg/MagicMirror/issues/1540)
- Disable sending of notification CLOCK_SECOND when displaySeconds is false.
### Fixed
- Updatenotification module: Properly handle race conditions, prevent crash.
- Send `NEWS_FEED` notification also for the first news messages which are shown.
- Fixed issue where weather module would not refresh data after a network or API outage. [#1722](https://github.com/MichMich/MagicMirror/issues/1722)
- Fixed issue where weather module would not refresh data after a network or API outage. [#1722](https://github.com/MagicMirrorOrg/MagicMirror/issues/1722)
- Fixed weatherforecast module not displaying rain amount on fallback endpoint.
- Notifications CLOCK_SECOND & CLOCK_MINUTE being from startup instead of matched against the clock and avoid drifting.
@@ -827,7 +1152,7 @@ Special thanks to @sdetweil for all his great contributions!
- Russian translation for Feels
- Calendar module: added `nextDaysRelative` config option
- Add `broadcastPastEvents` config option for calendars to include events from the past `maximumNumberOfDays` in event broadcasts
- Added feature to broadcast news feed items `NEWS_FEED` and updated news items `NEWS_FEED_UPDATED` in default [newsfeed](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/newsfeed) module (when news is updated) with documented default and `config.js` options in [README.md](https://github.com/MichMich/MagicMirror/blob/develop/modules/default/newsfeed/README.md)
- Added feature to broadcast news feed items `NEWS_FEED` and updated news items `NEWS_FEED_UPDATED` in default [newsfeed](https://github.com/MagicMirrorOrg/MagicMirror/tree/develop/modules/default/newsfeed) module (when news is updated) with documented default and `config.js` options in [README.md](https://github.com/MagicMirrorOrg/MagicMirror/blob/develop/modules/default/newsfeed/README.md)
- Added notifications to default `clock` module broadcasting `CLOCK_SECOND` and `CLOCK_MINUTE` for the respective time elapsed.
- Added UK Met Office Datapoint feed as a provider in the default weather module.
- Added new provider class
@@ -836,7 +1161,7 @@ Special thanks to @sdetweil for all his great contributions!
- Use Feels Like temp from feed if present
- Optionally display probability of precipitation (PoP) in current weather (UK Met Office data)
- Automatically try to fix eslint errors by passing `--fix` option to it
- Added sunrise and sunset times to weathergov weather-provider [#1705](https://github.com/MichMich/MagicMirror/issues/1705)
- Added sunrise and sunset times to weathergov weather-provider [#1705](https://github.com/MagicMirrorOrg/MagicMirror/issues/1705)
- Added "useLocationAsHeader" to display "location" in `config.js` as header when location name is not returned
- Added to `newsfeed.js`: in order to design the news article better with css, three more class-names were introduced: newsfeed-desc, newsfeed-desc, newsfeed-desc
@@ -845,18 +1170,18 @@ Special thanks to @sdetweil for all his great contributions!
- English translation for "Feels" to "Feels like"
- Fixed the example calendar url in `config.js.sample`
- Updated `ical.js` to solve various calendar issues.
- Updated weather city list url [#1676](https://github.com/MichMich/MagicMirror/issues/1676)
- Updated weather city list url [#1676](https://github.com/MagicMirrorOrg/MagicMirror/issues/1676)
- Only update clock once per minute when seconds aren't shown
- Updated weather-provider documentation.
### Fixed
- Fixed uncaught exception, race condition on module update
- Fixed issue [#1696](https://github.com/MichMich/MagicMirror/issues/1696), some ical files start date to not parse to date type
- Fixed issue [#1696](https://github.com/MagicMirrorOrg/MagicMirror/issues/1696), some ical files start date to not parse to date type
- Allowance HTML5 autoplay-policy (policy is changed from Chrome 66 updates)
- Handle SIGTERM messages
- Fixes sliceMultiDayEvents so it respects maximumNumberOfDays
- Minor types in default NewsFeed [README.md](https://github.com/MichMich/MagicMirror/blob/develop/modules/default/newsfeed/README.md)
- Minor types in default NewsFeed [README.md](https://github.com/MagicMirrorOrg/MagicMirror/blob/develop/modules/default/newsfeed/README.md)
- Fix typos and small syntax errors, cleanup dependencies, remove multiple-empty-lines, add semi-rule
- Fixed issues with calendar not displaying one-time changes to repeating events
- Updated the fetchedLocationName variable in currentweather.js so that city shows up in the header
@@ -894,41 +1219,41 @@ Fixed `package.json` version number.
### Updated
- Bumped the Electron dependency to v3.0.13 to support the most recent Raspbian. [#1500](https://github.com/MichMich/MagicMirror/issues/1500)
- Bumped the Electron dependency to v3.0.13 to support the most recent Raspbian. [#1500](https://github.com/MagicMirrorOrg/MagicMirror/issues/1500)
- Updated modernizr code in alert module, fixed a small typo there too
- More verbose error message on console if the config is malformed
- Updated installer script to install Node.js version 10.x
### Fixed
- Fixed temperature displays in currentweather and weatherforecast modules [#1503](https://github.com/MichMich/MagicMirror/issues/1503), [#1511](https://github.com/MichMich/MagicMirror/issues/1511).
- Fixed unhandled error on bad git data in updatenotification module [#1285](https://github.com/MichMich/MagicMirror/issues/1285).
- Weather forecast now works with openweathermap in new weather module. Daily data are displayed, see issue [#1504](https://github.com/MichMich/MagicMirror/issues/1504).
- Fixed temperature displays in currentweather and weatherforecast modules [#1503](https://github.com/MagicMirrorOrg/MagicMirror/issues/1503), [#1511](https://github.com/MagicMirrorOrg/MagicMirror/issues/1511).
- Fixed unhandled error on bad git data in updatenotification module [#1285](https://github.com/MagicMirrorOrg/MagicMirror/issues/1285).
- Weather forecast now works with openweathermap in new weather module. Daily data are displayed, see issue [#1504](https://github.com/MagicMirrorOrg/MagicMirror/issues/1504).
- Fixed analogue clock border display issue where non-black backgrounds used (previous fix for issue 611)
- Fixed compatibility issues caused when modules request different versions of Font Awesome, see issue [#1522](https://github.com/MichMich/MagicMirror/issues/1522). MagicMirror² now uses [Font Awesome 5 with v4 shims included for backwards compatibility](https://fontawesome.com/how-to-use/on-the-web/setup/upgrading-from-version-4#shims).
- Fixed compatibility issues caused when modules request different versions of Font Awesome, see issue [#1522](https://github.com/MagicMirrorOrg/MagicMirror/issues/1522). MagicMirror² now uses [Font Awesome 5 with v4 shims included for backwards compatibility](https://fontawesome.com/how-to-use/on-the-web/setup/upgrading-from-version-4#shims).
- Installation script problems with raspbian
- Calendar: only show repeating count if the event is actually repeating [#1534](https://github.com/MichMich/MagicMirror/pull/1534)
- Calendar: only show repeating count if the event is actually repeating [#1534](https://github.com/MagicMirrorOrg/MagicMirror/pull/1534)
- Calendar: Fix exdate handling when multiple values are specified (comma separated)
- Calendar: Fix relative date handling for fulldate events, calculate difference always from start of day [#1572](https://github.com/MichMich/MagicMirror/issues/1572)
- Calendar: Fix relative date handling for fulldate events, calculate difference always from start of day [#1572](https://github.com/MagicMirrorOrg/MagicMirror/issues/1572)
- Fix null dereference in moduleNeedsUpdate when the module isn't visible
- Calendar: Fixed event end times by setting default calendarEndTime to "LT" (Local time format). [#1479]
- Calendar: Fixed missing calendar fetchers after server process restarts [#1589](https://github.com/MichMich/MagicMirror/issues/1589)
- Calendar: Fixed missing calendar fetchers after server process restarts [#1589](https://github.com/MagicMirrorOrg/MagicMirror/issues/1589)
- Notification: fixed background color (was white text on white background)
- Use getHeader instead of data.header when creating the DOM so overwriting the function also propagates into it
- Fix documentation of `useKMPHwind` option in currentweather
### New weather module
- Fixed weather forecast table display [#1499](https://github.com/MichMich/MagicMirror/issues/1499).
- Fixed weather forecast table display [#1499](https://github.com/MagicMirrorOrg/MagicMirror/issues/1499).
- Dimmed loading indicator for weather forecast.
- Implemented config option `decimalSymbol` [#1499](https://github.com/MichMich/MagicMirror/issues/1499).
- Aligned indoor values in current weather vertical [#1499](https://github.com/MichMich/MagicMirror/issues/1499).
- Implemented config option `decimalSymbol` [#1499](https://github.com/MagicMirrorOrg/MagicMirror/issues/1499).
- Aligned indoor values in current weather vertical [#1499](https://github.com/MagicMirrorOrg/MagicMirror/issues/1499).
- Added humidity support to nunjuck unit filter.
- Do not display degree symbol for temperature in Kelvin [#1503](https://github.com/MichMich/MagicMirror/issues/1503).
- Weather forecast now works with openweathermap for both, `/forecast` and `/forecast/daily`, in new weather module. If you use the `/forecast`-weatherEndpoint, the hourly data are converted to daily data, see issues [#1504](https://github.com/MichMich/MagicMirror/issues/1504), [#1513](https://github.com/MichMich/MagicMirror/issues/1513).
- Added fade, fadePoint and maxNumberOfDays properties to the forecast mode [#1516](https://github.com/MichMich/MagicMirror/issues/1516)
- Fixed Loading string and decimalSymbol string replace [#1538](https://github.com/MichMich/MagicMirror/issues/1538)
- Show Snow amounts in new weather module [#1545](https://github.com/MichMich/MagicMirror/issues/1545)
- Do not display degree symbol for temperature in Kelvin [#1503](https://github.com/MagicMirrorOrg/MagicMirror/issues/1503).
- Weather forecast now works with openweathermap for both, `/forecast` and `/forecast/daily`, in new weather module. If you use the `/forecast`-weatherEndpoint, the hourly data are converted to daily data, see issues [#1504](https://github.com/MagicMirrorOrg/MagicMirror/issues/1504), [#1513](https://github.com/MagicMirrorOrg/MagicMirror/issues/1513).
- Added fade, fadePoint and maxNumberOfDays properties to the forecast mode [#1516](https://github.com/MagicMirrorOrg/MagicMirror/issues/1516)
- Fixed Loading string and decimalSymbol string replace [#1538](https://github.com/MagicMirrorOrg/MagicMirror/issues/1538)
- Show Snow amounts in new weather module [#1545](https://github.com/MagicMirrorOrg/MagicMirror/issues/1545)
- Added weather.gov as a new weather-provider for US locations
## [2.6.0] - 2019-01-01
@@ -953,7 +1278,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
- Screenshot for the weather forecast module
- Portuguese translation for "Feels"
- Croatian translation
- Fading for dateheaders timeFormat in Calendar [#1464](https://github.com/MichMich/MagicMirror/issues/1464)
- Fading for dateheaders timeFormat in Calendar [#1464](https://github.com/MagicMirrorOrg/MagicMirror/issues/1464)
- Documentation for the existing `scale` option in the Weather Forecast module.
### Fixed
@@ -962,7 +1287,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
- Fixed Polish translation for Single Update Info
- Ignore entries with unparseable details in the calendar module
- Bug showing FullDayEvents one day too long in calendar fixed
- Bug in newsfeed when `removeStartTags` is used on the description [#1478](https://github.com/MichMich/MagicMirror/issues/1478)
- Bug in newsfeed when `removeStartTags` is used on the description [#1478](https://github.com/MagicMirrorOrg/MagicMirror/issues/1478)
### Updated
@@ -995,8 +1320,8 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
- Fixed mixup between german and spanish translation for newsfeed.
- Fixed close dates to be absolute, if no configured in the config.js - module Calendar
- Fixed the updatenotification module message about new commits in the repository, so they can be correctly localized in singular and plural form.
- Fix for weatherforecast rainfall rounding [#1374](https://github.com/MichMich/MagicMirror/issues/1374)
- Fix calendar parsing issue for Midori on RasperryPi Zero w, related to issue #694.
- Fix for weatherforecast rainfall rounding [#1374](https://github.com/MagicMirrorOrg/MagicMirror/issues/1374)
- Fix calendar parsing issue for Midori on Raspberry Pi Zero w, related to issue #694.
- Fix weather city ID link in sample config
- Fixed issue with clientonly not updating with IP address and port provided on command line.
@@ -1017,7 +1342,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
## [2.4.0] - 2018-07-01
**Warning:** This release includes an updated version of Electron. This requires a Raspberry Pi configuration change to allow the best performance and prevent the CPU from overheating. Please read the information on the [MagicMirror² Wiki](https://github.com/michmich/magicmirror/wiki/configuring-the-raspberry-pi#enable-the-open-gl-driver-to-decrease-electrons-cpu-usage).
**Warning:** This release includes an updated version of Electron. This requires a Raspberry Pi configuration change to allow the best performance and prevent the CPU from overheating. Please read the information on the [MagicMirror² Wiki](https://github.com/MagicMirrorOrg/MagicMirror/wiki/configuring-the-raspberry-pi#enable-the-open-gl-driver-to-decrease-electrons-cpu-usage).
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
@@ -1039,20 +1364,20 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
- Upgrade to Electron 2.0.0.
- Remove yarn-or-npm which breaks production builds.
- Invoke module suspend even if no dom content. [#1308](https://github.com/MichMich/MagicMirror/issues/1308)
- Invoke module suspend even if no dom content. [#1308](https://github.com/MagicMirrorOrg/MagicMirror/issues/1308)
### Fixed
- Fixed issue where wind chill could not be displayed in Fahrenheit. [#1247](https://github.com/MichMich/MagicMirror/issues/1247)
- Fixed issues where a module crashes when it tries to dismiss a non existing alert. [#1240](https://github.com/MichMich/MagicMirror/issues/1240)
- Fixed issue where wind chill could not be displayed in Fahrenheit. [#1247](https://github.com/MagicMirrorOrg/MagicMirror/issues/1247)
- Fixed issues where a module crashes when it tries to dismiss a non existing alert. [#1240](https://github.com/MagicMirrorOrg/MagicMirror/issues/1240)
- In default module currentWeather/currentWeather.js line 296, 300, self.config.animationSpeed can not be found because the notificationReceived function does not have "self" variable.
- Fixed browser-side code to work on the Midori browser.
- Fixed issue where heat index was reporting incorrect values in Celsius and Fahrenheit. [#1263](https://github.com/MichMich/MagicMirror/issues/1263)
- Fixed issue where heat index was reporting incorrect values in Celsius and Fahrenheit. [#1263](https://github.com/MagicMirrorOrg/MagicMirror/issues/1263)
- Fixed weatherforecast to use dt_txt field instead of dt to handle timezones better
- Newsfeed now remembers to show the description when `"ARTICLE_LESS_DETAILS"` is called if the user wants to always show the description. [#1282](https://github.com/MichMich/MagicMirror/issues/1282)
- Newsfeed now remembers to show the description when `"ARTICLE_LESS_DETAILS"` is called if the user wants to always show the description. [#1282](https://github.com/MagicMirrorOrg/MagicMirror/issues/1282)
- `clientonly/*.js` is now linted, and one linting error is fixed
- Fix issue #1196 by changing underscore to hyphen in locale id, in align with momentjs.
- Fixed issue where heat index and wind chill were reporting incorrect values in Kelvin. [#1263](https://github.com/MichMich/MagicMirror/issues/1263)
- Fix issue #1196 by changing underscore to hyphen in locale id, in align with moment.js.
- Fixed issue where heat index and wind chill were reporting incorrect values in Kelvin. [#1263](https://github.com/MagicMirrorOrg/MagicMirror/issues/1263)
### Updated
@@ -1064,7 +1389,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
### Fixed
- Downgrade electron to 1.4.15 to solve the black screen issue.[#1243](https://github.com/MichMich/MagicMirror/issues/1243)
- Downgrade electron to 1.4.15 to solve the black screen issue.[#1243](https://github.com/MagicMirrorOrg/MagicMirror/issues/1243)
## [2.3.0] - 2018-04-01
@@ -1076,7 +1401,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
- Implement Danger.js to notify contributors when CHANGELOG.md is missing in PR.
- Allow scrolling in full page article view of default newsfeed module with gesture events from [MMM-Gestures](https://github.com/thobach/MMM-Gestures)
- Changed 'compliments.js' - Updated DOM if remote compliments are loaded instead of waiting one updateInterval to show custom compliments
- Automated unit tests utils, deprecated, translator, cloneObject(lockstrings)
- Automated unit tests utils, deprecated, translator, cloneObject(lockStrings)
- Automated integration tests translations
- Add advanced filtering to the excludedEvents configuration of the default calendar module
- New currentweather module config option: `showFeelsLike`: Shows how it actually feels like. (wind chill or heat index)
@@ -1180,7 +1505,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
### Fixed
- Fixed issue with incorrect alignment of analog clock when displayed in the center column of the MM.
- Fixed ipWhitelist behaviour to make empty whitelist ([]) allow any and all hosts access to the MM.
- Fixed ipWhitelist behavior to make empty whitelist ([]) allow any and all hosts access to the MM.
- Fixed issue with calendar module where 'excludedEvents' count towards 'maximumEntries'.
- Fixed issue with calendar module where global configuration of maximumEntries was not overridden by calendar specific config (see module doc).
- Fixed issue where `this.file(filename)` returns a path with two hashes.
@@ -1190,8 +1515,8 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
### Changed
- Revert Docker related changes in favor of [docker-MagicMirror](https://github.com/bastilimbach/docker-MagicMirror). All Docker images are outsourced. ([#856](https://github.com/MichMich/MagicMirror/pull/856))
- Change Docker base image (Debian + Node) to an arm based distro (AlpineARM + Node) ([#846](https://github.com/MichMich/MagicMirror/pull/846))
- Revert Docker related changes in favor of [docker-MagicMirror](https://github.com/bastilimbach/docker-MagicMirror). All Docker images are outsourced. ([#856](https://github.com/MagicMirrorOrg/MagicMirror/pull/856))
- Change Docker base image (Debian + Node) to an arm based distro (AlpineARM + Node) ([#846](https://github.com/MagicMirrorOrg/MagicMirror/pull/846))
- Fix the dockerfile to have it running from the first time.
### Added
@@ -1222,7 +1547,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
### Fixed
- Fix instruction in README for using automatically installer script.
- Bug of duplicated compliments as described in [here](https://forum.magicmirror.builders/topic/2381/compliments-module-stops-cycling-compliments).
- Bug of [duplicated compliments](https://forum.magicmirror.builders/topic/2381/compliments-module-stops-cycling-compliments).
- Fix double message about port when server is starting
- Corrected Swedish translations for TODAY/TOMORROW/DAYAFTERTOMORROW.
- Removed unused import from js/electron.js
@@ -1238,7 +1563,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
- Add `anytime` group for Compliments module.
- Compliments module can use remoteFile without default daytime arrays defined.
- Installer: Use init config.js from config.js.sample.
- Switched out `rrule` package for `rrule-alt` and fixes in `ical.js` in order to fix calendar issues. ([#565](https://github.com/MichMich/MagicMirror/issues/565))
- Switched out `rrule` package for `rrule-alt` and fixes in `ical.js` in order to fix calendar issues. ([#565](https://github.com/MagicMirrorOrg/MagicMirror/issues/565))
- Make mouse events pass through the region fullscreen_above to modules below.
- Scaled the splash screen down to make it a bit more subtle.
- Replace HTML tables with markdown tables in README files.
@@ -1251,7 +1576,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
### Added
- Added Docker support (Pull Request [#673](https://github.com/MichMich/MagicMirror/pull/673)).
- Added Docker support (Pull Request [#673](https://github.com/MagicMirrorOrg/MagicMirror/pull/673)).
- Calendar-specific support for `maximumEntries`, and `maximumNumberOfDays`.
- Add loaded function to modules, providing an async callback.
- Made default newsfeed module aware of gesture events from [MMM-Gestures](https://github.com/thobach/MMM-Gestures)
@@ -1285,7 +1610,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
- Added multiple calendar icon support.
- Added tests for Translations, dev argument, version, dev console.
- Added test anytime feature compliments module.
- Added test ipwhitelist configuration directive.
- Added test ipWhitelist configuration directive.
- Added test for calendar module: default, basic-auth, backward compatibility, fail-basic-auth.
- Added meta tags to support fullscreen mode on iOS (for server mode)
- Added `ignoreOldItems` and `ignoreOlderThan` options to the News Feed module
@@ -1297,7 +1622,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
- Updated .gitignore to not ignore default modules folder.
- Remove white flash on boot up.
- Added `update` in Raspberry Pi installation script.
- Fix an issue where the analog clock looked scrambled. ([#611](https://github.com/MichMich/MagicMirror/issues/611))
- Fix an issue where the analog clock looked scrambled. ([#611](https://github.com/MagicMirrorOrg/MagicMirror/issues/611))
- If units are set to imperial, the showRainAmount option of weatherforecast will show the correct unit.
- Module currentWeather: check if temperature received from api is defined.
- Fix an issue with module hidden status changing to `true` although lock string prevented showing it.
@@ -1314,18 +1639,18 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
- Finnish translation.
- Danish translation.
- Turkish translation.
- Option to limit access to certain IP addresses based on the value of `ipWhitelist` in the `config.js`, default is access from localhost only (Issue [#456](https://github.com/MichMich/MagicMirror/issues/456)).
- Option to limit access to certain IP addresses based on the value of `ipWhitelist` in the `config.js`, default is access from localhost only (Issue [#456](https://github.com/MagicMirrorOrg/MagicMirror/issues/456)).
- Added ability to change the point of time when calendar events get relative.
- Add Splash screen on boot.
- Add option to show humidity in currentWeather module.
- Add VSCode IntelliSense support.
- Module API: Add Visibility locking to module system. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#visibility-locking) for more information.
- Module API: Method to overwrite the module's header. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#getheader) for more information.
- Module API: Option to define the minimum MagicMirror² version to run a module. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules#requiresversion) for more information.
- Calendar module now broadcasts the event list to all other modules using the notification system. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/calendar) for more information.
- Possibility to use the calendar feed as the source for the weather (currentweather & weatherforecast) location data. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/weatherforecast) for more information.
- Module API: Add Visibility locking to module system. [See documentation](https://github.com/MagicMirrorOrg/MagicMirror/tree/develop/modules#visibility-locking) for more information.
- Module API: Method to overwrite the module's header. [See documentation](https://github.com/MagicMirrorOrg/MagicMirror/tree/develop/modules#getheader) for more information.
- Module API: Option to define the minimum MagicMirror² version to run a module. [See documentation](https://github.com/MagicMirrorOrg/MagicMirror/tree/develop/modules#requiresversion) for more information.
- Calendar module now broadcasts the event list to all other modules using the notification system. [See documentation](https://github.com/MagicMirrorOrg/MagicMirror/tree/develop/modules/default/calendar) for more information.
- Possibility to use the calendar feed as the source for the weather (currentweather & weatherforecast) location data. [See documentation](https://github.com/MagicMirrorOrg/MagicMirror/tree/develop/modules/default/weatherforecast) for more information.
- Added option to show rain amount in the weatherforecast default module
- Add module `updatenotification` to get an update whenever a new version is available. [See documentation](https://github.com/MichMich/MagicMirror/tree/develop/modules/default/updatenotification) for more information.
- Add module `updatenotification` to get an update whenever a new version is available. [See documentation](https://github.com/MagicMirrorOrg/MagicMirror/tree/develop/modules/default/updatenotification) for more information.
- Add the ability to set timezone on the date display in the Clock Module
- Ability to set date format in calendar module
- Possibility to use currentweather for the compliments
@@ -1395,11 +1720,11 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
### Fixed
- Prevent `getModules()` selectors from returning duplicate entries.
- Append endpoints of weather modules with `/` to retrieve the correct data. (Issue [#337](https://github.com/MichMich/MagicMirror/issues/337))
- Append endpoints of weather modules with `/` to retrieve the correct data. (Issue [#337](https://github.com/MagicMirrorOrg/MagicMirror/issues/337))
- Corrected grammar in `module.js` from 'suspend' to 'suspended'.
- Fixed openweathermap.org URL in config sample.
- Prevent currentweather module from crashing when received data object is incorrect.
- Fix issue where translation loading prevented the UI start-up when the language was set to 'en'. (Issue [#388](https://github.com/MichMich/MagicMirror/issues/388))
- Fix issue where translation loading prevented the UI start-up when the language was set to 'en'. (Issue [#388](https://github.com/MagicMirrorOrg/MagicMirror/issues/388))
### Updated
@@ -1419,8 +1744,8 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
### Fixed
- Edit Alert Module to display title & message if they are provided in the notification (Issue [#300](https://github.com/MichMich/MagicMirror/issues/300))
- Removed 'null' reference from updateModuleContent(). This fixes recent Edge and Internet Explorer browser displays (Issue [#319](https://github.com/MichMich/MagicMirror/issues/319))
- Edit Alert Module to display title & message if they are provided in the notification (Issue [#300](https://github.com/MagicMirrorOrg/MagicMirror/issues/300))
- Removed 'null' reference from updateModuleContent(). This fixes recent Edge and Internet Explorer browser displays (Issue [#319](https://github.com/MagicMirrorOrg/MagicMirror/issues/319))
### Changed
@@ -1437,7 +1762,7 @@ A huge, huge, huge thanks to user @fewieden for all his hard work on the new `we
### Fixed
- Added reference to Italian Translation.
- Added the missing NE translation to all languages. [#344](https://github.com/MichMich/MagicMirror/issues/344)
- Added the missing NE translation to all languages. [#344](https://github.com/MagicMirrorOrg/MagicMirror/issues/344)
- Added proper User-Agent string to calendar call.
### Changed
@@ -1471,3 +1796,53 @@ It includes (but is not limited to) the following features:
### Initial release of MagicMirror
This was part of the blogpost: [https://michaelteeuw.nl/post/83916869600/magic-mirror-part-vi-production-of-the](https://michaelteeuw.nl/post/83916869600/magic-mirror-part-vi-production-of-the)
[2.33.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.32.0...develop
[2.32.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.31.0...v2.32.0
[2.31.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.30.0...v2.31.0
[2.30.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.29.0...v2.30.0
[2.29.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.28.0...v2.29.0
[2.28.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.27.0...v2.28.0
[2.27.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.26.0...v2.27.0
[2.26.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.25.0...v2.26.0
[2.25.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.24.0...v2.25.0
[2.24.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.23.0...v2.24.0
[2.23.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.22.0...v2.23.0
[2.22.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.21.0...v2.22.0
[2.21.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.20.0...v2.21.0
[2.20.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.19.0...v2.20.0
[2.19.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.18.0...v2.19.0
[2.18.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.17.1...v2.18.0
[2.17.1]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.17.0...v2.17.1
[2.17.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.16.0...v2.17.0
[2.16.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.15.0...v2.16.0
[2.15.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.14.0...v2.15.0
[2.14.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.13.0...v2.14.0
[2.13.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.12.0...v2.13.0
[2.12.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.11.0...v2.12.0
[2.11.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.10.1...v2.11.0
[2.10.1]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.10.0...v2.10.1
[2.10.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.9.0...v2.10.0
[2.9.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.8.0...v2.9.0
[2.8.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.7.1...v2.8.0
[2.7.1]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.7.0...v2.7.1
[2.7.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.6.0...v2.7.0
[2.6.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.5.0...v2.6.0
[2.5.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.4.1...v2.5.0
[2.4.1]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.4.0...v2.4.1
[2.4.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.3.1...v2.4.0
[2.3.1]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.3.0...v2.3.1
[2.3.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.2.2...v2.3.0
[2.2.2]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.2.1...v2.2.2
[2.2.1]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.2.0...v2.2.1
[2.2.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.1.3...v2.2.0
[2.1.3]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.1.2...v2.1.3
[2.1.2]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.1.1...v2.1.2
[2.1.1]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.1.0...v2.1.1
[2.1.0]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.0.5...v2.1.0
[2.0.5]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.0.4...v2.0.5
[2.0.4]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.0.3...v2.0.4
[2.0.3]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.0.2...v2.0.3
[2.0.2]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.0.1...v2.0.2
[2.0.1]: https://github.com/MagicMirrorOrg/MagicMirror/compare/v2.0.0...v2.0.1
[2.0.0]: https://github.com/MagicMirrorOrg/MagicMirror/releases/tag/v2.0.0

View File

@@ -1,3 +1,5 @@
# Collaboration
This document describes how collaborators of this repository should work together.
## Pull Requests
@@ -5,7 +7,7 @@ This document describes how collaborators of this repository should work togethe
- never merge your own PR's
- never merge without someone having approved (approving and merging from same person is allowed)
- wait for all approvals requested (or the author decides something different in the comments)
- never merge to `master`, except for releases (because of update notification)
- merge to `master` only for releases or other urgent issues (update notification is only triggered by tags)
- merges to master should be tagged with the "mastermerge" label so that the test runs through
## Issues
@@ -15,4 +17,51 @@ This document describes how collaborators of this repository should work togethe
## Releases
- are done by @MichMich only
Are done by
- [ ] @rejas
- [ ] @sdetweil
- [ ] @khassel
### Pre-Deployment steps
- [ ] update dependencies (a few days before)
### Deployment steps
- [ ] pull latest `develop` branch
- [ ] create `prep-release` branch from `develop`
- [ ] update `package.json` and `package-lock.json` to reflect correct version number `2.xx.0`
- [ ] test `prep-release` branch
- [ ] update `CHANGELOG.md`
- [ ] add all contributor names: `...`
- [ ] add min. node version: > ⚠️ This release needs nodejs version `v22.14.0` or higher
- [ ] check release link at the bottom of the file
- [ ] commit and push all changes
- [ ] create pull request from `prep-release` to `develop` branch with title `Prepare Release 2.xx.0`
- [ ] after successful test run via github actions: merge pull request to `develop`
- [ ] after successful test run via github actions: create pull request from `develop` to `master` branch
- [ ] add label `mastermerge`
- [ ] title of the PR is `Release 2.xx.0`
- [ ] description of the PR is the section of the `CHANGELOG.md`
- [ ] after PR tests run without issues, merge PR
- [ ] create new release with
- [ ] corresponding version tag `v2.xx.0`
- [ ] a release name: `...`
- [ ] description of the release is the section of the `CHANGELOG.md`
### Draft new development release
- [ ] checkout `develop` branch
- [ ] update `package.json` and `package-lock.json` to reflect correct version number `2.xx.0-develop`
- [ ] draft new section in `CHANGELOG.md`
- [ ] create new release link at the bottom of the file
- [ ] commit and push `develop` branch
- [ ] if new release will be in January, update the year in LICENSE.md
### After release
- [ ] publish release notes with link to github release on forum in new locked topic
- [ ] close all issues with label `ready (coming with next release)`
- [ ] release new documentation by merging `develop` on `master` in documentation repository
- [ ] publish new version on [npm](https://www.npmjs.com/package/magicmirror)

View File

@@ -1,6 +1,6 @@
# The MIT License (MIT)
Copyright © 2016-2022 Michael Teeuw
Copyright © 2016-2025 Michael Teeuw
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation

View File

@@ -1,17 +1,17 @@
![MagicMirror²: The open source modular smart mirror platform. ](.github/header.png)
# ![MagicMirror²: The open source modular smart mirror platform.](.github/header.png)
<p style="text-align: center">
<a href="https://choosealicense.com/licenses/mit">
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License">
</a>
<img src="https://img.shields.io/github/actions/workflow/status/michmich/magicmirror/automated-tests.yaml" alt="GitHub Actions">
<img src="https://img.shields.io/github/checks-status/michmich/magicmirror/master" alt="Build Status">
<a href="https://github.com/MichMich/MagicMirror">
<img src="https://img.shields.io/github/stars/michmich/magicmirror?style=social">
</a>
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License">
</a>
<img src="https://img.shields.io/github/actions/workflow/status/magicmirrororg/magicmirror/automated-tests.yaml" alt="GitHub Actions">
<img src="https://img.shields.io/github/check-runs/magicmirrororg/magicmirror/master" alt="Build Status">
<a href="https://github.com/MagicMirrorOrg/MagicMirror">
<img src="https://img.shields.io/github/stars/magicmirrororg/magicmirror?style=social" alt="GitHub Stars">
</a>
</p>
**MagicMirror²** is an open source modular smart mirror platform. With a growing list of installable modules, the **MagicMirror²** allows you to convert your hallway or bathroom mirror into your personal assistant. **MagicMirror²** is built by the creator of [the original MagicMirror](https://michaelteeuw.nl/tagged/magicmirror) with the incredible help of a [growing community of contributors](https://github.com/MichMich/MagicMirror/graphs/contributors).
**MagicMirror²** is an open source modular smart mirror platform. With a growing list of installable modules, the **MagicMirror²** allows you to convert your hallway or bathroom mirror into your personal assistant. **MagicMirror²** is built by the creator of [the original MagicMirror](https://michaelteeuw.nl/tagged/magicmirror) with the incredible help of a [growing community of contributors](https://github.com/MagicMirrorOrg/MagicMirror/graphs/contributors).
MagicMirror² focuses on a modular plugin system and uses [Electron](https://www.electronjs.org/) as an application wrapper. So no more web server or browser installs necessary!
@@ -24,7 +24,7 @@ For the full documentation including **[installation instructions](https://docs.
- Website: [https://magicmirror.builders](https://magicmirror.builders)
- Documentation: [https://docs.magicmirror.builders](https://docs.magicmirror.builders)
- Forum: [https://forum.magicmirror.builders](https://forum.magicmirror.builders)
- Technical discussions: https://forum.magicmirror.builders/category/11/core-system
- Technical discussions: <https://forum.magicmirror.builders/category/11/core-system>
- Discord: [https://discord.gg/J5BAtvx](https://discord.gg/J5BAtvx)
- Blog: [https://michaelteeuw.nl/tagged/magicmirror](https://michaelteeuw.nl/tagged/magicmirror)
- Donations: [https://magicmirror.builders/#donate](https://magicmirror.builders/#donate)
@@ -41,7 +41,7 @@ For the full contribution guidelines, check out: [https://docs.magicmirror.build
## Enjoying MagicMirror? Consider a donation!
MagicMirror² is opensource and free. That doesn't mean we don't need any money.
MagicMirror² is Open Source and free. That doesn't mean we don't need any money.
Please consider a donation to help us cover the ongoing costs like webservers and email services.
If we receive enough donations we might even be able to free up some working hours and spend some extra time improving the MagicMirror² core.
@@ -49,5 +49,5 @@ If we receive enough donations we might even be able to free up some working hou
To donate, please follow [this](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=G5D8E9MR5DTD2&source=url) link.
<p style="text-align: center">
<a href="https://forum.magicmirror.builders/topic/728/magicmirror-is-voted-number-1-in-the-magpi-top-50"><img src="https://magicmirror.builders/img/magpi-best-watermark-custom.png" width="150" alt="MagPi Top 50"></a>
<a href="https://forum.magicmirror.builders/topic/728/magicmirror-is-voted-number-1-in-the-magpi-top-50"><img src="https://magicmirror.builders/img/magpi-best-watermark-custom.png" width="150" alt="MagPi Top 50"></a>
</p>

View File

@@ -28,7 +28,7 @@
});
// determine if "--use-tls"-flag was provided
config["tls"] = process.argv.indexOf("--use-tls") > 0;
config.tls = process.argv.indexOf("--use-tls") > 0;
}
/**
@@ -40,7 +40,7 @@
// Return new pending promise
return new Promise((resolve, reject) => {
// Select http or https module, depending on requested url
const lib = url.startsWith("https") ? require("https") : require("http");
const lib = url.startsWith("https") ? require("node:https") : require("node:http");
const request = lib.get(url, (response) => {
let configData = "";
@@ -83,6 +83,17 @@
if (["localhost", "127.0.0.1", "::1", "::ffff:127.0.0.1", undefined].indexOf(config.address) === -1) {
getServerConfig(`${prefix}${config.address}:${config.port}/config/`)
.then(function (configReturn) {
// check environment for DISPLAY or WAYLAND_DISPLAY
const elecParams = ["js/electron.js"];
if (process.env.WAYLAND_DISPLAY) {
console.log(`Client: Using WAYLAND_DISPLAY=${process.env.WAYLAND_DISPLAY}`);
elecParams.push("--enable-features=UseOzonePlatform");
elecParams.push("--ozone-platform=wayland");
} else if (process.env.DISPLAY) {
console.log(`Client: Using DISPLAY=${process.env.DISPLAY}`);
} else {
fail("Error: Requires environment variable WAYLAND_DISPLAY or DISPLAY, none is provided.");
}
// Pass along the server config via an environment variable
const env = Object.create(process.env);
env.clientonly = true; // set to pass to electron.js
@@ -94,7 +105,7 @@
// Spawn electron application
const electron = require("electron");
const child = require("child_process").spawn(electron, ["js/electron.js"], options);
const child = require("node:child_process").spawn(electron, elecParams, options);
// Pipe all child process output to current stdout
child.stdout.on("data", function (buf) {

View File

@@ -1,7 +1,4 @@
/* MagicMirror² Config Sample
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
/* Config Sample
*
* For more information on how you can configure this file
* see https://docs.magicmirror.builders/configuration/introduction.html
@@ -31,7 +28,11 @@ let config = {
httpsCertificate: "", // HTTPS Certificate path, only require when useHttps is true
language: "en",
locale: "en-US",
locale: "en-US", // this variable is provided as a consistent location
// it is currently only used by 3rd party modules. no MagicMirror code uses this value
// as we have no usage, we have no constraints on what this field holds
// see https://en.wikipedia.org/wiki/Locale_(computer_software) for the possibilities
logLevel: ["INFO", "LOG", "WARN", "ERROR"], // Add "DEBUG" for even more logging
timeFormat: 24,
units: "metric",
@@ -70,11 +71,10 @@ let config = {
module: "weather",
position: "top_right",
config: {
weatherProvider: "openweathermap",
weatherProvider: "openmeteo",
type: "current",
location: "New York",
locationID: "5128581", //ID from http://bulk.openweathermap.org/sample/city.list.json.gz; unzip the gz file and find your city
apiKey: "YOUR_OPENWEATHER_API_KEY"
lat: 40.776676,
lon: -73.971321
}
},
{
@@ -82,11 +82,10 @@ let config = {
position: "top_right",
header: "Weather Forecast",
config: {
weatherProvider: "openweathermap",
weatherProvider: "openmeteo",
type: "forecast",
location: "New York",
locationID: "5128581", //ID from http://bulk.openweathermap.org/sample/city.list.json.gz; unzip the gz file and find your city
apiKey: "YOUR_OPENWEATHER_API_KEY"
lat: 40.776676,
lon: -73.971321
}
},
{

253
cspell.config.json Normal file
View File

@@ -0,0 +1,253 @@
{
"version": "0.2",
"language": "en",
"words": [
"aarch",
"Alvinger",
"Ampio",
"andrezibaia",
"angeldeejay",
"apiontek",
"armv",
"ashishtank",
"autoplay",
"beada",
"Binney",
"bluemanos",
"bnitkin",
"bokmål",
"Brasileiro",
"Brento",
"browserwindow",
"bryanzzhu",
"btoconnor",
"bugsounet",
"buxxi",
"byday",
"calendarfetcherutils",
"calendarutils",
"chamakura",
"cjbrunner",
"clientonly",
"clockfaces",
"cmdline",
"codac",
"Crazylegstoo",
"crazyscot",
"Creepin",
"currentweather",
"CUSTOMCSS",
"customregions",
"cxmj",
"Cymraeg",
"dariom",
"darksky",
"dateheader",
"dateheaders",
"davide",
"DAYAFTERTOMORROW",
"DAYBEFOREYESTERDAY",
"defaultmodules",
"dgoth",
"dkallen",
"drivelist",
"DTEND",
"DTSTAMP",
"DTSTART",
"Duffman",
"earlman",
"easyas",
"eddiehung",
"Edgardos",
"Ekristoffe",
"elec",
"eltociear",
"envcanada",
"envsub",
"envsubst",
"eouia",
"exdate",
"expectedheaders",
"ezeholz",
"Faizan",
"feedme",
"feelslike",
"Fenner",
"fewieden",
"fixuppm",
"flopp",
"fontawesome",
"fontface",
"forecastweather",
"fortawesome",
"frameguard",
"Frysk",
"fulldate",
"fullday",
"fullscreen",
"geraki",
"Gevoelstemperatuur",
"GHSA",
"ghsas",
"grenagit",
"Heiko",
"Hirschberger",
"hourlyweather",
"Hwind",
"ical",
"illimarkangur",
"Ingan",
"ipfilter",
"ismarslomic",
"jakemulley",
"jakobsarwary",
"jalibu",
"jargordon",
"jetson",
"jkriegshauser",
"jsdocs",
"jsonlint",
"jupadin",
"kaennchenstruggle",
"Kalenderwoche",
"kenzal",
"Keyport",
"khassel",
"Kingdon",
"kioskmode",
"klaernie",
"kleinmantara",
"Kmph",
"Knapoc",
"Koepke",
"kolbyjack",
"krekos",
"Kristjan",
"krukle",
"labwc",
"Landis",
"larryare",
"letsencrypt",
"libgpiod",
"Lightspeed",
"locationforecast",
"lockstring",
"lstrip",
"Luciella",
"luxon",
"lxsession",
"magicmirror",
"martingron",
"marvai",
"mastermerge",
"matchtype",
"maxentries",
"Meteo",
"michaelteeuw",
"michmich",
"Midori",
"mirontoli",
"MISSINGLANG",
"mixasgr",
"MMPM",
"modernizr",
"modulename",
"multiday",
"Mystara",
"Ñandú",
"nathannaveen",
"naveensrinivasan",
"ndom",
"Nerfzooka",
"NEWSFEED",
"newsitems",
"nfogal",
"njwilliams",
"nonrepeating",
"Norsk",
"nunjuck",
"odroid",
"oemel",
"onecall",
"onevent",
"openmeteo",
"openweathermap",
"oraclesean",
"oscarb",
"philnagel",
"Português",
"PRECIP",
"Problema",
"psieg",
"radokristof",
"rajniszp",
"rebuilded",
"Reis",
"rejas",
"Resig",
"roboto",
"rohitdharavath",
"Rosso",
"rrule",
"savvadam",
"sdetweil",
"sendheaders",
"serveronly",
"sexualized",
"skpanagiotis",
"SMHI",
"Snille",
"socketclient",
"socketio",
"spectron",
"Starinvest",
"sthuber",
"Stieber",
"stylelintrc",
"subclassing",
"sunaction",
"suncalc",
"suntimes",
"symboltest",
"systeminformation",
"tada",
"taglist",
"Teeuw",
"TESTMODE",
"thomasrockhu",
"tomzt",
"ukmetoffice",
"ukmetofficedatahub",
"unitless",
"unparseable",
"updatenotification",
"Vaice",
"veeck",
"VEVENT",
"vgtu",
"Voelt",
"vppencilsharpener",
"Wallys",
"Weatherbit",
"WEATHERDATA",
"Weatherflow",
"weatherforecast",
"weathergov",
"weathericons",
"weatherobject",
"weatherutils",
"windspeed",
"Woolridge",
"worktree",
"xlarge",
"xrandr",
"xsmall",
"xsorifc",
"xwindows",
"xxxe",
"Ybbet",
"yearmatchgroup"
],
"ignorePaths": ["node_modules/**", "modules/**", "translations/**", "tests/mocks/**", "tests/e2e/modules/clock_es_spec.js", "css/roboto.css"],
"dictionaries": ["node"]
}

View File

@@ -1,10 +1,8 @@
/* MagicMirror² Custom CSS Sample
/* Custom CSS Sample
*
* Change color and fonts here.
*
* Beware that properties cannot be unitless, so for example write '--gap-body: 0px;' instead of just '--gap-body: 0;'
*
* MIT Licensed.
*/
/* Uncomment and adjust accordingly if you want to import another font from the google-fonts-api: */
@@ -18,7 +16,7 @@
--font-primary: "Roboto Condensed";
--font-secondary: "Roboto";
--font-size: 20px;
--font-size-small: 0.75rem;
@@ -26,6 +24,6 @@
--gap-body-right: 60px;
--gap-body-bottom: 60px;
--gap-body-left: 60px;
--gap-modules: 30px;
}

View File

@@ -239,3 +239,16 @@ sup {
border-spacing: 0;
border-collapse: separate;
}
/**
* Container Definitions.
*/
.region .container {
display: flex;
flex-direction: column;
}
.region .container.hidden {
display: none;
}

View File

@@ -2,11 +2,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 100;
src:
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-100-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-100-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-100-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-100-normal.woff") format("woff");
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@@ -14,11 +14,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 100;
src:
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-100-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-100-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-100-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-100-normal.woff") format("woff");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@@ -26,11 +26,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 100;
src:
url("node_modules/@fontsource/roboto/files/roboto-greek-ext-100-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-greek-ext-100-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-greek-ext-100-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-greek-ext-100-normal.woff") format("woff");
unicode-range: U+1F00-1FFF;
}
@@ -38,11 +38,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 100;
src:
url("node_modules/@fontsource/roboto/files/roboto-greek-100-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-greek-100-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-greek-100-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-greek-100-normal.woff") format("woff");
unicode-range: U+0370-03FF;
}
@@ -50,11 +50,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 100;
src:
url("node_modules/@fontsource/roboto/files/roboto-vietnamese-100-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-vietnamese-100-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-vietnamese-100-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-vietnamese-100-normal.woff") format("woff");
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@@ -62,11 +62,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 100;
src:
url("node_modules/@fontsource/roboto/files/roboto-latin-ext-100-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-latin-ext-100-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-latin-ext-100-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-latin-ext-100-normal.woff") format("woff");
unicode-range: U+0100-02AF, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@@ -74,11 +74,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 100;
src:
url("node_modules/@fontsource/roboto/files/roboto-latin-100-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-latin-100-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-latin-100-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-latin-100-normal.woff") format("woff");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@@ -86,11 +86,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 300;
src:
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-300-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-300-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-300-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-300-normal.woff") format("woff");
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@@ -98,11 +98,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 300;
src:
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-300-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-300-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-300-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-300-normal.woff") format("woff");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@@ -110,11 +110,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 300;
src:
url("node_modules/@fontsource/roboto/files/roboto-greek-ext-300-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-greek-ext-300-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-greek-ext-300-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-greek-ext-300-normal.woff") format("woff");
unicode-range: U+1F00-1FFF;
}
@@ -122,11 +122,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 300;
src:
url("node_modules/@fontsource/roboto/files/roboto-greek-300-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-greek-300-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-greek-300-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-greek-300-normal.woff") format("woff");
unicode-range: U+0370-03FF;
}
@@ -134,11 +134,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 300;
src:
url("node_modules/@fontsource/roboto/files/roboto-vietnamese-300-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-vietnamese-300-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-vietnamese-300-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-vietnamese-300-normal.woff") format("woff");
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@@ -146,11 +146,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 300;
src:
url("node_modules/@fontsource/roboto/files/roboto-latin-ext-300-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-latin-ext-300-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-latin-ext-300-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-latin-ext-300-normal.woff") format("woff");
unicode-range: U+0100-02AF, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@@ -158,11 +158,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 300;
src:
url("node_modules/@fontsource/roboto/files/roboto-latin-300-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-latin-300-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-latin-300-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-latin-300-normal.woff") format("woff");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@@ -170,11 +170,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 400;
src:
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-400-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-400-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-400-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-400-normal.woff") format("woff");
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@@ -182,11 +182,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 400;
src:
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-400-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-400-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-400-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-400-normal.woff") format("woff");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@@ -194,11 +194,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 400;
src:
url("node_modules/@fontsource/roboto/files/roboto-greek-ext-400-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-greek-ext-400-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-greek-ext-400-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-greek-ext-400-normal.woff") format("woff");
unicode-range: U+1F00-1FFF;
}
@@ -206,11 +206,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 400;
src:
url("node_modules/@fontsource/roboto/files/roboto-greek-400-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-greek-400-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-greek-400-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-greek-400-normal.woff") format("woff");
unicode-range: U+0370-03FF;
}
@@ -218,11 +218,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 400;
src:
url("node_modules/@fontsource/roboto/files/roboto-vietnamese-400-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-vietnamese-400-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-vietnamese-400-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-vietnamese-400-normal.woff") format("woff");
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@@ -230,11 +230,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 400;
src:
url("node_modules/@fontsource/roboto/files/roboto-latin-ext-400-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-latin-ext-400-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-latin-ext-400-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-latin-ext-400-normal.woff") format("woff");
unicode-range: U+0100-02AF, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@@ -242,11 +242,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 400;
src:
url("node_modules/@fontsource/roboto/files/roboto-latin-400-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-latin-400-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-latin-400-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-latin-400-normal.woff") format("woff");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@@ -254,11 +254,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 500;
src:
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-500-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-500-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-500-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-500-normal.woff") format("woff");
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@@ -266,11 +266,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 500;
src:
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-500-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-500-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-500-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-500-normal.woff") format("woff");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@@ -278,11 +278,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 500;
src:
url("node_modules/@fontsource/roboto/files/roboto-greek-ext-500-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-greek-ext-500-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-greek-ext-500-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-greek-ext-500-normal.woff") format("woff");
unicode-range: U+1F00-1FFF;
}
@@ -290,11 +290,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 500;
src:
url("node_modules/@fontsource/roboto/files/roboto-greek-500-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-greek-500-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-greek-500-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-greek-500-normal.woff") format("woff");
unicode-range: U+0370-03FF;
}
@@ -302,11 +302,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 500;
src:
url("node_modules/@fontsource/roboto/files/roboto-vietnamese-500-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-vietnamese-500-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-vietnamese-500-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-vietnamese-500-normal.woff") format("woff");
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@@ -314,11 +314,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 500;
src:
url("node_modules/@fontsource/roboto/files/roboto-latin-ext-500-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-latin-ext-500-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-latin-ext-500-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-latin-ext-500-normal.woff") format("woff");
unicode-range: U+0100-02AF, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@@ -326,11 +326,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 500;
src:
url("node_modules/@fontsource/roboto/files/roboto-latin-500-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-latin-500-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-latin-500-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-latin-500-normal.woff") format("woff");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@@ -338,11 +338,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 700;
src:
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-700-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-700-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-700-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-ext-700-normal.woff") format("woff");
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@@ -350,11 +350,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 700;
src:
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-700-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-cyrillic-700-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-700-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-cyrillic-700-normal.woff") format("woff");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@@ -362,11 +362,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 700;
src:
url("node_modules/@fontsource/roboto/files/roboto-greek-ext-700-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-greek-ext-700-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-greek-ext-700-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-greek-ext-700-normal.woff") format("woff");
unicode-range: U+1F00-1FFF;
}
@@ -374,11 +374,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 700;
src:
url("node_modules/@fontsource/roboto/files/roboto-greek-700-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-greek-700-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-greek-700-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-greek-700-normal.woff") format("woff");
unicode-range: U+0370-03FF;
}
@@ -386,11 +386,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 700;
src:
url("node_modules/@fontsource/roboto/files/roboto-vietnamese-700-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-vietnamese-700-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-vietnamese-700-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-vietnamese-700-normal.woff") format("woff");
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@@ -398,11 +398,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 700;
src:
url("node_modules/@fontsource/roboto/files/roboto-latin-ext-700-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-latin-ext-700-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-latin-ext-700-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-latin-ext-700-normal.woff") format("woff");
unicode-range: U+0100-02AF, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@@ -410,11 +410,11 @@
@font-face {
font-family: Roboto;
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 700;
src:
url("node_modules/@fontsource/roboto/files/roboto-latin-700-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto/files/roboto-latin-700-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto/files/roboto-latin-700-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto/files/roboto-latin-700-normal.woff") format("woff");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@@ -422,11 +422,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 300;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-ext-300-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-ext-300-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-ext-300-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-ext-300-normal.woff") format("woff");
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@@ -434,11 +434,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 300;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-300-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-300-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-300-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-300-normal.woff") format("woff");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@@ -446,11 +446,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 300;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-ext-300-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-ext-300-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-ext-300-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-ext-300-normal.woff") format("woff");
unicode-range: U+1F00-1FFF;
}
@@ -458,11 +458,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 300;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-300-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-300-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-300-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-300-normal.woff") format("woff");
unicode-range: U+0370-03FF;
}
@@ -470,11 +470,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 300;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-vietnamese-300-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-vietnamese-300-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-vietnamese-300-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-vietnamese-300-normal.woff") format("woff");
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@@ -482,11 +482,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 300;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-ext-300-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-ext-300-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-ext-300-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-ext-300-normal.woff") format("woff");
unicode-range: U+0100-02AF, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@@ -494,11 +494,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 300;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-300-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-300-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-300-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-300-normal.woff") format("woff");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@@ -506,11 +506,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 400;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-ext-400-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-ext-400-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-ext-400-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-ext-400-normal.woff") format("woff");
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@@ -518,11 +518,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 400;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-400-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-400-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-400-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-400-normal.woff") format("woff");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@@ -530,11 +530,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 400;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-ext-400-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-ext-400-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-ext-400-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-ext-400-normal.woff") format("woff");
unicode-range: U+1F00-1FFF;
}
@@ -542,11 +542,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 400;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-400-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-400-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-400-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-400-normal.woff") format("woff");
unicode-range: U+0370-03FF;
}
@@ -554,11 +554,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 400;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-vietnamese-400-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-vietnamese-400-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-vietnamese-400-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-vietnamese-400-normal.woff") format("woff");
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@@ -566,11 +566,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 400;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-ext-400-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-ext-400-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-ext-400-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-ext-400-normal.woff") format("woff");
unicode-range: U+0100-02AF, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@@ -578,11 +578,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 400;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-400-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-400-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-400-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-400-normal.woff") format("woff");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@@ -590,11 +590,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 700;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-ext-700-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-ext-700-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-ext-700-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-ext-700-normal.woff") format("woff");
unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
@@ -602,11 +602,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 700;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-700-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-700-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-700-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-cyrillic-700-normal.woff") format("woff");
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@@ -614,11 +614,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 700;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-ext-700-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-ext-700-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-ext-700-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-ext-700-normal.woff") format("woff");
unicode-range: U+1F00-1FFF;
}
@@ -626,11 +626,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 700;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-700-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-700-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-700-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-greek-700-normal.woff") format("woff");
unicode-range: U+0370-03FF;
}
@@ -638,11 +638,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 700;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-vietnamese-700-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-vietnamese-700-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-vietnamese-700-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-vietnamese-700-normal.woff") format("woff");
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@@ -650,11 +650,11 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 700;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-ext-700-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-ext-700-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-ext-700-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-ext-700-normal.woff") format("woff");
unicode-range: U+0100-02AF, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1E00-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@@ -662,10 +662,10 @@
@font-face {
font-family: "Roboto Condensed";
font-style: normal;
font-display: var(--fontsource-display, swap);
font-display: swap;
font-weight: 700;
src:
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-700-normal.woff2") format("woff2"),
url("node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-700-normal.woff") format("woff");
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-700-normal.woff2") format("woff2"),
url("../node_modules/@fontsource/roboto-condensed/files/roboto-condensed-latin-700-normal.woff") format("woff");
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

131
eslint.config.mjs Normal file
View File

@@ -0,0 +1,131 @@
import {defineConfig, globalIgnores} from "eslint/config";
import globals from "globals";
import {flatConfigs as importX} from "eslint-plugin-import-x";
import jest from "eslint-plugin-jest";
import js from "@eslint/js";
import jsdoc from "eslint-plugin-jsdoc";
import packageJson from "eslint-plugin-package-json";
import stylistic from "@stylistic/eslint-plugin";
export default defineConfig([
globalIgnores(["config/**", "modules/**/*", "!modules/default/**", "js/positions.js"]),
{
files: ["**/*.js"],
languageOptions: {
ecmaVersion: "latest",
globals: {
...globals.browser,
...globals.node,
Log: "readonly",
MM: "readonly",
Module: "readonly",
config: "readonly",
moment: "readonly"
}
},
plugins: {js, jsdoc, stylistic},
extends: [importX.recommended, jest.configs["flat/recommended"], "js/recommended", jsdoc.configs["flat/recommended"], "stylistic/all"],
rules: {
"@stylistic/array-element-newline": ["error", "consistent"],
"@stylistic/arrow-parens": ["error", "always"],
"@stylistic/brace-style": "off",
"@stylistic/comma-dangle": ["error", "never"],
"@stylistic/dot-location": ["error", "property"],
"@stylistic/function-call-argument-newline": ["error", "consistent"],
"@stylistic/function-paren-newline": ["error", "consistent"],
"@stylistic/implicit-arrow-linebreak": ["error", "beside"],
"@stylistic/indent": ["error", "tab"],
"@stylistic/max-statements-per-line": ["error", {max: 2}],
"@stylistic/multiline-comment-style": "off",
"@stylistic/multiline-ternary": ["error", "always-multiline"],
"@stylistic/newline-per-chained-call": ["error", {ignoreChainWithDepth: 4}],
"@stylistic/no-extra-parens": "off",
"@stylistic/no-tabs": "off",
"@stylistic/object-curly-spacing": ["error", "always"],
"@stylistic/object-property-newline": ["error", {allowAllPropertiesOnSameLine: true}],
"@stylistic/operator-linebreak": ["error", "before"],
"@stylistic/padded-blocks": "off",
"@stylistic/quote-props": ["error", "as-needed"],
"@stylistic/quotes": ["error", "double"],
"@stylistic/semi": ["error", "always"],
"@stylistic/space-before-function-paren": ["error", "always"],
"@stylistic/spaced-comment": "off",
"dot-notation": "error",
eqeqeq: "error",
"id-length": "off",
"import-x/extensions": "error",
"import-x/newline-after-import": "error",
"import-x/order": "error",
"init-declarations": "off",
"jest/consistent-test-it": "warn",
"jest/no-done-callback": "warn",
"jest/prefer-expect-resolves": "warn",
"jest/prefer-mock-promise-shorthand": "warn",
"jest/prefer-to-be": "warn",
"jest/prefer-to-have-length": "warn",
"max-lines-per-function": ["warn", 400],
"max-statements": "off",
"no-global-assign": "off",
"no-inline-comments": "off",
"no-magic-numbers": "off",
"no-param-reassign": "error",
"no-plusplus": "off",
"no-prototype-builtins": "off",
"no-ternary": "off",
"no-throw-literal": "error",
"no-undefined": "off",
"no-unneeded-ternary": "error",
"no-unused-vars": "off",
"no-useless-return": "error",
"no-warning-comments": "off",
"object-shorthand": ["error", "methods"],
"one-var": "off",
"prefer-template": "error",
"sort-keys": "off"
}
},
{
files: ["**/*.js"],
ignores: [
"clientonly/index.js",
"js/logger.js",
"tests/**/*.js"
],
rules: {"no-console": "error"}
},
{
files: ["**/package.json"],
plugins: {packageJson},
extends: ["packageJson/recommended"]
},
{
files: ["**/*.mjs"],
languageOptions: {
ecmaVersion: "latest",
globals: {
...globals.node
},
sourceType: "module"
},
plugins: {js, stylistic},
extends: [importX.recommended, "js/all", "stylistic/all"],
rules: {
"@stylistic/array-element-newline": "off",
"@stylistic/indent": ["error", "tab"],
"@stylistic/object-property-newline": ["error", {allowAllPropertiesOnSameLine: true}],
"@stylistic/padded-blocks": ["error", "never"],
"@stylistic/quote-props": ["error", "as-needed"],
"import-x/no-unresolved": ["error", {ignore: ["eslint/config"]}],
"max-lines-per-function": ["error", 100],
"no-magic-numbers": "off",
"one-var": ["error", "never"],
"sort-keys": "off"
}
},
{
files: ["tests/configs/modules/weather/*.js"],
rules: {
"@stylistic/quotes": "off"
}
}
]);

View File

@@ -1,25 +0,0 @@
{
"name": "magicmirror-fonts",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "magicmirror-fonts",
"license": "MIT",
"dependencies": {
"@fontsource/roboto": "^5.0.8",
"@fontsource/roboto-condensed": "^5.0.14"
}
},
"node_modules/@fontsource/roboto": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-5.0.8.tgz",
"integrity": "sha512-XxPltXs5R31D6UZeLIV1td3wTXU3jzd3f2DLsXI8tytMGBkIsGcc9sIyiupRtA8y73HAhuSCeweOoBqf6DbWCA=="
},
"node_modules/@fontsource/roboto-condensed": {
"version": "5.0.14",
"resolved": "https://registry.npmjs.org/@fontsource/roboto-condensed/-/roboto-condensed-5.0.14.tgz",
"integrity": "sha512-ZNBHUhE5/3z9efMIjpBblFsfLHgGotJjlzKd5Q8DODbkRRWy6Yh+JnbiaJZ8zwQyHyYBNOolk57BG4BcjSzrRg=="
}
}
}

View File

@@ -1,16 +0,0 @@
{
"name": "magicmirror-fonts",
"description": "Package for fonts use by MagicMirror² Core.",
"repository": {
"type": "git",
"url": "git+https://github.com/MichMich/MagicMirror.git"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/MichMich/MagicMirror/issues"
},
"dependencies": {
"@fontsource/roboto": "^5.0.8",
"@fontsource/roboto-condensed": "^5.0.14"
}
}

View File

@@ -12,12 +12,13 @@
<link rel="icon" href="data:;base64,iVBORw0KGgo=" />
<link rel="stylesheet" type="text/css" href="css/main.css" />
<link rel="stylesheet" type="text/css" href="fonts/roboto.css" />
<link rel="stylesheet" type="text/css" href="vendor/node_modules/animate.css/animate.min.css" />
<link rel="stylesheet" type="text/css" href="css/roboto.css" />
<link rel="stylesheet" type="text/css" href="node_modules/animate.css/animate.min.css" />
<!-- custom.css is loaded by the loader.js to make sure it's loaded after the module css files. -->
<script type="text/javascript">
window.mmVersion = "#VERSION#";
window.mmTestMode = "#TESTMODE#";
</script>
</head>
<body>
@@ -41,10 +42,10 @@
</div>
<div class="region fullscreen above"><div class="container"></div></div>
<script type="text/javascript" src="socket.io/socket.io.js"></script>
<script type="text/javascript" src="vendor/node_modules/nunjucks/browser/nunjucks.min.js"></script>
<script type="text/javascript" src="node_modules/nunjucks/browser/nunjucks.min.js"></script>
<script type="text/javascript" src="js/defaults.js"></script>
<script type="text/javascript" src="#CONFIG_FILE#"></script>
<script type="text/javascript" src="vendor/vendor.js"></script>
<script type="text/javascript" src="js/vendor.js"></script>
<script type="text/javascript" src="modules/default/defaultmodules.js"></script>
<script type="text/javascript" src="modules/default/utils.js"></script>
<script type="text/javascript" src="js/logger.js"></script>
@@ -55,6 +56,7 @@
<script type="text/javascript" src="js/loader.js"></script>
<script type="text/javascript" src="js/socketclient.js"></script>
<script type="text/javascript" src="js/animateCSS.js"></script>
<script type="text/javascript" src="js/positions.js"></script>
<script type="text/javascript" src="js/main.js"></script>
</body>
</html>

View File

@@ -1,4 +0,0 @@
#!/bin/bash
# This file is still here to keep PM2 working on older installations.
cd ~/MagicMirror
DISPLAY=:0 npm start

View File

@@ -1,33 +1,37 @@
module.exports = async () => {
return {
verbose: true,
testTimeout: 20000,
testSequencer: "<rootDir>/tests/utils/test_sequencer.js",
projects: [
{
displayName: "unit",
globalSetup: "<rootDir>/tests/unit/helpers/global-setup.js",
moduleNameMapper: {
logger: "<rootDir>/js/logger.js"
},
testMatch: ["**/tests/unit/**/*.[jt]s?(x)"],
testPathIgnorePatterns: ["<rootDir>/tests/unit/mocks", "<rootDir>/tests/unit/helpers"]
const config = {
verbose: true,
testTimeout: 20000,
testSequencer: "<rootDir>/tests/utils/test_sequencer.js",
projects: [
{
displayName: "unit",
globalSetup: "<rootDir>/tests/unit/helpers/global-setup.js",
moduleNameMapper: {
logger: "<rootDir>/js/logger.js"
},
{
displayName: "electron",
testMatch: ["**/tests/electron/**/*.[jt]s?(x)"],
testPathIgnorePatterns: ["<rootDir>/tests/electron/helpers"]
},
{
displayName: "e2e",
setupFilesAfterEnv: ["<rootDir>/tests/e2e/helpers/mock-console.js"],
testMatch: ["**/tests/e2e/**/*.[jt]s?(x)"],
modulePaths: ["<rootDir>/js/"],
testPathIgnorePatterns: ["<rootDir>/tests/e2e/helpers", "<rootDir>/tests/e2e/mocks"]
}
],
collectCoverageFrom: ["./clientonly/**/*.js", "./js/**/*.js", "./modules/default/**/*.js", "./serveronly/**/*.js"],
coverageReporters: ["lcov", "text"],
coverageProvider: "v8"
};
testMatch: ["**/tests/unit/**/*.[jt]s?(x)"],
testPathIgnorePatterns: ["<rootDir>/tests/unit/mocks", "<rootDir>/tests/unit/helpers"]
},
{
displayName: "electron",
testMatch: ["**/tests/electron/**/*.[jt]s?(x)"],
testPathIgnorePatterns: ["<rootDir>/tests/electron/helpers"]
},
{
displayName: "e2e",
testMatch: ["**/tests/e2e/**/*.[jt]s?(x)"],
modulePaths: ["<rootDir>/js/"],
testPathIgnorePatterns: ["<rootDir>/tests/e2e/helpers", "<rootDir>/tests/e2e/mocks"]
}
],
collectCoverageFrom: [
"<rootDir>/clientonly/**/*.js",
"<rootDir>/js/**/*.js",
"<rootDir>/modules/default/**/*.js",
"<rootDir>/serveronly/**/*.js"
],
coverageReporters: ["lcov", "text"],
coverageProvider: "v8"
};
module.exports = config;

View File

@@ -1,10 +1,3 @@
/* MagicMirror²
* AnimateCSS System from https://animate.style/
* by @bugsounet
* for Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
/* enumeration of animations in Array **/
const AnimateCSSIn = [
// Attention seekers
@@ -162,3 +155,4 @@ function removeAnimateCSS (element, animation) {
node.classList.remove("animate__animated", animationName);
node.style.removeProperty("--animate-duration");
}
if (typeof window === "undefined") module.exports = { AnimateCSSIn, AnimateCSSOut };

122
js/app.js
View File

@@ -1,26 +1,29 @@
/* MagicMirror²
* The Core App (Server)
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
// Alias modules mentioned in package.js under _moduleAliases.
require("module-alias/register");
const fs = require("fs");
const path = require("path");
const fs = require("node:fs");
const path = require("node:path");
const envsub = require("envsub");
const Log = require("logger");
const Server = require(`${__dirname}/server`);
const Utils = require(`${__dirname}/utils`);
const defaultModules = require(`${__dirname}/../modules/default/defaultmodules`);
const { getEnvVarsAsObj } = require(`${__dirname}/server_functions`);
// used to control fetch timeout for node_helpers
const { setGlobalDispatcher, Agent } = require("undici");
// common timeout value, provide environment override in case
const fetch_timeout = process.env.mmFetchTimeout !== undefined ? process.env.mmFetchTimeout : 30000;
// Get version number.
global.version = require(`${__dirname}/../package.json`).version;
global.mmTestMode = process.env.mmTestMode === "true";
Log.log(`Starting MagicMirror: v${global.version}`);
// Log system information.
Utils.logSystemInformation(global.version);
// global absolute root path
global.root_path = path.resolve(`${__dirname}/../`);
@@ -29,7 +32,7 @@ if (process.env.MM_CONFIG_FILE) {
}
// FIXME: Hotfix Pull Request
// https://github.com/MichMich/MagicMirror/pull/673
// https://github.com/MagicMirrorOrg/MagicMirror/pull/673
if (process.env.MM_PORT) {
global.mmPort = process.env.MM_PORT;
}
@@ -37,10 +40,13 @@ if (process.env.MM_PORT) {
// The next part is here to prevent a major exception when there
// is no internet connection. This could probable be solved better.
process.on("uncaughtException", function (err) {
Log.error("Whoops! There was an uncaught exception...");
Log.error(err);
Log.error("MagicMirror² will not quit, but it might be a good idea to check why this happened. Maybe no internet connection?");
Log.error("If you think this really is an issue, please open an issue on GitHub: https://github.com/MichMich/MagicMirror/issues");
// ignore strange exceptions under aarch64 coming from systeminformation:
if (!err.stack.includes("node_modules/systeminformation")) {
Log.error("Whoops! There was an uncaught exception...");
Log.error(err);
Log.error("MagicMirror² will not quit, but it might be a good idea to check why this happened. Maybe no internet connection?");
Log.error("If you think this really is an issue, please open an issue on GitHub: https://github.com/MagicMirrorOrg/MagicMirror/issues");
}
});
/**
@@ -59,6 +65,10 @@ function App () {
async function loadConfig () {
Log.log("Loading config ...");
const defaults = require(`${__dirname}/defaults`);
if (process.env.JEST_WORKER_ID !== undefined) {
// if we are running with jest
defaults.address = "0.0.0.0";
}
// For this check proposed to TestSuite
// https://forum.magicmirror.builders/topic/1456/test-suite-for-magicmirror/8
@@ -67,10 +77,10 @@ function App () {
// check if templateFile exists
try {
fs.accessSync(templateFile, fs.F_OK);
fs.accessSync(templateFile, fs.constants.F_OK);
} catch (err) {
templateFile = null;
Log.debug("config template file not exists, no envsubst");
Log.log("config template file not exists, no envsubst");
}
if (templateFile) {
@@ -91,7 +101,7 @@ function App () {
envFiles.push(configEnvFile);
}
} catch (err) {
Log.debug(`${configEnvFile} does not exist. ${err.message}`);
Log.log(`${configEnvFile} does not exist. ${err.message}`);
}
let options = {
@@ -113,18 +123,23 @@ function App () {
}
}
require(`${global.root_path}/js/check_config.js`);
try {
fs.accessSync(configFilename, fs.F_OK);
fs.accessSync(configFilename, fs.constants.F_OK);
const c = require(configFilename);
if (Object.keys(c).length === 0) {
Log.error("WARNING! Config file appears empty, maybe missing module.exports last line?");
}
checkDeprecatedOptions(c);
return Object.assign(defaults, c);
} catch (e) {
if (e.code === "ENOENT") {
Log.error(Utils.colors.error("WARNING! Could not find config file. Please create one. Starting with default configuration."));
Log.error("WARNING! Could not find config file. Please create one. Starting with default configuration.");
} else if (e instanceof ReferenceError || e instanceof SyntaxError) {
Log.error(Utils.colors.error(`WARNING! Could not validate config file. Starting with default configuration. Please correct syntax errors at or above this line: ${e.stack}`));
Log.error(`WARNING! Could not validate config file. Starting with default configuration. Please correct syntax errors at or above this line: ${e.stack}`);
} else {
Log.error(Utils.colors.error(`WARNING! Could not load config file. Starting with default configuration. Error found: ${e}`));
Log.error(`WARNING! Could not load config file. Starting with default configuration. Error found: ${e}`);
}
}
@@ -138,11 +153,23 @@ function App () {
*/
function checkDeprecatedOptions (userConfig) {
const deprecated = require(`${global.root_path}/js/deprecated`);
const deprecatedOptions = deprecated.configs;
// check for deprecated core options
const deprecatedOptions = deprecated.configs;
const usedDeprecated = deprecatedOptions.filter((option) => userConfig.hasOwnProperty(option));
if (usedDeprecated.length > 0) {
Log.warn(Utils.colors.warn(`WARNING! Your config is using deprecated options: ${usedDeprecated.join(", ")}. Check README and CHANGELOG for more up-to-date ways of getting the same functionality.`));
Log.warn(`WARNING! Your config is using deprecated option(s): ${usedDeprecated.join(", ")}. Check README and CHANGELOG for more up-to-date ways of getting the same functionality.`);
}
// check for deprecated module options
for (const element of userConfig.modules) {
if (deprecated[element.module] !== undefined && element.config !== undefined) {
const deprecatedModuleOptions = deprecated[element.module];
const usedDeprecatedModuleOptions = deprecatedModuleOptions.filter((option) => element.config.hasOwnProperty(option));
if (usedDeprecatedModuleOptions.length > 0) {
Log.warn(`WARNING! Your config for module ${element.module} is using deprecated option(s): ${usedDeprecatedModuleOptions.join(", ")}. Check README and CHANGELOG for more up-to-date ways of getting the same functionality.`);
}
}
}
}
@@ -153,16 +180,25 @@ function App () {
function loadModule (module) {
const elements = module.split("/");
const moduleName = elements[elements.length - 1];
let moduleFolder = `${__dirname}/../modules/${module}`;
const env = getEnvVarsAsObj();
let moduleFolder = path.resolve(`${__dirname}/../${env.modulesDir}`, module);
if (defaultModules.includes(moduleName)) {
moduleFolder = `${__dirname}/../modules/default/${module}`;
const defaultModuleFolder = path.resolve(`${__dirname}/../modules/default/`, module);
if (process.env.JEST_WORKER_ID === undefined) {
moduleFolder = defaultModuleFolder;
} else {
// running in Jest, allow defaultModules placed under moduleDir for testing
if (env.modulesDir === "modules" || env.modulesDir === "tests/mocks") {
moduleFolder = defaultModuleFolder;
}
}
}
const moduleFile = `${moduleFolder}/${module}.js`;
const moduleFile = `${moduleFolder}/${moduleName}.js`;
try {
fs.accessSync(moduleFile, fs.R_OK);
fs.accessSync(moduleFile, fs.constants.R_OK);
} catch (e) {
Log.warn(`No ${moduleFile} found for module: ${moduleName}.`);
}
@@ -171,14 +207,21 @@ function App () {
let loadHelper = true;
try {
fs.accessSync(helperPath, fs.R_OK);
fs.accessSync(helperPath, fs.constants.R_OK);
} catch (e) {
loadHelper = false;
Log.log(`No helper found for module: ${moduleName}.`);
}
// if the helper was found
if (loadHelper) {
const Module = require(helperPath);
let Module;
try {
Module = require(helperPath);
} catch (e) {
Log.error(`Error when loading ${moduleName}:`, e.message);
return;
}
let m = new Module();
if (m.requiresVersion) {
@@ -249,13 +292,28 @@ function App () {
Log.setLogLevel(config.logLevel);
// get the used module positions
Utils.getModulePositions();
let modules = [];
for (const module of config.modules) {
if (!modules.includes(module.module) && !module.disabled) {
modules.push(module.module);
if (module.disabled) continue;
if (module.module) {
if (Utils.moduleHasValidPosition(module.position) || typeof (module.position) === "undefined") {
// Only add this module to be loaded if it is not a duplicate (repeated instance of the same module)
if (!modules.includes(module.module)) {
modules.push(module.module);
}
} else {
Log.warn("Invalid module position found for this configuration:" + `\n${JSON.stringify(module, null, 2)}`);
}
} else {
Log.warn("No module name found for this configuration:" + `\n${JSON.stringify(module, null, 2)}`);
}
}
setGlobalDispatcher(new Agent({ connect: { timeout: fetch_timeout } }));
await loadModules(modules);
httpServer = new Server(config);
@@ -306,7 +364,7 @@ function App () {
}
} catch (error) {
Log.error(`Error when stopping node_helper for module ${nodeHelper.name}:`);
console.error(error);
Log.error(error);
}
}

View File

@@ -1,20 +1,17 @@
/* MagicMirror²
*
* Check the configuration file for errors
*
* By Rodrigo Ramírez Norambuena https://rodrigoramirez.com
* MIT Licensed.
*/
const path = require("path");
const fs = require("fs");
const path = require("node:path");
const fs = require("node:fs");
const { styleText } = require("node:util");
const Ajv = require("ajv");
const globals = require("globals");
const { Linter } = require("eslint");
const linter = new Linter();
const rootPath = path.resolve(`${__dirname}/../`);
const Log = require(`${rootPath}/js/logger.js`);
const Utils = require(`${rootPath}/js/utils.js`);
const linter = new Linter({ configType: "flat" });
const ajv = new Ajv();
/**
* Returns a string with path of configuration file.
* Check if set by environment variable MM_CONFIG_FILE
@@ -33,40 +30,107 @@ function checkConfigFile () {
// Check if file is present
if (fs.existsSync(configFileName) === false) {
Log.error(Utils.colors.error("File not found: "), configFileName);
throw new Error("No config file present!");
throw new Error(`File not found: ${configFileName}\nNo config file present!`);
}
// Check permission
try {
fs.accessSync(configFileName, fs.F_OK);
} catch (e) {
Log.error(Utils.colors.error(e));
throw new Error("No permission to access config file!");
fs.accessSync(configFileName, fs.constants.F_OK);
} catch (error) {
throw new Error(`${error}\nNo permission to access config file!`);
}
// Validate syntax of the configuration file.
Log.info(Utils.colors.info("Checking file... "), configFileName);
Log.info(`Checking config file ${configFileName} ...`);
// I'm not sure if all ever is utf-8
const configFile = fs.readFileSync(configFileName, "utf-8");
// Explicitly tell linter that he might encounter es6 syntax ("let config = {...}")
const errors = linter.verify(configFile, {
env: {
es6: true
}
});
const errors = linter.verify(
configFile,
{
languageOptions: {
ecmaVersion: "latest",
globals: {
...globals.node
}
},
rules: { "no-undef": "error" }
},
configFileName
);
if (errors.length === 0) {
Log.info(Utils.colors.pass("Your configuration file doesn't contain syntax errors :)"));
Log.info(styleText("green", "Your configuration file doesn't contain syntax errors :)"));
validateModulePositions(configFileName);
} else {
Log.error(Utils.colors.error("Your configuration file contains syntax errors :("));
let errorMessage = "Your configuration file contains syntax errors :(";
for (const error of errors) {
Log.error(`Line ${error.line} column ${error.column}: ${error.message}`);
errorMessage += `\nLine ${error.line} column ${error.column}: ${error.message}`;
}
throw new Error(errorMessage);
}
}
checkConfigFile();
/**
*
* @param {string} configFileName - The path and filename of the configuration file to validate.
*/
function validateModulePositions (configFileName) {
Log.info("Checking modules structure configuration ...");
const positionList = Utils.getModulePositions();
// Make Ajv schema configuration of modules config
// Only scan "module" and "position"
const schema = {
type: "object",
properties: {
modules: {
type: "array",
items: {
type: "object",
properties: {
module: {
type: "string"
},
position: {
type: "string",
enum: positionList
}
},
required: ["module"]
}
}
}
};
// Scan all modules
const validate = ajv.compile(schema);
const data = require(configFileName);
const valid = validate(data);
if (valid) {
Log.info(styleText("green", "Your modules structure configuration doesn't contain errors :)"));
} else {
const module = validate.errors[0].instancePath.split("/")[2];
const position = validate.errors[0].instancePath.split("/")[3];
let errorMessage = "This module configuration contains errors:";
errorMessage += `\n${JSON.stringify(data.modules[module], null, 2)}`;
if (position) {
errorMessage += `\n${position}: ${validate.errors[0].message}`;
errorMessage += `\n${JSON.stringify(validate.errors[0].params.allowedValues, null, 2).slice(1, -1)}`;
} else {
errorMessage += validate.errors[0].message;
}
Log.error(errorMessage);
}
}
try {
checkConfigFile();
} catch (error) {
Log.error(error.message);
process.exit(1);
}

View File

@@ -1,6 +1,7 @@
/* global Class, xyz */
/* Simple JavaScript Inheritance
/*
* Simple JavaScript Inheritance
* By John Resig https://johnresig.com/
*
* Inspired by base2 and Prototype
@@ -22,8 +23,10 @@
Class.extend = function (prop) {
let _super = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
/*
* Instantiate a base class (but only create the instance,
* don't run the init constructor)
*/
initializing = true;
const prototype = new this();
initializing = false;
@@ -42,12 +45,16 @@
return function () {
const tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
/*
* Add a new ._super() method that is the same method
* but on the super-class
*/
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
/*
* The method only need to be bound temporarily, so we
* remove it when we're done executing
*/
const ret = fn.apply(this, arguments);
this._super = tmp;

View File

@@ -1,11 +1,5 @@
/* global mmPort */
/* MagicMirror²
* Config Defaults
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
const address = "localhost";
let port = 8080;
if (typeof mmPort !== "undefined") {
@@ -25,8 +19,9 @@ const defaults = {
units: "metric",
zoom: 1,
customCss: "css/custom.css",
foreignModulesDir: "modules",
// httpHeaders used by helmet, see https://helmetjs.github.io/. You can add other/more object values by overriding this in config.js,
// e.g. you need to add `frameguard: false` for embedding MagicMirror in another website, see https://github.com/MichMich/MagicMirror/issues/2847
// e.g. you need to add `frameguard: false` for embedding MagicMirror in another website, see https://github.com/MagicMirrorOrg/MagicMirror/issues/2847
httpHeaders: { contentSecurityPolicy: false, crossOriginOpenerPolicy: false, crossOriginEmbedderPolicy: false, crossOriginResourcePolicy: false, originAgentCluster: false },
// properties for checking if server is alive and has same startup-timestamp, the check is per default enabled
@@ -67,7 +62,7 @@ const defaults = {
position: "middle_center",
classes: "xsmall",
config: {
text: "If you get this message while your config file is already created,<br>" + "it probably contains an error. To validate your config file run in your MagicMirror² directory<br>" + "<pre>npm run config:check</pre>"
text: "If you get this message while your config file is already created,<br>" + "it probably contains an error. To validate your config file run in your MagicMirror² directory<br>" + "<pre>node --run config:check</pre>"
}
},
{
@@ -75,15 +70,10 @@ const defaults = {
position: "bottom_bar",
classes: "xsmall dimmed",
config: {
text: "www.michaelteeuw.nl"
text: "https://magicmirror.builders/"
}
}
],
paths: {
modules: "modules",
vendor: "vendor"
}
]
};
/*************** DO NOT EDIT THE LINE BELOW ***************/

View File

@@ -1,11 +1,4 @@
/* MagicMirror² Deprecated Config Options List
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*
* Olex S. original idea this deprecated option
*/
module.exports = {
configs: ["kioskmode"]
configs: ["kioskmode"],
clock: ["secondsColor"]
};

View File

@@ -8,9 +8,12 @@ const Log = require("./logger");
let config = process.env.config ? JSON.parse(process.env.config) : {};
// Module to control application life.
const app = electron.app;
// Per default electron is started with --disable-gpu flag, if you want the gpu enabled,
// you must set the env var ELECTRON_ENABLE_GPU=1 on startup.
// See https://www.electronjs.org/docs/latest/tutorial/offscreen-rendering for more info.
/*
* Per default electron is started with --disable-gpu flag, if you want the gpu enabled,
* you must set the env var ELECTRON_ENABLE_GPU=1 on startup.
* See https://www.electronjs.org/docs/latest/tutorial/offscreen-rendering for more info.
*/
if (process.env.ELECTRON_ENABLE_GPU !== "1") {
app.disableHardwareAcceleration();
}
@@ -18,16 +21,21 @@ if (process.env.ELECTRON_ENABLE_GPU !== "1") {
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
/*
* Keep a global reference of the window object, if you don't, the window will
* be closed automatically when the JavaScript object is garbage collected.
*/
let mainWindow;
/**
*
*/
function createWindow () {
// see https://www.electronjs.org/docs/latest/api/screen
// Create a window that fills the screen's available work area.
/*
* see https://www.electronjs.org/docs/latest/api/screen
* Create a window that fills the screen's available work area.
*/
let electronSize = (800, 600);
try {
electronSize = electron.screen.getPrimaryDisplay().workAreaSize;
@@ -40,6 +48,7 @@ function createWindow () {
let electronOptionsDefaults = {
width: electronSize.width,
height: electronSize.height,
icon: "mm2.png",
x: 0,
y: 0,
darkTheme: true,
@@ -51,8 +60,10 @@ function createWindow () {
backgroundColor: "#000000"
};
// DEPRECATED: "kioskmode" backwards compatibility, to be removed
// settings these options directly instead provides cleaner interface
/*
* DEPRECATED: "kioskmode" backwards compatibility, to be removed
* settings these options directly instead provides cleaner interface
*/
if (config.kioskmode) {
electronOptionsDefaults.kiosk = true;
} else {
@@ -65,14 +76,33 @@ function createWindow () {
const electronOptions = Object.assign({}, electronOptionsDefaults, config.electronOptions);
if (process.env.JEST_WORKER_ID !== undefined && process.env.MOCK_DATE !== undefined) {
// if we are running with jest and we want to mock the current date
const fakeNow = new Date(process.env.MOCK_DATE).valueOf();
Date = class extends Date {
constructor (...args) {
if (args.length === 0) {
super(fakeNow);
} else {
super(...args);
}
}
};
const __DateNowOffset = fakeNow - Date.now();
const __DateNow = Date.now;
Date.now = () => __DateNow() + __DateNowOffset;
}
// Create the browser window.
mainWindow = new BrowserWindow(electronOptions);
// and load the index.html of the app.
// If config.address is not defined or is an empty string (listening on all interfaces), connect to localhost
/*
* and load the index.html of the app.
* If config.address is not defined or is an empty string (listening on all interfaces), connect to localhost
*/
let prefix;
if ((config["tls"] !== null && config["tls"]) || config.useHttps) {
if ((config.tls !== null && config.tls) || config.useHttps) {
prefix = "https://";
} else {
prefix = "http://";
@@ -82,7 +112,7 @@ function createWindow () {
const port = process.env.MM_PORT || config.port;
mainWindow.loadURL(`${prefix}${address}:${port}`);
// Open the DevTools if run with "npm start dev"
// Open the DevTools if run with "node --run start:dev"
if (process.argv.includes("dev")) {
if (process.env.JEST_WORKER_ID !== undefined) {
// if we are running with jest
@@ -121,11 +151,11 @@ function createWindow () {
//remove response headers that prevent sites of being embedded into iframes if configured
mainWindow.webContents.session.webRequest.onHeadersReceived((details, callback) => {
let curHeaders = details.responseHeaders;
if (config["ignoreXOriginHeader"] || false) {
if (config.ignoreXOriginHeader || false) {
curHeaders = Object.fromEntries(Object.entries(curHeaders).filter((header) => !(/x-frame-options/i).test(header[0])));
}
if (config["ignoreContentSecurityPolicy"] || false) {
if (config.ignoreContentSecurityPolicy || false) {
curHeaders = Object.fromEntries(Object.entries(curHeaders).filter((header) => !(/content-security-policy/i).test(header[0])));
}
@@ -148,14 +178,18 @@ app.on("window-all-closed", function () {
});
app.on("activate", function () {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
/*
* On OS X it's common to re-create a window in the app when the
* dock icon is clicked and there are no other windows open.
*/
if (mainWindow === null) {
createWindow();
}
});
/* This method will be called when SIGINT is received and will call
/*
* This method will be called when SIGINT is received and will call
* each node_helper's stop function if it exists. Added to fix #1056
*
* Note: this is only used if running Electron. Otherwise
@@ -186,8 +220,10 @@ if (process.env.clientonly) {
});
}
// Start the core application if server is run on localhost
// This starts all node helpers and starts the webserver.
/*
* Start the core application if server is run on localhost
* This starts all node helpers and starts the webserver.
*/
if (["localhost", "127.0.0.1", "::1", "::ffff:127.0.0.1", undefined].includes(config.address)) {
core.start().then((c) => {
config = c;

View File

@@ -1,11 +1,5 @@
/* global defaultModules, vendor */
/* MagicMirror²
* Module and File loaders.
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
const Loader = (function () {
/* Create helper variables */
@@ -16,6 +10,15 @@ const Loader = (function () {
/* Private Methods */
/**
* Retrieve object of env variables.
* @returns {object} with key: values as assembled in js/server_functions.js
*/
const getEnvVars = async function () {
const res = await fetch(`${location.protocol}//${location.host}${config.basePath}env`);
return JSON.parse(await res.text());
};
/**
* Loops through all modules and requests start for every module.
*/
@@ -56,26 +59,36 @@ const Loader = (function () {
* @returns {object[]} module data as configured in config
*/
const getAllModules = function () {
return config.modules;
const AllModules = config.modules.filter((module) => (module.module !== undefined) && (MM.getAvailableModulePositions.indexOf(module.position) > -1 || typeof (module.position) === "undefined"));
return AllModules;
};
/**
* Generate array with module information including module paths.
* @returns {object[]} Module information.
*/
const getModuleData = function () {
const getModuleData = async function () {
const modules = getAllModules();
const moduleFiles = [];
const envVars = await getEnvVars();
modules.forEach(function (moduleData, index) {
const module = moduleData.module;
const elements = module.split("/");
const moduleName = elements[elements.length - 1];
let moduleFolder = `${config.paths.modules}/${module}`;
let moduleFolder = `${envVars.modulesDir}/${module}`;
if (defaultModules.indexOf(moduleName) !== -1) {
moduleFolder = `${config.paths.modules}/default/${module}`;
const defaultModuleFolder = `modules/default/${module}`;
if (window.name !== "jsdom") {
moduleFolder = defaultModuleFolder;
} else {
// running in Jest, allow defaultModules placed under moduleDir for testing
if (envVars.modulesDir === "modules") {
moduleFolder = defaultModuleFolder;
}
}
}
if (moduleData.disabled === true) {
@@ -95,7 +108,8 @@ const Loader = (function () {
header: moduleData.header,
configDeepMerge: typeof moduleData.configDeepMerge === "boolean" ? moduleData.configDeepMerge : false,
config: moduleData.config,
classes: typeof moduleData.classes !== "undefined" ? `${moduleData.classes} ${module}` : module
classes: typeof moduleData.classes !== "undefined" ? `${moduleData.classes} ${module}` : module,
order: (typeof moduleData.order === "number" && Number.isInteger(moduleData.order)) ? moduleData.order : 0
});
});
@@ -171,6 +185,7 @@ const Loader = (function () {
};
script.onerror = function () {
Log.error("Error on loading script:", fileName);
script.remove();
resolve();
};
document.getElementsByTagName("body")[0].appendChild(script);
@@ -188,6 +203,7 @@ const Loader = (function () {
};
stylesheet.onerror = function () {
Log.error("Error on loading stylesheet:", fileName);
stylesheet.remove();
resolve();
};
document.getElementsByTagName("head")[0].appendChild(stylesheet);
@@ -202,27 +218,22 @@ const Loader = (function () {
* Load all modules as defined in the config.
*/
async loadModules () {
let moduleData = getModuleData();
const moduleData = await getModuleData();
const envVars = await getEnvVars();
const customCss = envVars.customCss;
/**
* @returns {Promise<void>} when all modules are loaded
*/
const loadNextModule = async function () {
if (moduleData.length > 0) {
const nextModule = moduleData[0];
await loadModule(nextModule);
moduleData = moduleData.slice(1);
await loadNextModule();
} else {
// All modules loaded. Load custom.css
// This is done after all the modules so we can
// overwrite all the defined styles.
await loadFile(config.customCss);
// custom.css loaded. Start all modules.
await startModules();
}
};
await loadNextModule();
// Load all modules
for (const module of moduleData) {
await loadModule(module);
}
// Load custom.css
// Since this happens after loading the modules,
// it overwrites the default styles.
await loadFile(customCss);
// Start all modules.
await startModules();
},
/**
@@ -249,7 +260,7 @@ const Loader = (function () {
// This file is available in the vendor folder.
// Load it from this vendor folder.
loadedFiles.push(fileName.toLowerCase());
return loadFile(`${config.paths.vendor}/${vendor[fileName]}`);
return loadFile(`${vendor[fileName]}`);
}
// File not loaded yet.

View File

@@ -1,19 +1,49 @@
/* MagicMirror²
* Log
*
* This logger is very simple, but needs to be extended.
* This system can eventually be used to push the log messages to an external target.
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
// This logger is very simple, but needs to be extended.
(function (root, factory) {
if (typeof exports === "object") {
if (process.env.JEST_WORKER_ID === undefined) {
const { styleText } = require("node:util");
// add timestamps in front of log messages
require("console-stamp")(console, {
pattern: "yyyy-mm-dd HH:MM:ss.l",
include: ["debug", "log", "info", "warn", "error"]
format: ":date(yyyy-mm-dd HH:MM:ss.l) :label(7) :msg",
tokens: {
label: (arg) => {
const { method, defaultTokens } = arg;
let label = defaultTokens.label(arg);
switch (method) {
case "error":
label = styleText("red", label);
break;
case "warn":
label = styleText("yellow", label);
break;
case "debug":
label = styleText("bgBlue", label);
break;
case "info":
label = styleText("blue", label);
break;
}
return label;
},
msg: (arg) => {
const { method, defaultTokens } = arg;
let msg = defaultTokens.msg(arg);
switch (method) {
case "error":
msg = styleText("red", msg);
break;
case "warn":
msg = styleText("yellow", msg);
break;
case "info":
msg = styleText("blue", msg);
break;
}
return msg;
}
}
});
}
// Node, CommonJS-like

View File

@@ -1,11 +1,5 @@
/* global Loader, defaults, Translator, addAnimateCSS, removeAnimateCSS, AnimateCSSIn, AnimateCSSOut */
/* global Loader, defaults, Translator, addAnimateCSS, removeAnimateCSS, AnimateCSSIn, AnimateCSSOut, modulePositions */
/* MagicMirror²
* Main System
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
const MM = (function () {
let modules = [];
@@ -36,6 +30,8 @@ const MM = (function () {
dom.className = `module ${dom.className} ${module.data.classes}`;
}
dom.style.order = (typeof module.data.order === "number" && Number.isInteger(module.data.order)) ? module.data.order : 0;
dom.opacity = 0;
wrapper.appendChild(dom);
@@ -292,9 +288,9 @@ const MM = (function () {
Log.debug(`${module.identifier} Force remove animateIn (in hide): ${module.hasAnimateIn}`);
module.hasAnimateIn = false;
}
// haveAnimateName for verify if we are using AninateCSS library
// haveAnimateName for verify if we are using AnimateCSS library
// we check AnimateCSSOut Array for validate it
// and finaly return the animate name or `null` (for default MM² animation)
// and finally return the animate name or `null` (for default MM² animation)
let haveAnimateName = null;
// check if have valid animateOut in module definition (module.data.animateOut)
if (module.data.animateOut && AnimateCSSOut.indexOf(module.data.animateOut) !== -1) haveAnimateName = module.data.animateOut;
@@ -363,7 +359,7 @@ const MM = (function () {
}
}
// Check if there are no more lockstrings set, or the force option is set.
// Check if there are no more lockStrings set, or the force option is set.
// Otherwise cancel show action.
if (module.lockStrings.length !== 0 && options.force !== true) {
Log.log(`Will not show ${module.name}. LockStrings active: ${module.lockStrings.join(",")}`);
@@ -386,7 +382,7 @@ const MM = (function () {
module.hidden = false;
// If forced show, clean current lockstrings.
// If forced show, clean current lockStrings.
if (module.lockStrings.length !== 0 && options.force === true) {
Log.log(`Force show of module: ${module.name}`);
module.lockStrings = [];
@@ -396,9 +392,9 @@ const MM = (function () {
if (moduleWrapper !== null) {
clearTimeout(module.showHideTimer);
// haveAnimateName for verify if we are using AninateCSS library
// haveAnimateName for verify if we are using AnimateCSS library
// we check AnimateCSSIn Array for validate it
// and finaly return the animate name or `null` (for default MM² animation)
// and finally return the animate name or `null` (for default MM² animation)
let haveAnimateName = null;
// check if have valid animateOut in module definition (module.data.animateIn)
if (module.data.animateIn && AnimateCSSIn.indexOf(module.data.animateIn) !== -1) haveAnimateName = module.data.animateIn;
@@ -456,10 +452,9 @@ const MM = (function () {
* an ugly top margin. By using this function, the top bar will be hidden if the
* update notification is not visible.
*/
const updateWrapperStates = function () {
const positions = ["top_bar", "top_left", "top_center", "top_right", "upper_third", "middle_center", "lower_third", "bottom_left", "bottom_center", "bottom_right", "bottom_bar", "fullscreen_above", "fullscreen_below"];
positions.forEach(function (position) {
const updateWrapperStates = function () {
modulePositions.forEach(function (position) {
const wrapper = selectWrapper(position);
const moduleWrappers = wrapper.getElementsByClassName("module");
@@ -470,7 +465,8 @@ const MM = (function () {
}
});
wrapper.style.display = showWrapper ? "block" : "none";
// move container definitions to main CSS
wrapper.className = showWrapper ? "container" : "container hidden";
});
};
@@ -615,13 +611,13 @@ const MM = (function () {
// if server startup time has changed (which means server was restarted)
// the client reloads the mm page
try {
const res = await fetch(`${location.protocol}//${location.host}/startup`);
const res = await fetch(`${location.protocol}//${location.host}${config.basePath}startup`);
const curr = await res.text();
if (startUp === "") startUp = curr;
if (startUp !== curr) {
startUp = "";
window.location.reload(true);
console.warn("Refreshing Website because server was restarted");
Log.warn("Refreshing Website because server was restarted");
}
} catch (err) {
Log.error(`MagicMirror not reachable: ${err}`);
@@ -673,7 +669,10 @@ const MM = (function () {
}
// Further implementation is done in the private method.
updateDom(module, updateOptions);
updateDom(module, updateOptions).then(function () {
// Once the update is complete and rendered, send a notification to the module that the DOM has been updated
sendNotification("MODULE_DOM_UPDATED", null, null, module);
});
},
/**
@@ -707,7 +706,10 @@ const MM = (function () {
showModule (module, speed, callback, options) {
// do not change module.hidden yet, only if we really show it later
showModule(module, speed, callback, options);
}
},
// Return all available module positions.
getAvailableModulePositions: modulePositions
};
}());

View File

@@ -1,17 +1,16 @@
/* global Class, cloneObject, Loader, MMSocket, nunjucks, Translator */
/* MagicMirror²
/*
* Module Blueprint.
* @typedef {Object} Module
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
const Module = Class.extend({
/*********************************************************
/**
********************************************************
* All methods (and properties) below can be subclassed. *
*********************************************************/
********************************************************
*/
// Set the minimum MagicMirror² module version for this module.
requiresVersion: "2.0.0",
@@ -22,13 +21,17 @@ const Module = Class.extend({
// Timer reference used for showHide animation callbacks.
showHideTimer: null,
// Array to store lockStrings. These strings are used to lock
// visibility when hiding and showing module.
/*
* Array to store lockStrings. These strings are used to lock
* visibility when hiding and showing module.
*/
lockStrings: [],
// Storage of the nunjucks Environment,
// This should not be referenced directly.
// Use the nunjucksEnvironment() to get it.
/*
* Storage of the nunjucks Environment,
* This should not be referenced directly.
* Use the nunjucksEnvironment() to get it.
*/
_nunjucksEnvironment: null,
/**
@@ -193,9 +196,11 @@ const Module = Class.extend({
Log.log(`${this.name} is resumed.`);
},
/*********************************************
/**
********************************************
* The methods below don't need subclassing. *
*********************************************/
********************************************
*/
/**
* Set the module data.

18
js/module_functions.js Normal file
View File

@@ -0,0 +1,18 @@
/**
* Schedule the timer for the next update
* @param {object} timer The timer of the module
* @param {bigint} intervalMS interval in milliseconds
* @param {Function} callback function to call when the timer expires
*/
const scheduleTimer = function (timer, intervalMS, callback) {
if (process.env.JEST_WORKER_ID === undefined) {
// only set timer when not running in jest
let tmr = timer;
clearTimeout(tmr);
tmr = setTimeout(function () {
callback();
}, intervalMS);
}
};
module.exports = { scheduleTimer };

View File

@@ -1,9 +1,3 @@
/* MagicMirror²
* Node Helper Superclass
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
const express = require("express");
const Log = require("logger");
const Class = require("./class");
@@ -55,7 +49,8 @@ const NodeHelper = Class.extend({
this.path = path;
},
/* sendSocketNotification(notification, payload)
/*
* sendSocketNotification(notification, payload)
* Send a socket notification to the node helper.
*
* argument notification string - The identifier of the notification.
@@ -65,7 +60,8 @@ const NodeHelper = Class.extend({
this.io.of(this.name).emit(notification, payload);
},
/* setExpressApp(app)
/*
* setExpressApp(app)
* Sets the express app object for this module.
* This allows you to host files from the created webserver.
*
@@ -77,7 +73,8 @@ const NodeHelper = Class.extend({
app.use(`/${this.name}`, express.static(`${this.path}/public`));
},
/* setSocketIO(io)
/*
* setSocketIO(io)
* Sets the socket io object for this module.
* Binds message receiver.
*
@@ -89,20 +86,9 @@ const NodeHelper = Class.extend({
Log.log(`Connecting socket for: ${this.name}`);
io.of(this.name).on("connection", (socket) => {
// add a catch all event.
const onevent = socket.onevent;
socket.onevent = function (packet) {
const args = packet.data || [];
onevent.call(this, packet); // original call
packet.data = ["*"].concat(args);
onevent.call(this, packet); // additional call to catch-all
};
// register catch all.
socket.on("*", (notification, payload) => {
if (notification !== "*") {
this.socketNotificationReceived(notification, payload);
}
socket.onAny((notification, payload) => {
this.socketNotificationReceived(notification, payload);
});
});
}

View File

@@ -1,21 +1,15 @@
/* MagicMirror²
* Server
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
const fs = require("fs");
const http = require("http");
const https = require("https");
const path = require("path");
const fs = require("node:fs");
const http = require("node:http");
const https = require("node:https");
const path = require("node:path");
const express = require("express");
const ipfilter = require("express-ipfilter").IpFilter;
const helmet = require("helmet");
const socketio = require("socket.io");
const Log = require("logger");
const Utils = require("./utils");
const { cors, getConfig, getHtml, getVersion, getStartup } = require("./server_functions");
const { cors, getConfig, getHtml, getVersion, getStartup, getEnvVars } = require("./server_functions");
const vendor = require(`${__dirname}/vendor`);
/**
* Server
@@ -62,7 +56,7 @@ function Server (config) {
server.listen(port, config.address || "localhost");
if (config.ipWhitelist instanceof Array && config.ipWhitelist.length === 0) {
Log.warn(Utils.colors.warn("You're using a full whitelist configuration to allow for all IPs"));
Log.warn("You're using a full whitelist configuration to allow for all IPs");
}
app.use(function (req, res, next) {
@@ -79,9 +73,13 @@ function Server (config) {
app.use(helmet(config.httpHeaders));
app.use("/js", express.static(__dirname));
// TODO add tests directory only when running tests?
const directories = ["/config", "/css", "/fonts", "/modules", "/vendor", "/translations", "/tests/configs", "/tests/mocks"];
for (const directory of directories) {
let directories = ["/config", "/css", "/modules", "/node_modules/animate.css", "/node_modules/@fontsource", "/node_modules/@fortawesome", "/translations", "/tests/configs", "/tests/mocks"];
for (const [key, value] of Object.entries(vendor)) {
const dirArr = value.split("/");
if (dirArr[0] === "node_modules") directories.push(`/${dirArr[0]}/${dirArr[1]}`);
}
const uniqDirs = [...new Set(directories)];
for (const directory of uniqDirs) {
app.use(directory, express.static(path.resolve(global.root_path + directory)));
}
@@ -93,6 +91,8 @@ function Server (config) {
app.get("/startup", (req, res) => getStartup(req, res));
app.get("/env", (req, res) => getEnvVars(req, res));
app.get("/", (req, res) => getHtml(req, res));
server.on("listening", () => {

View File

@@ -1,5 +1,5 @@
const fs = require("fs");
const path = require("path");
const fs = require("node:fs");
const path = require("node:path");
const Log = require("logger");
const startUp = new Date();
@@ -45,12 +45,12 @@ async function cors (req, res) {
url = match[1];
const headersToSend = getHeadersToSend(req.url);
const expectedRecievedHeaders = geExpectedRecievedHeaders(req.url);
const expectedReceivedHeaders = geExpectedReceivedHeaders(req.url);
Log.log(`cors url: ${url}`);
const response = await fetch(url, { headers: headersToSend });
for (const header of expectedRecievedHeaders) {
for (const header of expectedReceivedHeaders) {
const headerValue = response.headers.get(header);
if (header) res.set(header, headerValue);
}
@@ -89,16 +89,16 @@ function getHeadersToSend (url) {
* @param {string} url - The url containing the expected headers from the response.
* @returns {string[]} headers - The name of the expected headers.
*/
function geExpectedRecievedHeaders (url) {
const expectedRecievedHeaders = ["Content-Type"];
const expectedRecievedHeadersMatch = new RegExp("expectedheaders=(.+?)(&|$)", "g").exec(url);
if (expectedRecievedHeadersMatch) {
const headers = expectedRecievedHeadersMatch[1].split(",");
function geExpectedReceivedHeaders (url) {
const expectedReceivedHeaders = ["Content-Type"];
const expectedReceivedHeadersMatch = new RegExp("expectedheaders=(.+?)(&|$)", "g").exec(url);
if (expectedReceivedHeadersMatch) {
const headers = expectedReceivedHeadersMatch[1].split(",");
for (const header of headers) {
expectedRecievedHeaders.push(header);
expectedReceivedHeaders.push(header);
}
}
return expectedRecievedHeaders;
return expectedReceivedHeaders;
}
/**
@@ -109,6 +109,7 @@ function geExpectedRecievedHeaders (url) {
function getHtml (req, res) {
let html = fs.readFileSync(path.resolve(`${global.root_path}/index.html`), { encoding: "utf8" });
html = html.replace("#VERSION#", global.version);
html = html.replace("#TESTMODE#", global.mmTestMode);
let configFile = "config/config.js";
if (typeof global.configuration_file !== "undefined") {
@@ -128,4 +129,30 @@ function getVersion (req, res) {
res.send(global.version);
}
module.exports = { cors, getConfig, getHtml, getVersion, getStartup };
/**
* Gets environment variables needed in the browser.
* @returns {object} environment variables key: values
*/
function getEnvVarsAsObj () {
const obj = { modulesDir: `${config.foreignModulesDir}`, customCss: `${config.customCss}` };
if (process.env.MM_MODULES_DIR) {
obj.modulesDir = process.env.MM_MODULES_DIR.replace(`${global.root_path}/`, "");
}
if (process.env.MM_CUSTOMCSS_FILE) {
obj.customCss = process.env.MM_CUSTOMCSS_FILE.replace(`${global.root_path}/`, "");
}
return obj;
}
/**
* Gets environment variables needed in the browser.
* @param {Request} req - the request
* @param {Response} res - the result
*/
function getEnvVars (req, res) {
const obj = getEnvVarsAsObj();
res.send(obj);
}
module.exports = { cors, getConfig, getHtml, getVersion, getStartup, getEnvVars, getEnvVarsAsObj };

View File

@@ -1,11 +1,5 @@
/* global io */
/* MagicMirror²
* TODO add description
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
const MMSocket = function (moduleName) {
if (typeof moduleName !== "string") {
throw new Error("Please set the module name for the MMSocket.");

View File

@@ -1,11 +1,5 @@
/* global translations */
/* MagicMirror²
* Translator (l10n)
*
* By Christopher Fenner https://github.com/CFenner
* MIT Licensed.
*/
const Translator = (function () {
/**
@@ -21,14 +15,14 @@ const Translator = (function () {
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
// needs error handler try/catch at least
let fileinfo = null;
let fileInfo = null;
try {
fileinfo = JSON.parse(xhr.responseText);
fileInfo = JSON.parse(xhr.responseText);
} catch (exception) {
// nothing here, but don't die
Log.error(` loading json file =${file} failed`);
}
resolve(fileinfo);
resolve(fileInfo);
}
};
xhr.send(null);

View File

@@ -1,16 +1,85 @@
/* MagicMirror²
* Utils
*
* By Rodrigo Ramírez Norambuena https://rodrigoramirez.com
* MIT Licensed.
*/
const colors = require("colors/safe");
const path = require("node:path");
const rootPath = path.resolve(`${__dirname}/../`);
const Log = require(`${rootPath}/js/logger.js`);
const os = require("node:os");
const fs = require("node:fs");
const si = require("systeminformation");
const modulePositions = []; // will get list from index.html
const regionRegEx = /"region ([^"]*)/i;
const indexFileName = "index.html";
const discoveredPositionsJSFilename = "js/positions.js";
module.exports = {
colors: {
warn: colors.yellow,
error: colors.red,
info: colors.blue,
pass: colors.green
async logSystemInformation (mirrorVersion) {
try {
const system = await si.system();
const osInfo = await si.osInfo();
const versions = await si.versions();
const usedNodeVersion = process.version.replace("v", "");
const installedNodeVersion = versions.node;
const totalRam = (os.totalmem() / 1024 / 1024).toFixed(2);
const freeRam = (os.freemem() / 1024 / 1024).toFixed(2);
const usedRam = ((os.totalmem() - os.freemem()) / 1024 / 1024).toFixed(2);
let systemDataString = [
"\n#### System Information ####",
`- SYSTEM: manufacturer: ${system.manufacturer}; model: ${system.model}; virtual: ${system.virtual}; MM: ${mirrorVersion}`,
`- OS: platform: ${osInfo.platform}; distro: ${osInfo.distro}; release: ${osInfo.release}; arch: ${osInfo.arch}; kernel: ${versions.kernel}`,
`- VERSIONS: electron: ${process.versions.electron}; used node: ${usedNodeVersion}; installed node: ${installedNodeVersion}; npm: ${versions.npm}; pm2: ${versions.pm2}`,
`- ENV: XDG_SESSION_TYPE: ${process.env.XDG_SESSION_TYPE}; MM_CONFIG_FILE: ${process.env.MM_CONFIG_FILE}`,
` WAYLAND_DISPLAY: ${process.env.WAYLAND_DISPLAY}; DISPLAY: ${process.env.DISPLAY}; ELECTRON_ENABLE_GPU: ${process.env.ELECTRON_ENABLE_GPU}`,
`- RAM: total: ${totalRam} MB; free: ${freeRam} MB; used: ${usedRam} MB`,
`- OTHERS: uptime: ${Math.floor(os.uptime() / 60)} minutes; timeZone: ${Intl.DateTimeFormat().resolvedOptions().timeZone}`
].join("\n");
Log.info(systemDataString);
// Return is currently only for jest
return systemDataString;
} catch (error) {
Log.error(error);
}
},
// return all available module positions
getAvailableModulePositions () {
return modulePositions;
},
// return if position is on modulePositions Array (true/false)
moduleHasValidPosition (position) {
if (this.getAvailableModulePositions().indexOf(position) === -1) return false;
return true;
},
getModulePositions () {
// if not already discovered
if (modulePositions.length === 0) {
// get the lines of the index.html
const lines = fs.readFileSync(indexFileName).toString().split("\n");
// loop thru the lines
lines.forEach((line) => {
// run the regex on each line
const results = regionRegEx.exec(line);
// if the regex returned something
if (results && results.length > 0) {
// get the position parts and replace space with underscore
const positionName = results[1].replace(" ", "_");
// add it to the list
modulePositions.push(positionName);
}
});
try {
fs.writeFileSync(discoveredPositionsJSFilename, `const modulePositions=${JSON.stringify(modulePositions)}`);
}
catch (error) {
Log.error("unable to write js/positions.js with the discovered module positions\nmake the MagicMirror/js folder writeable by the user starting MagicMirror");
}
}
// return the list to the caller
return modulePositions;
}
};

View File

@@ -1,9 +1,3 @@
/* MagicMirror²
* Vendor File Definition
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
const vendor = {
"moment.js": "node_modules/moment/min/moment-with-locales.js",
"moment-timezone.js": "node_modules/moment-timezone/builds/moment-timezone-with-data.js",
@@ -11,7 +5,8 @@ const vendor = {
"weather-icons-wind.css": "node_modules/weathericons/css/weather-icons-wind.css",
"font-awesome.css": "css/font-awesome.css",
"nunjucks.js": "node_modules/nunjucks/browser/nunjucks.min.js",
"suncalc.js": "node_modules/suncalc/suncalc.js"
"suncalc.js": "node_modules/suncalc/suncalc.js",
"croner.js": "node_modules/croner/dist/croner.umd.js"
};
if (typeof module !== "undefined") {

BIN
mm2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@@ -1,11 +1,5 @@
/* global NotificationFx */
/* MagicMirror²
* Module: alert
*
* By Paul-Vincent Roll https://paulvincentroll.com/
* MIT Licensed.
*/
Module.register("alert", {
alerts: {},
@@ -31,6 +25,7 @@ Module.register("alert", {
da: "translations/da.json",
de: "translations/de.json",
en: "translations/en.json",
eo: "translations/eo.json",
es: "translations/es.json",
fr: "translations/fr.json",
hu: "translations/hu.json",

View File

@@ -9,7 +9,7 @@
font-size: 70%;
position: relative;
display: table;
word-wrap: break-word;
overflow-wrap: break-word;
max-width: 100%;
border-width: 1px;
border-radius: 5px;
@@ -35,7 +35,7 @@
top: 40%;
width: 40%;
height: auto;
word-wrap: break-word;
overflow-wrap: break-word;
border-radius: 20px;
}

View File

@@ -0,0 +1,4 @@
{
"sysTitle": "MagicMirror² Ειδοποίηση",
"welcome": "Καλώς ήρθατε, η εκκίνηση ήταν επιτυχής!"
}

View File

@@ -0,0 +1,4 @@
{
"sysTitle": "MagicMirror²-sciigo",
"welcome": "Bonvenon, lanĉo sukcesis!"
}

View File

@@ -1,11 +1,5 @@
/* global CalendarUtils */
/* MagicMirror²
* Module: Calendar
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
Module.register("calendar", {
// Define module defaults
defaults: {
@@ -35,6 +29,7 @@ Module.register("calendar", {
dateEndFormat: "LT",
fullDayEventDateFormat: "MMM Do",
showEnd: false,
showEndsOnlyWithDuration: false,
getRelative: 6,
hidePrivate: false,
hideOngoing: false,
@@ -42,6 +37,7 @@ Module.register("calendar", {
hideDuplicates: true,
showTimeToday: false,
colored: false,
forceUseCurrentTime: false,
tableClass: "small",
calendars: [
{
@@ -81,14 +77,17 @@ Module.register("calendar", {
// Define required scripts.
getScripts () {
return ["calendarutils.js", "moment.js"];
return ["calendarutils.js", "moment.js", "moment-timezone.js"];
},
// Define required translations.
getTranslations () {
// The translations for the default modules are defined in the core translation files.
// Therefore we can just return false. Otherwise we should have returned a dictionary.
// If you're trying to build your own module including translations, check out the documentation.
/*
* The translations for the default modules are defined in the core translation files.
* Therefore we can just return false. Otherwise we should have returned a dictionary.
* If you're trying to build your own module including translations, check out the documentation.
*/
return false;
},
@@ -97,12 +96,12 @@ Module.register("calendar", {
Log.info(`Starting module: ${this.name}`);
if (this.config.colored) {
Log.warn("Your are using the deprecated config values 'colored'. Please switch to 'coloredSymbol' & 'coloredText'!");
Log.warn("Your are using the deprecated config values 'colored'. Please switch to 'coloredSymbol' & 'coloredText'!");
this.config.coloredText = true;
this.config.coloredSymbol = true;
}
if (this.config.coloredSymbolOnly) {
Log.warn("Your are using the deprecated config values 'coloredSymbolOnly'. Please switch to 'coloredSymbol' & 'coloredText'!");
Log.warn("Your are using the deprecated config values 'coloredSymbolOnly'. Please switch to 'coloredSymbol' & 'coloredText'!");
this.config.coloredText = false;
this.config.coloredSymbol = true;
}
@@ -152,8 +151,10 @@ Module.register("calendar", {
};
}
// tell helper to start a fetcher for this calendar
// fetcher till cycle
/*
* tell helper to start a fetcher for this calendar
* fetcher till cycle
*/
this.addCalendar(calendar.url, calendar.auth, calendarConfig);
});
@@ -167,12 +168,17 @@ Module.register("calendar", {
this.selfUpdate();
},
notificationReceived (notification, payload, sender) {
if (notification === "FETCH_CALENDAR") {
if (this.hasCalendarURL(payload.url)) {
this.sendSocketNotification(notification, { url: payload.url, id: this.identifier });
}
}
},
// Override socket notification handler.
socketNotificationReceived (notification, payload) {
if (notification === "FETCH_CALENDAR") {
this.sendSocketNotification(notification, { url: payload.url, id: this.identifier });
}
if (this.identifier !== payload.id) {
return;
@@ -212,10 +218,6 @@ Module.register("calendar", {
// Override dom generator.
getDom () {
const ONE_SECOND = 1000; // 1,000 milliseconds
const ONE_MINUTE = ONE_SECOND * 60;
const ONE_HOUR = ONE_MINUTE * 60;
const ONE_DAY = ONE_HOUR * 24;
const events = this.createEventList(true);
const wrapper = document.createElement("table");
wrapper.className = this.config.tableClass;
@@ -247,7 +249,9 @@ Module.register("calendar", {
let lastSeenDate = "";
events.forEach((event, index) => {
const dateAsString = moment(event.startDate, "x").format(this.config.dateFormat);
const eventStartDateMoment = this.timestampToMoment(event.startDate);
const eventEndDateMoment = this.timestampToMoment(event.endDate);
const dateAsString = eventStartDateMoment.format(this.config.dateFormat);
if (this.config.timeFormat === "dateheaders") {
if (lastSeenDate !== dateAsString) {
const dateRow = document.createElement("tr");
@@ -329,7 +333,7 @@ Module.register("calendar", {
repeatingCountTitle = this.countTitleForUrl(event.url);
if (repeatingCountTitle !== "") {
const thisYear = new Date(parseInt(event.startDate)).getFullYear(),
const thisYear = eventStartDateMoment.year(),
yearDiff = thisYear - event.firstYear;
repeatingCountTitle = `, ${yearDiff} ${repeatingCountTitle}`;
@@ -384,11 +388,15 @@ Module.register("calendar", {
timeWrapper.className = `time light ${this.config.flipDateHeaderTitle ? "align-right " : "align-left "}${this.timeClassForUrl(event.url)}`;
timeWrapper.style.paddingLeft = "2px";
timeWrapper.style.textAlign = this.config.flipDateHeaderTitle ? "right" : "left";
timeWrapper.innerHTML = moment(event.startDate, "x").format("LT");
timeWrapper.innerHTML = eventStartDateMoment.format("LT");
// Add endDate to dataheaders if showEnd is enabled
if (this.config.showEnd) {
timeWrapper.innerHTML += ` - ${CalendarUtils.capFirst(moment(event.endDate, "x").format("LT"))}`;
if (this.config.showEndsOnlyWithDuration && event.startDate === event.endDate) {
// no duration here, don't display end
} else {
timeWrapper.innerHTML += ` - ${CalendarUtils.capFirst(eventEndDateMoment.format("LT"))}`;
}
}
eventWrapper.appendChild(timeWrapper);
@@ -400,32 +408,43 @@ Module.register("calendar", {
const timeWrapper = document.createElement("td");
eventWrapper.appendChild(titleWrapper);
const now = new Date();
const now = moment();
if (this.config.timeFormat === "absolute") {
// Use dateFormat
timeWrapper.innerHTML = CalendarUtils.capFirst(moment(event.startDate, "x").format(this.config.dateFormat));
timeWrapper.innerHTML = CalendarUtils.capFirst(eventStartDateMoment.format(this.config.dateFormat));
// Add end time if showEnd
if (this.config.showEnd) {
timeWrapper.innerHTML += "-";
timeWrapper.innerHTML += CalendarUtils.capFirst(moment(event.endDate, "x").format(this.config.dateEndFormat));
// and has a duation
if (event.startDate !== event.endDate) {
timeWrapper.innerHTML += "-";
timeWrapper.innerHTML += CalendarUtils.capFirst(eventEndDateMoment.format(this.config.dateEndFormat));
}
}
// For full day events we use the fullDayEventDateFormat
if (event.fullDayEvent) {
//subtract one second so that fullDayEvents end at 23:59:59, and not at 0:00:00 one the next day
event.endDate -= ONE_SECOND;
timeWrapper.innerHTML = CalendarUtils.capFirst(moment(event.startDate, "x").format(this.config.fullDayEventDateFormat));
} else if (this.config.getRelative > 0 && event.startDate < now) {
eventEndDateMoment.subtract(1, "second");
timeWrapper.innerHTML = CalendarUtils.capFirst(eventStartDateMoment.format(this.config.fullDayEventDateFormat));
// only show end if requested and allowed and the dates are different
if (this.config.showEnd && !this.config.showEndsOnlyWithDuration && !eventStartDateMoment.isSame(eventEndDateMoment, "d")) {
timeWrapper.innerHTML += "-";
timeWrapper.innerHTML += CalendarUtils.capFirst(eventEndDateMoment.format(this.config.fullDayEventDateFormat));
} else if (!eventStartDateMoment.isSame(eventEndDateMoment, "d") && eventStartDateMoment.isBefore(now)) {
timeWrapper.innerHTML = CalendarUtils.capFirst(now.format(this.config.fullDayEventDateFormat));
}
} else if (this.config.getRelative > 0 && eventStartDateMoment.isBefore(now)) {
// Ongoing and getRelative is set
timeWrapper.innerHTML = CalendarUtils.capFirst(
this.translate("RUNNING", {
fallback: `${this.translate("RUNNING")} {timeUntilEnd}`,
timeUntilEnd: moment(event.endDate, "x").fromNow(true)
timeUntilEnd: eventEndDateMoment.fromNow(true)
})
);
} else if (this.config.urgency > 0 && event.startDate - now < this.config.urgency * ONE_DAY) {
} else if (this.config.urgency > 0 && eventStartDateMoment.diff(now, "d") < this.config.urgency) {
// Within urgency days
timeWrapper.innerHTML = CalendarUtils.capFirst(moment(event.startDate, "x").fromNow());
timeWrapper.innerHTML = CalendarUtils.capFirst(eventStartDateMoment.fromNow());
}
if (event.fullDayEvent && this.config.nextDaysRelative) {
// Full days events within the next two days
@@ -433,9 +452,9 @@ Module.register("calendar", {
timeWrapper.innerHTML = CalendarUtils.capFirst(this.translate("TODAY"));
} else if (event.yesterday) {
timeWrapper.innerHTML = CalendarUtils.capFirst(this.translate("YESTERDAY"));
} else if (event.startDate - now < ONE_DAY && event.startDate - now > 0) {
} else if (event.tomorrow) {
timeWrapper.innerHTML = CalendarUtils.capFirst(this.translate("TOMORROW"));
} else if (event.startDate - now < 2 * ONE_DAY && event.startDate - now > 0) {
} else if (event.dayAfterTomorrow) {
if (this.translate("DAYAFTERTOMORROW") !== "DAYAFTERTOMORROW") {
timeWrapper.innerHTML = CalendarUtils.capFirst(this.translate("DAYAFTERTOMORROW"));
}
@@ -443,23 +462,25 @@ Module.register("calendar", {
}
} else {
// Show relative times
if (event.startDate >= now || (event.fullDayEvent && event.today)) {
if (eventStartDateMoment.isSameOrAfter(now) || (event.fullDayEvent && eventEndDateMoment.diff(now, "days") === 0)) {
// Use relative time
if (!this.config.hideTime && !event.fullDayEvent) {
timeWrapper.innerHTML = CalendarUtils.capFirst(moment(event.startDate, "x").calendar(null, { sameElse: this.config.dateFormat }));
Log.debug("event not hidden and not fullday");
timeWrapper.innerHTML = `${CalendarUtils.capFirst(eventStartDateMoment.calendar(null, { sameElse: this.config.dateFormat }))}`;
} else {
timeWrapper.innerHTML = CalendarUtils.capFirst(
moment(event.startDate, "x").calendar(null, {
Log.debug("event full day or hidden");
timeWrapper.innerHTML = `${CalendarUtils.capFirst(
eventStartDateMoment.calendar(null, {
sameDay: this.config.showTimeToday ? "LT" : `[${this.translate("TODAY")}]`,
nextDay: `[${this.translate("TOMORROW")}]`,
nextWeek: "dddd",
sameElse: event.fullDayEvent ? this.config.fullDayEventDateFormat : this.config.dateFormat
})
);
)}`;
}
if (event.fullDayEvent) {
// Full days events within the next two days
if (event.today) {
if (event.today || (event.fullDayEvent && eventEndDateMoment.diff(now, "days") === 0)) {
timeWrapper.innerHTML = CalendarUtils.capFirst(this.translate("TODAY"));
} else if (event.dayBeforeYesterday) {
if (this.translate("DAYBEFOREYESTERDAY") !== "DAYBEFOREYESTERDAY") {
@@ -467,23 +488,25 @@ Module.register("calendar", {
}
} else if (event.yesterday) {
timeWrapper.innerHTML = CalendarUtils.capFirst(this.translate("YESTERDAY"));
} else if (event.startDate - now < ONE_DAY && event.startDate - now > 0) {
} else if (event.tomorrow) {
timeWrapper.innerHTML = CalendarUtils.capFirst(this.translate("TOMORROW"));
} else if (event.startDate - now < 2 * ONE_DAY && event.startDate - now > 0) {
} else if (event.dayAfterTomorrow) {
if (this.translate("DAYAFTERTOMORROW") !== "DAYAFTERTOMORROW") {
timeWrapper.innerHTML = CalendarUtils.capFirst(this.translate("DAYAFTERTOMORROW"));
}
}
} else if (event.startDate - now < this.config.getRelative * ONE_HOUR) {
Log.info("event fullday");
} else if (eventStartDateMoment.diff(now, "h") < this.config.getRelative) {
Log.info("not full day but within getrelative size");
// If event is within getRelative hours, display 'in xxx' time format or moment.fromNow()
timeWrapper.innerHTML = CalendarUtils.capFirst(moment(event.startDate, "x").fromNow());
timeWrapper.innerHTML = `${CalendarUtils.capFirst(eventStartDateMoment.fromNow())}`;
}
} else {
// Ongoing event
timeWrapper.innerHTML = CalendarUtils.capFirst(
this.translate("RUNNING", {
fallback: `${this.translate("RUNNING")} {timeUntilEnd}`,
timeUntilEnd: moment(event.endDate, "x").fromNow(true)
timeUntilEnd: eventEndDateMoment.fromNow(true)
})
);
}
@@ -562,97 +585,114 @@ Module.register("calendar", {
return false;
},
/**
* converts the given timestamp to a moment with a timezone
* @param {number} timestamp timestamp from an event
* @returns {moment.Moment} moment with a timezone
*/
timestampToMoment (timestamp) {
return moment(timestamp, "x").tz(moment.tz.guess());
},
/**
* Creates the sorted list of all events.
* @param {boolean} limitNumberOfEntries Whether to filter returned events for display.
* @returns {object[]} Array with events.
*/
createEventList (limitNumberOfEntries) {
const ONE_SECOND = 1000; // 1,000 milliseconds
const ONE_MINUTE = ONE_SECOND * 60;
const ONE_HOUR = ONE_MINUTE * 60;
const ONE_DAY = ONE_HOUR * 24;
let now = moment();
let today = now.clone().startOf("day");
let future = now.clone().startOf("day").add(this.config.maximumNumberOfDays, "days");
const now = new Date();
const today = moment().startOf("day");
const future = moment().startOf("day").add(this.config.maximumNumberOfDays, "days").toDate();
let events = [];
for (const calendarUrl in this.calendarData) {
const calendar = this.calendarData[calendarUrl];
let remainingEntries = this.maximumEntriesForUrl(calendarUrl);
let maxPastDaysCompare = now - this.maximumPastDaysForUrl(calendarUrl) * ONE_DAY;
let maxPastDaysCompare = now.clone().subtract(this.maximumPastDaysForUrl(calendarUrl), "days");
let by_url_calevents = [];
for (const e in calendar) {
const event = JSON.parse(JSON.stringify(calendar[e])); // clone object
const eventStartDateMoment = this.timestampToMoment(event.startDate);
const eventEndDateMoment = this.timestampToMoment(event.endDate);
if (this.config.hidePrivate && event.class === "PRIVATE") {
// do not add the current event, skip it
continue;
}
if (limitNumberOfEntries) {
if (event.endDate < maxPastDaysCompare) {
if (eventEndDateMoment.isBefore(maxPastDaysCompare)) {
continue;
}
if (this.config.hideOngoing && event.startDate < now) {
if (this.config.hideOngoing && eventStartDateMoment.isBefore(now)) {
continue;
}
if (this.config.hideDuplicates && this.listContainsEvent(events, event)) {
continue;
}
if (--remainingEntries < 0) {
break;
}
}
event.url = calendarUrl;
event.today = event.startDate >= today && event.startDate < today + ONE_DAY;
event.dayBeforeYesterday = event.startDate >= today - ONE_DAY * 2 && event.startDate < today - ONE_DAY;
event.yesterday = event.startDate >= today - ONE_DAY && event.startDate < today;
event.tomorrow = !event.today && event.startDate >= today + ONE_DAY && event.startDate < today + 2 * ONE_DAY;
event.dayAfterTomorrow = !event.tomorrow && event.startDate >= today + ONE_DAY * 2 && event.startDate < today + 3 * ONE_DAY;
event.today = eventStartDateMoment.isSame(now, "d");
event.dayBeforeYesterday = eventStartDateMoment.isSame(now.clone().subtract(2, "days"), "d");
event.yesterday = eventStartDateMoment.isSame(now.clone().subtract(1, "days"), "d");
event.tomorrow = eventStartDateMoment.isSame(now.clone().add(1, "days"), "d");
event.dayAfterTomorrow = eventStartDateMoment.isSame(now.clone().add(2, "days"), "d");
/* if sliceMultiDayEvents is set to true, multiday events (events exceeding at least one midnight) are sliced into days,
/*
* if sliceMultiDayEvents is set to true, multiday events (events exceeding at least one midnight) are sliced into days,
* otherwise, esp. in dateheaders mode it is not clear how long these events are.
*/
const maxCount = Math.ceil((event.endDate - 1 - moment(event.startDate, "x").endOf("day").format("x")) / ONE_DAY) + 1;
const maxCount = eventEndDateMoment.diff(eventStartDateMoment, "days");
if (this.config.sliceMultiDayEvents && maxCount > 1) {
const splitEvents = [];
let midnight
= moment(event.startDate, "x")
= eventStartDateMoment
.clone()
.startOf("day")
.add(1, "day")
.format("x");
.endOf("day");
let count = 1;
while (event.endDate > midnight) {
while (eventEndDateMoment.isAfter(midnight)) {
const thisEvent = JSON.parse(JSON.stringify(event)); // clone object
thisEvent.today = thisEvent.startDate >= today && thisEvent.startDate < today + ONE_DAY;
thisEvent.tomorrow = !thisEvent.today && thisEvent.startDate >= today + ONE_DAY && thisEvent.startDate < today + 2 * ONE_DAY;
thisEvent.endDate = midnight;
thisEvent.today = this.timestampToMoment(thisEvent.startDate).isSame(now, "d");
thisEvent.tomorrow = this.timestampToMoment(thisEvent.startDate).isSame(now.clone().add(1, "days"), "d");
thisEvent.endDate = midnight.clone().subtract(1, "day").format("x");
thisEvent.title += ` (${count}/${maxCount})`;
splitEvents.push(thisEvent);
event.startDate = midnight;
event.startDate = midnight.format("x");
count += 1;
midnight = moment(midnight, "x").add(1, "day").format("x"); // next day
midnight = midnight.clone().add(1, "day").endOf("day"); // next day
}
// Last day
event.title += ` (${count}/${maxCount})`;
event.today += event.startDate >= today && event.startDate < today + ONE_DAY;
event.tomorrow = !event.today && event.startDate >= today + ONE_DAY && event.startDate < today + 2 * ONE_DAY;
event.today += this.timestampToMoment(event.startDate).isSame(now, "d");
event.tomorrow = this.timestampToMoment(event.startDate).isSame(now.clone().add(1, "days"), "d");
splitEvents.push(event);
for (let splitEvent of splitEvents) {
if (splitEvent.endDate > now && splitEvent.endDate <= future) {
events.push(splitEvent);
if (this.timestampToMoment(splitEvent.endDate).isAfter(now) && this.timestampToMoment(splitEvent.endDate).isSameOrBefore(future)) {
by_url_calevents.push(splitEvent);
}
}
} else {
events.push(event);
by_url_calevents.push(event);
}
}
if (limitNumberOfEntries) {
// sort entries before clipping
by_url_calevents.sort(function (a, b) {
return a.startDate - b.startDate;
});
Log.debug(`pushing ${by_url_calevents.length} events to total with room for ${remainingEntries}`);
events = events.concat(by_url_calevents.slice(0, remainingEntries));
Log.debug(`events for calendar=${events.length}`);
} else {
events = events.concat(by_url_calevents);
}
}
Log.info(`sorting events count=${events.length}`);
events.sort(function (a, b) {
return a.startDate - b.startDate;
});
@@ -661,17 +701,22 @@ Module.register("calendar", {
return events;
}
// Limit the number of days displayed
// If limitDays is set > 0, limit display to that number of days
/*
* Limit the number of days displayed
* If limitDays is set > 0, limit display to that number of days
*/
if (this.config.limitDays > 0) {
let newEvents = [];
let lastDate = today.clone().subtract(1, "days").format("YYYYMMDD");
let lastDate = today.clone().subtract(1, "days");
let days = 0;
for (const ev of events) {
let eventDate = moment(ev.startDate, "x").format("YYYYMMDD");
// if date of event is later than lastdate
// check if we already are showing max unique days
if (eventDate > lastDate) {
let eventDate = this.timestampToMoment(ev.startDate);
/*
* if date of event is later than lastdate
* check if we already are showing max unique days
*/
if (eventDate.isAfter(lastDate)) {
// if the only entry in the first day is a full day event that day is not counted as unique
if (!this.config.limitDaysNeverSkip && newEvents.length === 1 && days === 1 && newEvents[0].fullDayEvent) {
days--;
@@ -687,7 +732,7 @@ Module.register("calendar", {
}
events = newEvents;
}
Log.info(`slicing events total maxcount=${this.config.maximumEntries}`);
return events.slice(0, this.config.maximumEntries);
},
@@ -858,9 +903,13 @@ Module.register("calendar", {
let p = this.getCalendarProperty(url, property, defaultValue);
if (property === "symbol" || property === "recurringSymbol" || property === "fullDaySymbol") {
const className = this.getCalendarProperty(url, "symbolClassName", this.config.defaultSymbolClassName);
p = className + p;
if (p instanceof Array) {
let t = [];
p.forEach((n) => { t.push(className + n); });
p = t;
}
else p = className + p;
}
if (!(p instanceof Array)) p = [p];
return p;
},

View File

@@ -1,15 +1,9 @@
/* MagicMirror²
* Node Helper: Calendar - CalendarFetcher
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
const https = require("https");
const https = require("node:https");
const ical = require("node-ical");
const Log = require("logger");
const NodeHelper = require("node_helper");
const CalendarFetcherUtils = require("./calendarfetcherutils");
const { scheduleTimer } = require("#module_functions");
/**
*
@@ -63,7 +57,7 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn
try {
data = ical.parseICS(responseData);
Log.debug(`parsed data=${JSON.stringify(data)}`);
Log.debug(`parsed data=${JSON.stringify(data, null, 2)}`);
events = CalendarFetcherUtils.filterEvents(data, {
excludedEvents,
includePastEvents,
@@ -72,28 +66,18 @@ const CalendarFetcher = function (url, reloadInterval, excludedEvents, maximumEn
});
} catch (error) {
fetchFailedCallback(this, error);
scheduleTimer();
scheduleTimer(reloadTimer, reloadInterval, fetchCalendar);
return;
}
this.broadcastEvents();
scheduleTimer();
scheduleTimer(reloadTimer, reloadInterval, fetchCalendar);
})
.catch((error) => {
fetchFailedCallback(this, error);
scheduleTimer();
scheduleTimer(reloadTimer, reloadInterval, fetchCalendar);
});
};
/**
* Schedule the timer for the next update.
*/
const scheduleTimer = function () {
clearTimeout(reloadTimer);
reloadTimer = setTimeout(function () {
fetchCalendar();
}, reloadInterval);
};
/* public methods */
/**

View File

@@ -1,121 +1,130 @@
/* MagicMirror²
* Calendar Fetcher Util Methods
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
/**
* @external Moment
*/
const path = require("path");
const moment = require("moment");
const moment = require("moment-timezone");
const zoneTable = require(path.join(__dirname, "windowsZones.json"));
const Log = require("../../../js/logger");
const CalendarFetcherUtils = {
/**
* Calculate the time correction, either dst/std or full day in cases where
* utc time is day before plus offset
* @param {object} event the event which needs adjustment
* @param {Date} date the date on which this event happens
* @returns {number} the necessary adjustment in hours
* Determine based on the title of an event if it should be excluded from the list of events
* TODO This seems like an overly complicated way to exclude events based on the title.
* @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.
*/
calculateTimezoneAdjustment (event, date) {
let adjustHours = 0;
// if a timezone was specified
if (!event.start.tz) {
Log.debug(" if no tz, guess based on now");
event.start.tz = moment.tz.guess();
}
Log.debug(`initial tz=${event.start.tz}`);
shouldEventBeExcluded (config, title) {
let filter = {
excluded: false,
until: null
};
for (let f in config.excludedEvents) {
let filter = config.excludedEvents[f],
testTitle = title.toLowerCase(),
until = null,
useRegex = false,
regexFlags = "g";
// if there is a start date specified
if (event.start.tz) {
// if this is a windows timezone
if (event.start.tz.includes(" ")) {
// use the lookup table to get theIANA name as moment and date don't know MS timezones
let tz = CalendarFetcherUtils.getIanaTZFromMS(event.start.tz);
Log.debug(`corrected TZ=${tz}`);
// watch out for unregistered windows timezone names
// if we had a successful lookup
if (tz) {
// change the timezone to the IANA name
event.start.tz = tz;
// Log.debug("corrected timezone="+event.start.tz)
if (filter instanceof Object) {
if (typeof filter.until !== "undefined") {
until = filter.until;
}
}
Log.debug(`corrected tz=${event.start.tz}`);
let current_offset = 0; // offset from TZ string or calculated
let mm = 0; // date with tz or offset
let start_offset = 0; // utc offset of created with tz
// if there is still an offset, lookup failed, use it
if (event.start.tz.startsWith("(")) {
const regex = /[+|-]\d*:\d*/;
const start_offsetString = event.start.tz.match(regex).toString().split(":");
let start_offset = parseInt(start_offsetString[0]);
start_offset *= event.start.tz[1] === "-" ? -1 : 1;
adjustHours = start_offset;
Log.debug(`defined offset=${start_offset} hours`);
current_offset = start_offset;
event.start.tz = "";
Log.debug(`ical offset=${current_offset} date=${date}`);
mm = moment(date);
let x = parseInt(moment(new Date()).utcOffset());
Log.debug(`net mins=${current_offset * 60 - x}`);
mm = mm.add(x - current_offset * 60, "minutes");
adjustHours = (current_offset * 60 - x) / 60;
event.start = mm.toDate();
Log.debug(`adjusted date=${event.start}`);
if (typeof filter.regex !== "undefined") {
useRegex = filter.regex;
}
// If additional advanced filtering is added in, this section
// must remain last as we overwrite the filter object with the
// filterBy string
if (filter.caseSensitive) {
filter = filter.filterBy;
testTitle = title;
} else if (useRegex) {
filter = filter.filterBy;
testTitle = title;
regexFlags += "i";
} else {
filter = filter.filterBy.toLowerCase();
}
} else {
// get the start time in that timezone
let es = moment(event.start);
// check for start date prior to start of daylight changing date
if (es.format("YYYY") < 2007) {
es.set("year", 2013); // if so, use a closer date
}
Log.debug(`start date/time=${es.toDate()}`);
start_offset = moment.tz(es, event.start.tz).utcOffset();
Log.debug(`start offset=${start_offset}`);
Log.debug(`start date/time w tz =${moment.tz(moment(event.start), event.start.tz).toDate()}`);
// get the specified date in that timezone
mm = moment.tz(moment(date), event.start.tz);
Log.debug(`event date=${mm.toDate()}`);
current_offset = mm.utcOffset();
filter = filter.toLowerCase();
}
Log.debug(`event offset=${current_offset} hour=${mm.format("H")} event date=${mm.toDate()}`);
// if the offset is greater than 0, east of london
if (current_offset !== start_offset) {
// big offset
Log.debug("offset");
let h = parseInt(mm.format("H"));
// check if the event time is less than the offset
if (h > 0 && h < Math.abs(current_offset) / 60) {
// if so, rrule created a wrong date (utc day, oops, with utc yesterday adjusted time)
// we need to fix that
//adjustHours = 24;
// Log.debug("adjusting date")
}
//-300 > -240
//if (Math.abs(current_offset) > Math.abs(start_offset)){
if (current_offset > start_offset) {
adjustHours -= 1;
Log.debug("adjust down 1 hour dst change");
//} else if (Math.abs(current_offset) < Math.abs(start_offset)) {
} else if (current_offset < start_offset) {
adjustHours += 1;
Log.debug("adjust up 1 hour dst change");
if (CalendarFetcherUtils.titleFilterApplies(testTitle, filter, useRegex, regexFlags)) {
if (until) {
filter.until = until;
} else {
filter.excluded = true;
}
break;
}
}
Log.debug(`adjustHours=${adjustHours}`);
return adjustHours;
return filter;
},
/**
* 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();
},
/**
* This function returns a list of moments for a recurring event.
* @param {object} event the current event which is a recurring event
* @param {moment.Moment} pastLocalMoment The past date to search for recurring events
* @param {moment.Moment} futureLocalMoment The future date to search for recurring events
* @param {number} durationInMs the duration of the event, this is used to take into account currently running events
* @returns {moment.Moment[]} All moments for the recurring event
*/
getMomentsFromRecurringEvent (event, pastLocalMoment, futureLocalMoment, durationInMs) {
const rule = event.rrule;
// can cause problems with e.g. birthdays before 1900
if ((rule.options && rule.origOptions && rule.origOptions.dtstart && rule.origOptions.dtstart.getFullYear() < 1900) || (rule.options && rule.options.dtstart && rule.options.dtstart.getFullYear() < 1900)) {
rule.origOptions.dtstart.setYear(1900);
rule.options.dtstart.setYear(1900);
}
// subtract the max of the duration of this event or 1 day to find events in the past that are currently still running and should therefor be displayed.
const oneDayInMs = 24 * 60 * 60000;
let searchFromDate = pastLocalMoment.clone().subtract(Math.max(durationInMs, oneDayInMs), "milliseconds").toDate();
let searchToDate = futureLocalMoment.clone().add(1, "days").toDate();
Log.debug(`Search for recurring events between: ${searchFromDate} and ${searchToDate}`);
// if until is set, and its a full day event, force the time to midnight. rrule gets confused with non-00 offset
// looks like MS Outlook sets the until time incorrectly for fullday events
if ((rule.options.until !== undefined) && CalendarFetcherUtils.isFullDayEvent(event)) {
Log.debug("fixup rrule until");
rule.options.until = moment(rule.options.until).clone().startOf("day").add(1, "day")
.toDate();
}
Log.debug("fix rrule start=", rule.options.dtstart);
Log.debug("event before rrule.between=", JSON.stringify(event, null, 2), "exdates=", event.exdate);
Log.debug(`RRule: ${rule.toString()}`);
rule.options.tzid = null; // RRule gets *very* confused with timezones
let dates = rule.between(searchFromDate, searchToDate, true, () => {
return true;
});
Log.debug(`Title: ${event.summary}, with dates: \n\n${JSON.stringify(dates)}\n`);
// shouldn't need this anymore, as RRULE not passed junk
dates = dates.filter((d) => {
return JSON.stringify(d) !== "null";
});
// Dates are returned in UTC timezone but with localdatetime because tzid is null.
// So we map the date to a moment using the original timezone of the event.
return dates.map((d) => (event.start.tz ? moment.tz(d, "UTC").tz(event.start.tz, true) : moment.tz(d, "UTC").tz(CalendarFetcherUtils.getLocalTimezone(), true)));
},
/**
@@ -127,32 +136,33 @@ const CalendarFetcherUtils = {
filterEvents (data, config) {
const newEvents = [];
// limitFunction doesn't do much limiting, see comment re: the dates
// array in rrule section below as to why we need to do the filtering
// ourselves
const limitFunction = function (date, i) {
return true;
};
const eventDate = function (event, time) {
return CalendarFetcherUtils.isFullDayEvent(event) ? moment(event[time], "YYYYMMDD") : moment(new Date(event[time]));
const startMoment = event[time].tz ? moment.tz(event[time], event[time].tz) : moment.tz(event[time], CalendarFetcherUtils.getLocalTimezone());
return CalendarFetcherUtils.isFullDayEvent(event) ? startMoment.startOf("day") : startMoment;
};
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.entries(data).forEach(([key, event]) => {
Log.debug("Processing entry...");
const now = new Date();
const today = moment().startOf("day").toDate();
const future
= moment()
.startOf("day")
.add(config.maximumNumberOfDays, "days")
.subtract(1, "seconds") // Subtract 1 second so that events that start on the middle of the night will not repeat.
.toDate();
let past = today;
if (config.includePastEvents) {
past = moment().startOf("day").subtract(config.maximumNumberOfDays, "days").toDate();
const title = CalendarFetcherUtils.getTitleFromEvent(event);
Log.debug(`title: ${title}`);
// Return quickly if event should be excluded.
let { excluded, eventFilterUntil } = this.shouldEventBeExcluded(config, title);
if (excluded) {
return;
}
// FIXME: Ugly fix to solve the facebook birthday issue.
@@ -165,292 +175,103 @@ const CalendarFetcherUtils = {
}
if (event.type === "VEVENT") {
Log.debug(`Event:\n${JSON.stringify(event)}`);
let startDate = eventDate(event, "start");
let endDate;
Log.debug(`Event:\n${JSON.stringify(event, null, 2)}`);
let eventStartMoment = eventDate(event, "start");
let eventEndMoment;
if (typeof event.end !== "undefined") {
endDate = eventDate(event, "end");
eventEndMoment = eventDate(event, "end");
} else if (typeof event.duration !== "undefined") {
endDate = startDate.clone().add(moment.duration(event.duration));
eventEndMoment = eventStartMoment.clone().add(moment.duration(event.duration));
} else {
if (!isFacebookBirthday) {
// make copy of start date, separate storage area
endDate = moment(startDate.format("x"), "x");
eventEndMoment = eventStartMoment.clone();
} else {
endDate = moment(startDate).add(1, "days");
eventEndMoment = eventStartMoment.clone().add(1, "days");
}
}
Log.debug(`start: ${startDate.toDate()}`);
Log.debug(`end:: ${endDate.toDate()}`);
Log.debug(`start: ${eventStartMoment.toDate()}`);
Log.debug(`end:: ${eventEndMoment.toDate()}`);
// Calculate the duration of the event for use with recurring events.
let duration = parseInt(endDate.format("x")) - parseInt(startDate.format("x"));
Log.debug(`duration: ${duration}`);
// FIXME: Since the parsed json object from node-ical comes with time information
// this check could be removed (?)
if (event.start.length === 8) {
startDate = startDate.startOf("day");
}
const title = CalendarFetcherUtils.getTitleFromEvent(event);
Log.debug(`title: ${title}`);
let excluded = false,
dateFilter = null;
for (let f in config.excludedEvents) {
let filter = config.excludedEvents[f],
testTitle = title.toLowerCase(),
until = null,
useRegex = false,
regexFlags = "g";
if (filter instanceof Object) {
if (typeof filter.until !== "undefined") {
until = filter.until;
}
if (typeof filter.regex !== "undefined") {
useRegex = filter.regex;
}
// If additional advanced filtering is added in, this section
// must remain last as we overwrite the filter object with the
// filterBy string
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)) {
if (until) {
dateFilter = until;
} else {
excluded = true;
}
break;
}
}
if (excluded) {
return;
}
const durationMs = eventEndMoment.valueOf() - eventStartMoment.valueOf();
Log.debug(`duration: ${durationMs}`);
const location = event.location || false;
const geo = event.geo || false;
const description = event.description || false;
if (typeof event.rrule !== "undefined" && event.rrule !== null && !isFacebookBirthday) {
const rule = event.rrule;
// TODO This should be a seperate function.
if (event.rrule && typeof event.rrule !== "undefined" && !isFacebookBirthday) {
// Recurring event.
let moments = CalendarFetcherUtils.getMomentsFromRecurringEvent(event, pastLocalMoment, futureLocalMoment, durationMs);
const pastMoment = moment(past);
const futureMoment = moment(future);
// can cause problems with e.g. birthdays before 1900
if ((rule.options && rule.origOptions && rule.origOptions.dtstart && rule.origOptions.dtstart.getFullYear() < 1900) || (rule.options && rule.options.dtstart && rule.options.dtstart.getFullYear() < 1900)) {
rule.origOptions.dtstart.setYear(1900);
rule.options.dtstart.setYear(1900);
}
// For recurring events, get the set of start dates that fall within the range
// of dates we're looking for.
// kblankenship1989 - to fix issue #1798, converting all dates to locale time first, then converting back to UTC time
let pastLocal = 0;
let futureLocal = 0;
if (CalendarFetcherUtils.isFullDayEvent(event)) {
Log.debug("fullday");
// if full day event, only use the date part of the ranges
pastLocal = pastMoment.toDate();
futureLocal = futureMoment.toDate();
Log.debug(`pastLocal: ${pastLocal}`);
Log.debug(`futureLocal: ${futureLocal}`);
} else {
// if we want past events
if (config.includePastEvents) {
// use the calculated past time for the between from
pastLocal = pastMoment.toDate();
} else {
// otherwise use NOW.. cause we shouldn't use any before now
pastLocal = moment().toDate(); //now
}
futureLocal = futureMoment.toDate(); // future
}
Log.debug(`Search for recurring events between: ${pastLocal} and ${futureLocal}`);
let dates = rule.between(pastLocal, futureLocal, true, limitFunction);
Log.debug(`Title: ${event.summary}, with dates: ${JSON.stringify(dates)}`);
dates = dates.filter((d) => {
if (JSON.stringify(d) === "null") return false;
else return true;
});
// The "dates" array contains the set of dates within our desired date range range that are valid
// for the recurrence rule. *However*, it's possible for us to have a specific recurrence that
// had its date changed from outside the range to inside the range. For the time being,
// we'll handle this by adding *all* recurrence entries into the set of dates that we check,
// because the logic below will filter out any recurrences that don't actually belong within
// our display range.
// Would be great if there was a better way to handle this.
Log.debug(`event.recurrences: ${event.recurrences}`);
if (event.recurrences !== undefined) {
for (let r in event.recurrences) {
// Only add dates that weren't already in the range we added from the rrule so that
// we don"t double-add those events.
if (moment(new Date(r)).isBetween(pastMoment, futureMoment) !== true) {
dates.push(new Date(r));
}
}
}
// Loop through the set of date entries to see which recurrences should be added to our event list.
for (let d in dates) {
let date = dates[d];
// Loop through the set of moment entries to see which recurrences should be added to our event list.
// TODO This should create an event per moment so we can change anything we want.
for (let m in moments) {
let curEvent = event;
let showRecurrence = true;
let recurringEventStartMoment = moments[m].tz(CalendarFetcherUtils.getLocalTimezone()).clone();
let recurringEventEndMoment = recurringEventStartMoment.clone().add(durationMs, "ms");
// set the time information in the date to equal the time information in the event
date.setUTCHours(curEvent.start.getUTCHours(), curEvent.start.getUTCMinutes(), curEvent.start.getUTCSeconds(), curEvent.start.getUTCMilliseconds());
// Get the offset of today where we are processing
// This will be the correction, we need to apply.
let nowOffset = new Date().getTimezoneOffset();
// For full day events, the time might be off from RRULE/Luxon problem
// Get time zone offset of the rule calculated event
let dateoffset = date.getTimezoneOffset();
// Reduce the time by the following offset.
Log.debug(` recurring date is ${date} offset is ${dateoffset}`);
let dh = moment(date).format("HH");
Log.debug(` recurring date is ${date} offset is ${dateoffset / 60} Hour is ${dh}`);
if (CalendarFetcherUtils.isFullDayEvent(event)) {
Log.debug("Fullday");
// If the offset is negative (east of GMT), where the problem is
if (dateoffset < 0) {
if (dh < Math.abs(dateoffset / 60)) {
// if the rrule byweekday WAS explicitly set , correct it
// reduce the time by the offset
if (curEvent.rrule.origOptions.byweekday !== undefined) {
// Apply the correction to the date/time to get it UTC relative
date = new Date(date.getTime() - Math.abs(24 * 60) * 60000);
}
// the duration was calculated way back at the top before we could correct the start time..
// fix it for this event entry
//duration = 24 * 60 * 60 * 1000;
Log.debug(`new recurring date1 fulldate is ${date}`);
}
} else {
// if the timezones are the same, correct date if needed
//if (event.start.tz === moment.tz.guess()) {
// if the date hour is less than the offset
if (24 - dh <= Math.abs(dateoffset / 60)) {
// if the rrule byweekday WAS explicitly set , correct it
if (curEvent.rrule.origOptions.byweekday !== undefined) {
// apply the correction to the date/time back to right day
date = new Date(date.getTime() + Math.abs(24 * 60) * 60000);
}
// the duration was calculated way back at the top before we could correct the start time..
// fix it for this event entry
//duration = 24 * 60 * 60 * 1000;
Log.debug(`new recurring date2 fulldate is ${date}`);
}
//}
}
} else {
// not full day, but luxon can still screw up the date on the rule processing
// we need to correct the date to get back to the right event for
if (dateoffset < 0) {
// if the date hour is less than the offset
if (dh <= Math.abs(dateoffset / 60)) {
// if the rrule byweekday WAS explicitly set , correct it
if (curEvent.rrule.origOptions.byweekday !== undefined) {
// Reduce the time by t:
// Apply the correction to the date/time to get it UTC relative
date = new Date(date.getTime() - Math.abs(24 * 60) * 60000);
}
// the duration was calculated way back at the top before we could correct the start time..
// fix it for this event entry
//duration = 24 * 60 * 60 * 1000;
Log.debug(`new recurring date1 is ${date}`);
}
} else {
// if the timezones are the same, correct date if needed
//if (event.start.tz === moment.tz.guess()) {
// if the date hour is less than the offset
if (24 - dh <= Math.abs(dateoffset / 60)) {
// if the rrule byweekday WAS explicitly set , correct it
if (curEvent.rrule.origOptions.byweekday !== undefined) {
// apply the correction to the date/time back to right day
date = new Date(date.getTime() + Math.abs(24 * 60) * 60000);
}
// the duration was calculated way back at the top before we could correct the start time..
// fix it for this event entry
//duration = 24 * 60 * 60 * 1000;
Log.debug(`new recurring date2 is ${date}`);
}
//}
}
}
startDate = moment(date);
Log.debug(`Corrected startDate: ${startDate.toDate()}`);
let adjustDays = CalendarFetcherUtils.calculateTimezoneAdjustment(event, date);
// Remove the time information of each date by using its substring, using the following method:
// .toISOString().substring(0,10).
// since the date is given as ISOString with YYYY-MM-DDTHH:MM:SS.SSSZ
// (see https://momentjs.com/docs/#/displaying/as-iso-string/).
// This must be done after `date` is adjusted
const dateKey = date.toISOString().substring(0, 10);
let dateKey = recurringEventStartMoment.tz("UTC").format("YYYY-MM-DD");
Log.debug("event date dateKey=", dateKey);
// For each date that we're checking, it's possible that there is a recurrence override for that one day.
if (curEvent.recurrences !== undefined && curEvent.recurrences[dateKey] !== undefined) {
// We found an override, so for this recurrence, use a potentially different title, start date, and duration.
curEvent = curEvent.recurrences[dateKey];
startDate = moment(curEvent.start);
duration = parseInt(moment(curEvent.end).format("x")) - parseInt(startDate.format("x"));
if (curEvent.recurrences !== undefined) {
Log.debug("have recurrences=", curEvent.recurrences);
if (curEvent.recurrences[dateKey] !== undefined) {
Log.debug("have a recurrence match for dateKey=", dateKey);
// We found an override, so for this recurrence, use a potentially different title, start date, and duration.
curEvent = curEvent.recurrences[dateKey];
// Some event start/end dates don't have timezones
if (curEvent.start.tz) {
recurringEventStartMoment = moment(curEvent.start).tz(curEvent.start.tz).tz(CalendarFetcherUtils.getLocalTimezone());
} else {
recurringEventStartMoment = moment(curEvent.start).tz(CalendarFetcherUtils.getLocalTimezone());
}
if (curEvent.end.tz) {
recurringEventEndMoment = moment(curEvent.end).tz(curEvent.end.tz).tz(CalendarFetcherUtils.getLocalTimezone());
} else {
recurringEventEndMoment = moment(curEvent.end).tz(CalendarFetcherUtils.getLocalTimezone());
}
} else {
Log.debug("recurrence key ", dateKey, " doesn't match");
}
}
// If there's no recurrence override, check for an exception date. Exception dates represent exceptions to the rule.
else if (curEvent.exdate !== undefined && curEvent.exdate[dateKey] !== undefined) {
// This date is an exception date, which means we should skip it in the recurrence pattern.
showRecurrence = false;
if (curEvent.exdate !== undefined) {
Log.debug("have datekey=", dateKey, " exdates=", curEvent.exdate);
if (curEvent.exdate[dateKey] !== undefined) {
// This date is an exception date, which means we should skip it in the recurrence pattern.
showRecurrence = false;
}
}
Log.debug(`duration: ${duration}`);
endDate = moment(parseInt(startDate.format("x")) + duration, "x");
if (startDate.format("x") === endDate.format("x")) {
endDate = endDate.endOf("day");
if (recurringEventStartMoment.valueOf() === recurringEventEndMoment.valueOf()) {
recurringEventEndMoment = recurringEventEndMoment.endOf("day");
}
const recurrenceTitle = CalendarFetcherUtils.getTitleFromEvent(curEvent);
// If this recurrence ends before the start of the date range, or starts after the end of the date range, don"t add
// it to the event list.
if (endDate.isBefore(past) || startDate.isAfter(future)) {
if (recurringEventEndMoment.isBefore(pastLocalMoment) || recurringEventStartMoment.isAfter(futureLocalMoment)) {
showRecurrence = false;
}
if (CalendarFetcherUtils.timeFilterApplies(now, endDate, dateFilter)) {
if (CalendarFetcherUtils.timeFilterApplies(now, recurringEventEndMoment, eventFilterUntil)) {
showRecurrence = false;
}
if (showRecurrence === true) {
Log.debug(`saving event: ${description}`);
Log.debug(`saving event: ${recurrenceTitle}`);
newEvents.push({
title: recurrenceTitle,
startDate: (adjustDays ? (adjustDays > 0 ? startDate.add(adjustDays, "hours") : startDate.subtract(Math.abs(adjustDays), "hours")) : startDate).format("x"),
endDate: (adjustDays ? (adjustDays > 0 ? endDate.add(adjustDays, "hours") : endDate.subtract(Math.abs(adjustDays), "hours")) : endDate).format("x"),
startDate: recurringEventStartMoment.format("x"),
endDate: recurringEventEndMoment.format("x"),
fullDayEvent: CalendarFetcherUtils.isFullDayEvent(event),
recurringEvent: true,
class: event.class,
@@ -459,7 +280,10 @@ const CalendarFetcherUtils = {
geo: geo,
description: description
});
} else {
Log.debug("not saving event ", recurrenceTitle, eventStartMoment);
}
Log.debug(" ");
}
// End recurring event parsing.
} else {
@@ -468,45 +292,45 @@ const CalendarFetcherUtils = {
// Log.debug("full day event")
// if the start and end are the same, then make end the 'end of day' value (start is at 00:00:00)
if (fullDayEvent && startDate.format("x") === endDate.format("x")) {
endDate = endDate.endOf("day");
if (fullDayEvent && eventStartMoment.valueOf() === eventEndMoment.valueOf()) {
eventEndMoment = eventEndMoment.endOf("day");
}
if (config.includePastEvents) {
// Past event is too far in the past, so skip.
if (endDate < past) {
if (eventEndMoment < pastLocalMoment) {
return;
}
} else {
// It's not a fullday event, and it is in the past, so skip.
if (!fullDayEvent && endDate < new Date()) {
if (!fullDayEvent && eventEndMoment < now) {
return;
}
// It's a fullday event, and it is before today, So skip.
if (fullDayEvent && endDate <= today) {
if (fullDayEvent && eventEndMoment <= now.startOf("day")) {
return;
}
}
// It exceeds the maximumNumberOfDays limit, so skip.
if (startDate > future) {
if (eventStartMoment > futureLocalMoment) {
return;
}
if (CalendarFetcherUtils.timeFilterApplies(now, endDate, dateFilter)) {
if (CalendarFetcherUtils.timeFilterApplies(now, eventEndMoment, eventFilterUntil)) {
return;
}
// get correction for date saving and dst change between now and then
let adjustDays = CalendarFetcherUtils.calculateTimezoneAdjustment(event, startDate.toDate());
// Every thing is good. Add it to the list.
newEvents.push({
title: title,
startDate: (adjustDays ? (adjustDays > 0 ? startDate.add(adjustDays, "hours") : startDate.subtract(Math.abs(adjustDays), "hours")) : startDate).format("x"),
endDate: (adjustDays ? (adjustDays > 0 ? endDate.add(adjustDays, "hours") : endDate.subtract(Math.abs(adjustDays), "hours")) : endDate).format("x"),
startDate: eventStartMoment.format("x"),
endDate: eventEndMoment.format("x"),
fullDayEvent: fullDayEvent,
recurringEvent: false,
class: event.class,
firstYear: event.start.getFullYear(),
location: location,
geo: geo,
description: description
@@ -522,18 +346,6 @@ const CalendarFetcherUtils = {
return newEvents;
},
/**
* Lookup iana tz from windows
* @param {string} msTZName the timezone name to lookup
* @returns {string|null} the iana name or null of none is found
*/
getIanaTZFromMS (msTZName) {
// Get hash entry
const he = zoneTable[msTZName];
// If found return iana name, else null
return he ? he.iana[0] : null;
},
/**
* Gets the title from the event.
* @param {object} event The event object to check.
@@ -573,8 +385,8 @@ const CalendarFetcherUtils = {
/**
* Determines if the user defined time filter should apply
* @param {Date} now Date object using previously created object for consistency
* @param {Moment} endDate Moment object representing the event end date
* @param {moment.Moment} now Date object using previously created object for consistency
* @param {moment.Moment} endDate Moment object representing the event end date
* @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
*/
@@ -585,7 +397,7 @@ const CalendarFetcherUtils = {
increment = until[1].slice(-1) === "s" ? until[1] : `${until[1]}s`, // Massage the data for moment js
filterUntil = moment(endDate.format()).subtract(value, increment);
return now < filterUntil.format("x");
return now < filterUntil;
}
return false;

View File

@@ -1,9 +1,3 @@
/* MagicMirror²
* Calendar Util Methods
*
* By Rejas
* MIT Licensed.
*/
const CalendarUtils = {
/**

View File

@@ -1,12 +1,11 @@
/* CalendarFetcher Tester
/*
* CalendarFetcher Tester
* use this script with `node debug.js` to test the fetcher without the need
* of starting the MagicMirror² core. Adjust the values below to your desire.
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
// Alias modules mentioned in package.js under _moduleAliases.
require("module-alias/register");
const Log = require("../../../js/logger");
const CalendarFetcher = require("./calendarfetcher");
@@ -22,22 +21,22 @@ const auth = {
pass: pass
};
console.log("Create fetcher ...");
Log.log("Create fetcher ...");
const fetcher = new CalendarFetcher(url, fetchInterval, [], maximumEntries, maximumNumberOfDays, auth);
fetcher.onReceive(function (fetcher) {
console.log(fetcher.events());
console.log("------------------------------------------------------------");
Log.log(fetcher.events());
Log.log("------------------------------------------------------------");
process.exit(0);
});
fetcher.onError(function (fetcher, error) {
console.log("Fetcher error:");
console.log(error);
Log.log("Fetcher error:");
Log.log(error);
process.exit(1);
});
fetcher.startFetch();
console.log("Create fetcher done! ");
Log.log("Create fetcher done! ");

View File

@@ -1,9 +1,3 @@
/* MagicMirror²
* Node Helper: Calendar
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
const NodeHelper = require("node_helper");
const Log = require("logger");
const CalendarFetcher = require("./calendarfetcher");
@@ -53,9 +47,14 @@ module.exports = NodeHelper.create({
}
let fetcher;
let fetchIntervalCorrected;
if (typeof this.fetchers[identifier + url] === "undefined") {
Log.log(`Create new calendarfetcher for url: ${url} - Interval: ${fetchInterval}`);
fetcher = new CalendarFetcher(url, fetchInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, broadcastPastEvents, selfSignedCert);
if (fetchInterval < 60000) {
Log.warn(`fetchInterval for url ${url} must be >= 60000`);
fetchIntervalCorrected = 60000;
}
Log.log(`Create new calendarfetcher for url: ${url} - Interval: ${fetchIntervalCorrected || fetchInterval}`);
fetcher = new CalendarFetcher(url, fetchIntervalCorrected || fetchInterval, excludedEvents, maximumEntries, maximumNumberOfDays, auth, broadcastPastEvents, selfSignedCert);
fetcher.onReceive((fetcher) => {
this.broadcastEvents(fetcher, identifier);

View File

@@ -1,11 +1,5 @@
/* global SunCalc, formatTime */
/* MagicMirror²
* Module: Clock
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
Module.register("clock", {
// Module config defaults.
defaults: {
@@ -20,7 +14,7 @@ Module.register("clock", {
clockBold: false,
showDate: true,
showTime: true,
showWeek: false,
showWeek: false, // options: true, false, 'short'
dateFormat: "dddd, LL",
sendNotifications: false,
@@ -29,9 +23,9 @@ Module.register("clock", {
analogFace: "simple", // options: 'none', 'simple', 'face-###' (where ### is 001 to 012 inclusive)
analogPlacement: "bottom", // options: 'top', 'bottom', 'left', 'right'
analogShowDate: "top", // OBSOLETE, can be replaced with analogPlacement and showTime, options: false, 'top', or 'bottom'
secondsColor: "#888888",
secondsColor: "#888888", // DEPRECATED, use CSS instead. Class "clock-second-digital" for digital clock, "clock-second" for analog clock.
showSunTimes: false,
showSunTimes: false, // options: true, false, 'disableNextEvent'
showMoonTimes: false, // options: false, 'times' (rise/set), 'percent' (lit percent), 'phase' (current phase), or 'both' (percent & phase)
lat: 47.630539,
lon: -122.344147
@@ -42,7 +36,7 @@ Module.register("clock", {
},
// Define styles.
getStyles () {
return ["clock_styles.css"];
return ["clock_styles.css", "font-awesome.css"];
},
// Define start sequence.
start () {
@@ -105,13 +99,14 @@ Module.register("clock", {
analogWrapper.className = "clock-circle";
const digitalWrapper = document.createElement("div");
digitalWrapper.className = "digital";
digitalWrapper.style.gridArea = "center";
/************************************
* Create wrappers for DIGITAL clock
*/
const dateWrapper = document.createElement("div");
const timeWrapper = document.createElement("div");
const hoursWrapper = document.createElement("span");
const minutesWrapper = document.createElement("span");
const secondsWrapper = document.createElement("sup");
const periodWrapper = document.createElement("span");
const sunWrapper = document.createElement("div");
@@ -121,39 +116,40 @@ Module.register("clock", {
// Style Wrappers
dateWrapper.className = "date normal medium";
timeWrapper.className = "time bright large light";
secondsWrapper.className = "seconds dimmed";
hoursWrapper.className = "clock-hour-digital";
minutesWrapper.className = "clock-minute-digital";
secondsWrapper.className = "clock-second-digital dimmed";
sunWrapper.className = "sun dimmed small";
moonWrapper.className = "moon dimmed small";
weekWrapper.className = "week dimmed medium";
// Set content of wrappers.
// The moment().format("h") method has a bug on the Raspberry Pi.
// So we need to generate the timestring manually.
// See issue: https://github.com/MichMich/MagicMirror/issues/181
let timeString;
const now = moment();
if (this.config.timezone) {
now.tz(this.config.timezone);
}
let hourSymbol = "HH";
if (this.config.timeFormat !== 24) {
hourSymbol = "h";
}
if (this.config.clockBold) {
timeString = now.format(`${hourSymbol}[<span class="bold">]mm[</span>]`);
} else {
timeString = now.format(`${hourSymbol}:mm`);
}
if (this.config.showDate) {
dateWrapper.innerHTML = now.format(this.config.dateFormat);
digitalWrapper.appendChild(dateWrapper);
}
if (this.config.displayType !== "analog" && this.config.showTime) {
timeWrapper.innerHTML = timeString;
let hourSymbol = "HH";
if (this.config.timeFormat !== 24) {
hourSymbol = "h";
}
hoursWrapper.innerHTML = now.format(hourSymbol);
minutesWrapper.innerHTML = now.format("mm");
timeWrapper.appendChild(hoursWrapper);
if (this.config.clockBold) {
minutesWrapper.classList.add("bold");
} else {
timeWrapper.innerHTML += ":";
}
timeWrapper.appendChild(minutesWrapper);
secondsWrapper.innerHTML = now.format("ss");
if (this.config.showPeriodUpper) {
periodWrapper.innerHTML = now.format("A");
@@ -175,21 +171,28 @@ Module.register("clock", {
if (this.config.showSunTimes) {
const sunTimes = SunCalc.getTimes(now, this.config.lat, this.config.lon);
const isVisible = now.isBetween(sunTimes.sunrise, sunTimes.sunset);
let nextEvent;
if (now.isBefore(sunTimes.sunrise)) {
nextEvent = sunTimes.sunrise;
} else if (now.isBefore(sunTimes.sunset)) {
nextEvent = sunTimes.sunset;
} else {
const tomorrowSunTimes = SunCalc.getTimes(now.clone().add(1, "day"), this.config.lat, this.config.lon);
nextEvent = tomorrowSunTimes.sunrise;
let sunWrapperInnerHTML = "";
if (this.config.showSunTimes !== "disableNextEvent") {
let nextEvent;
if (now.isBefore(sunTimes.sunrise)) {
nextEvent = sunTimes.sunrise;
} else if (now.isBefore(sunTimes.sunset)) {
nextEvent = sunTimes.sunset;
} else {
const tomorrowSunTimes = SunCalc.getTimes(now.clone().add(1, "day"), this.config.lat, this.config.lon);
nextEvent = tomorrowSunTimes.sunrise;
}
const untilNextEvent = moment.duration(moment(nextEvent).diff(now));
const untilNextEventString = `${untilNextEvent.hours()}h ${untilNextEvent.minutes()}m`;
sunWrapperInnerHTML = `<span class="${isVisible ? "bright" : ""}"><i class="fas fa-sun" aria-hidden="true"></i> ${untilNextEventString}</span>`;
}
const untilNextEvent = moment.duration(moment(nextEvent).diff(now));
const untilNextEventString = `${untilNextEvent.hours()}h ${untilNextEvent.minutes()}m`;
sunWrapper.innerHTML
= `<span class="${isVisible ? "bright" : ""}"><i class="fas fa-sun" aria-hidden="true"></i> ${untilNextEventString}</span>`
+ `<span><i class="fas fa-arrow-up" aria-hidden="true"></i> ${formatTime(this.config, sunTimes.sunrise)}</span>`
+ `<span><i class="fas fa-arrow-down" aria-hidden="true"></i> ${formatTime(this.config, sunTimes.sunset)}</span>`;
sunWrapperInnerHTML += `<span><i class="fas fa-arrow-up" aria-hidden="true"></i> ${formatTime(this.config, sunTimes.sunrise)}</span>`
+ `<span><i class="fas fa-arrow-down" aria-hidden="true"></i> ${formatTime(this.config, sunTimes.sunset)}</span>`;
sunWrapper.innerHTML = sunWrapperInnerHTML;
digitalWrapper.appendChild(sunWrapper);
}
@@ -215,13 +218,18 @@ Module.register("clock", {
moonWrapper.innerHTML
= `<span class="${isVisible ? "bright" : ""}">${image} ${showFraction ? illuminatedFractionString : ""}</span>`
+ `<span><i class="fas fa-arrow-up" aria-hidden="true"></i> ${moonRise ? formatTime(this.config, moonRise) : "..."}</span>`
+ `<span><i class="fas fa-arrow-down" aria-hidden="true"></i> ${moonSet ? formatTime(this.config, moonSet) : "..."}</span>`;
+ `<span><i class="fas fa-arrow-up" aria-hidden="true"></i> ${moonRise ? formatTime(this.config, moonRise) : "..."}</span>`
+ `<span><i class="fas fa-arrow-down" aria-hidden="true"></i> ${moonSet ? formatTime(this.config, moonSet) : "..."}</span>`;
digitalWrapper.appendChild(moonWrapper);
}
if (this.config.showWeek) {
weekWrapper.innerHTML = this.translate("WEEK", { weekNumber: now.week() });
if (this.config.showWeek === "short") {
weekWrapper.innerHTML = this.translate("WEEK_SHORT", { weekNumber: now.week() });
} else {
weekWrapper.innerHTML = this.translate("WEEK", { weekNumber: now.week() });
}
digitalWrapper.appendChild(weekWrapper);
}
@@ -247,7 +255,7 @@ Module.register("clock", {
analogWrapper.style.background = `url(${this.data.path}faces/${this.config.analogFace}.svg)`;
analogWrapper.style.backgroundSize = "100%";
// The following line solves issue: https://github.com/MichMich/MagicMirror/issues/611
// The following line solves issue: https://github.com/MagicMirrorOrg/MagicMirror/issues/611
// analogWrapper.style.border = "1px solid black";
analogWrapper.style.border = "rgba(0, 0, 0, 0.1)"; //Updated fix for Issue 611 where non-black backgrounds are used
} else if (this.config.analogFace !== "none") {
@@ -274,7 +282,7 @@ Module.register("clock", {
clockSecond.id = "clock-second";
clockSecond.style.transform = `rotate(${second}deg)`;
clockSecond.className = "clock-second";
clockSecond.style.backgroundColor = this.config.secondsColor;
clockSecond.style.backgroundColor = this.config.secondsColor; /* DEPRECATED, to be removed in a future version , use CSS instead */
clockFace.appendChild(clockSecond);
}
analogWrapper.appendChild(clockFace);

View File

@@ -78,16 +78,41 @@
left: 50%;
margin: -38% -1px 0 0; /* numbers must match negative length & thickness */
padding: 38% 1px 0 0; /* indicator length & thickness */
background: var(--color-text);
/* background: #888888 !important; */
/* use this instead of secondsColor */
/* have to use !important, because the code explicitly sets the color currently */
transform-origin: 50% 100%;
}
.module.clock .digital {
display: flex;
flex-direction: column;
gap: 3px;
}
.module.clock .sun,
.module.clock .moon {
display: flex;
white-space: nowrap;
gap: 10px;
}
.module.clock .sun > *,
.module.clock .moon > * {
flex: 1;
}
.module.clock .clock-hour-digital {
color: var(--color-text-bright);
}
.module.clock .clock-minute-digital {
color: var(--color-text-bright);
}
.module.clock .clock-second-digital {
color: var(--color-text-dimmed);
}

View File

@@ -1,9 +1,5 @@
/* MagicMirror²
* Module: Compliments
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
/* global Cron */
Module.register("compliments", {
// Module config defaults.
defaults: {
@@ -16,20 +12,27 @@ Module.register("compliments", {
},
updateInterval: 30000,
remoteFile: null,
remoteFileRefreshInterval: 0,
fadeSpeed: 4000,
morningStartTime: 3,
morningEndTime: 12,
afternoonStartTime: 12,
afternoonEndTime: 17,
random: true
random: true,
specialDayUnique: false
},
urlSuffix: "",
compliments_new: null,
refreshMinimumDelay: 15 * 60 * 60 * 1000, // 15 minutes
lastIndexUsed: -1,
// Set currentweather from module
currentWeatherType: "",
cron_regex: /^(((\d+,)+\d+|((\d+|[*])[/]\d+|((JAN|FEB|APR|MA[RY]|JU[LN]|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|APR|MA[RY]|JU[LN]|AUG|SEP|OCT|NOV|DEC))?))|(\d+-\d+)|\d+(-\d+)?[/]\d+(-\d+)?|\d+|[*]|(MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?) ?){5}$/i,
date_regex: "[1-9.][0-9.][0-9.]{2}-([0][1-9]|[1][0-2])-([1-2][0-9]|[0][1-9]|[3][0-1])",
pre_defined_types: ["anytime", "morning", "afternoon", "evening"],
// Define required scripts.
getScripts () {
return ["moment.js"];
return ["croner.js", "moment.js"];
},
// Define start sequence.
@@ -42,12 +45,62 @@ Module.register("compliments", {
const response = await this.loadComplimentFile();
this.config.compliments = JSON.parse(response);
this.updateDom();
if (this.config.remoteFileRefreshInterval !== 0) {
if ((this.config.remoteFileRefreshInterval >= this.refreshMinimumDelay) || window.mmTestMode === "true") {
setInterval(async () => {
const response = await this.loadComplimentFile();
if (response) {
this.compliments_new = JSON.parse(response);
}
else {
Log.error(`${this.name} remoteFile refresh failed`);
}
},
this.config.remoteFileRefreshInterval);
} else {
Log.error(`${this.name} remoteFileRefreshInterval less than minimum`);
}
}
}
let minute_sync_delay = 1;
// loop thru all the configured when events
for (let m of Object.keys(this.config.compliments)) {
// if it is a cron entry
if (this.isCronEntry(m)) {
// we need to synch our interval cycle to the minute
minute_sync_delay = (60 - (moment().second())) * 1000;
break;
}
}
// Schedule update timer. sync to the minute start (if needed), so minute based events happen on the minute start
setTimeout(() => {
setInterval(() => {
this.updateDom(this.config.fadeSpeed);
}, this.config.updateInterval);
},
minute_sync_delay);
},
// Schedule update timer.
setInterval(() => {
this.updateDom(this.config.fadeSpeed);
}, this.config.updateInterval);
// check to see if this entry could be a cron entry wich contains spaces
isCronEntry (entry) {
return entry.includes(" ");
},
/**
* @param {string} cronExpression The cron expression. See https://croner.56k.guru/usage/pattern/
* @param {Date} [timestamp] The timestamp to check. Defaults to the current time.
* @returns {number} The number of seconds until the next cron run.
*/
getSecondsUntilNextCronRun (cronExpression, timestamp = new Date()) {
// Required for seconds precision
const adjustedTimestamp = new Date(timestamp.getTime() - 1000);
// https://www.npmjs.com/package/croner
const cronJob = new Cron(cronExpression);
const nextRunTime = cronJob.nextRun(adjustedTimestamp);
const secondsDelta = (nextRunTime - adjustedTimestamp) / 1000;
return secondsDelta;
},
/**
@@ -56,7 +109,7 @@ Module.register("compliments", {
* @returns {number} a random index of given array
*/
randomIndex (compliments) {
if (compliments.length === 1) {
if (compliments.length <= 1) {
return 0;
}
@@ -80,34 +133,73 @@ Module.register("compliments", {
* @returns {string[]} array with compliments for the time of the day.
*/
complimentArray () {
const hour = moment().hour();
const date = moment().format("YYYY-MM-DD");
const now = moment();
const hour = now.hour();
const date = now.format("YYYY-MM-DD");
let compliments = [];
// Add time of day compliments
if (hour >= this.config.morningStartTime && hour < this.config.morningEndTime && this.config.compliments.hasOwnProperty("morning")) {
compliments = [...this.config.compliments.morning];
} else if (hour >= this.config.afternoonStartTime && hour < this.config.afternoonEndTime && this.config.compliments.hasOwnProperty("afternoon")) {
compliments = [...this.config.compliments.afternoon];
} else if (this.config.compliments.hasOwnProperty("evening")) {
compliments = [...this.config.compliments.evening];
let timeOfDay;
if (hour >= this.config.morningStartTime && hour < this.config.morningEndTime) {
timeOfDay = "morning";
} else if (hour >= this.config.afternoonStartTime && hour < this.config.afternoonEndTime) {
timeOfDay = "afternoon";
} else {
timeOfDay = "evening";
}
if (timeOfDay && this.config.compliments.hasOwnProperty(timeOfDay)) {
compliments = [...this.config.compliments[timeOfDay]];
}
// Add compliments based on weather
if (this.currentWeatherType in this.config.compliments) {
Array.prototype.push.apply(compliments, this.config.compliments[this.currentWeatherType]);
// if the predefine list doesn't include it (yet)
if (!this.pre_defined_types.includes(this.currentWeatherType)) {
// add it
this.pre_defined_types.push(this.currentWeatherType);
}
}
// Add compliments for anytime
Array.prototype.push.apply(compliments, this.config.compliments.anytime);
// Add compliments for special days
for (let entry in this.config.compliments) {
if (new RegExp(entry).test(date)) {
Array.prototype.push.apply(compliments, this.config.compliments[entry]);
// get the list of just date entry keys
let temp_list = Object.keys(this.config.compliments).filter((k) => {
if (this.pre_defined_types.includes(k)) return false;
else return true;
});
let date_compliments = [];
// Add compliments for special day/times
for (let entry of temp_list) {
// check if this could be a cron type entry
if (this.isCronEntry(entry)) {
// make sure the regex is valid
if (new RegExp(this.cron_regex).test(entry)) {
// check if we are in the time range for the cron entry
if (this.getSecondsUntilNextCronRun(entry, now.set("seconds", 0).toDate()) <= 1) {
// if so, use its notice entries
Array.prototype.push.apply(date_compliments, this.config.compliments[entry]);
}
} else Log.error(`compliments cron syntax invalid=${JSON.stringify(entry)}`);
} else if (new RegExp(entry).test(date)) {
Array.prototype.push.apply(date_compliments, this.config.compliments[entry]);
}
}
// if we found any date compliments
if (date_compliments.length) {
// and the special flag is true
if (this.config.specialDayUnique) {
// clear the non-date compliments if any
compliments.length = 0;
}
// put the date based compliments on the list
Array.prototype.push.apply(compliments, date_compliments);
}
return compliments;
},
@@ -118,8 +210,18 @@ Module.register("compliments", {
async loadComplimentFile () {
const isRemote = this.config.remoteFile.indexOf("http://") === 0 || this.config.remoteFile.indexOf("https://") === 0,
url = isRemote ? this.config.remoteFile : this.file(this.config.remoteFile);
const response = await fetch(url);
return await response.text();
// because we may be fetching the same url,
// we need to force the server to not give us the cached result
// create an extra property (ignored by the server handler) just so the url string is different
// that will never be the same, using the ms value of date
if (isRemote && this.config.remoteFileRefreshInterval !== 0) this.urlSuffix = `?dummy=${Date.now()}`;
//
try {
const response = await fetch(url + this.urlSuffix);
return await response.text();
} catch (error) {
Log.info(`${this.name} fetch failed error=`, error);
}
},
/**
@@ -169,6 +271,27 @@ Module.register("compliments", {
compliment.lastElementChild.remove();
wrapper.appendChild(compliment);
}
// if a new set of compliments was loaded from the refresh task
// we do this here to make sure no other function is using the compliments list
if (this.compliments_new) {
// use them
if (JSON.stringify(this.config.compliments) !== JSON.stringify(this.compliments_new)) {
// only reset if the contents changes
this.config.compliments = this.compliments_new;
// reset the index
this.lastIndexUsed = -1;
}
// clear new file list so we don't waste cycles comparing between refreshes
this.compliments_new = null;
}
// only in test mode
if (window.mmTestMode === "true") {
// check for (undocumented) remoteFile2 to test new file load
if (this.config.remoteFile2 !== null && this.config.remoteFileRefreshInterval !== 0) {
// switch the file so that next time it will be loaded from a changed file
this.config.remoteFile = this.config.remoteFile2;
}
}
return wrapper;
},

View File

@@ -1,8 +1,6 @@
/* MagicMirror² Default Modules List
/*
* Default Modules List
* Modules listed below can be loaded without the 'default/' prefix. Omitting the default folder name.
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
const defaultModules = ["alert", "calendar", "clock", "compliments", "helloworld", "newsfeed", "updatenotification", "weather"];

View File

@@ -1,9 +1,3 @@
/* MagicMirror²
* Module: HelloWorld
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
Module.register("helloworld", {
// Default module config.
defaults: {

View File

@@ -1,9 +1,3 @@
/* MagicMirror²
* Module: NewsFeed
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
Module.register("newsfeed", {
// Default module config.
defaults: {
@@ -44,7 +38,7 @@ Module.register("newsfeed", {
getUrlPrefix (item) {
if (item.useCorsProxy) {
return `${location.protocol}//${location.host}/cors?url=`;
return `${location.protocol}//${location.host}${config.basePath}cors?url=`;
} else {
return "";
}
@@ -63,7 +57,7 @@ Module.register("newsfeed", {
// Define required translations.
getTranslations () {
// The translations for the default modules are defined in the core translation files.
// Therefor we can just return false. Otherwise we should have returned a dictionary.
// Therefore we can just return false. Otherwise we should have returned a dictionary.
// If you're trying to build your own module including translations, check out the documentation.
return false;
},
@@ -118,27 +112,33 @@ Module.register("newsfeed", {
//Override template data and return whats used for the current template
getTemplateData () {
if (this.activeItem >= this.newsItems.length) {
this.activeItem = 0;
}
this.activeItemCount = this.newsItems.length;
// this.config.showFullArticle is a run-time configuration, triggered by optional notifications
if (this.config.showFullArticle) {
this.activeItemHash = this.newsItems[this.activeItem]?.hash;
return {
url: this.getActiveItemURL()
};
}
if (this.error) {
this.activeItemHash = undefined;
return {
error: this.error
};
}
if (this.newsItems.length === 0) {
this.activeItemHash = undefined;
return {
empty: true
};
}
if (this.activeItem >= this.newsItems.length) {
this.activeItem = 0;
}
const item = this.newsItems[this.activeItem];
this.activeItemHash = item.hash;
const items = this.newsItems.map(function (item) {
item.publishDate = moment(new Date(item.pubdate)).fromNow();
return item;
@@ -150,7 +150,7 @@ Module.register("newsfeed", {
sourceTitle: item.sourceTitle,
publishDate: moment(new Date(item.pubdate)).fromNow(),
title: item.title,
url: this.getUrlPrefix(item) + item.url,
url: this.getActiveItemURL(),
description: item.description,
items: items
};
@@ -177,6 +177,19 @@ Module.register("newsfeed", {
}
},
/**
* Gets a feed property by name
* @param {object} feed A feed object.
* @param {string} property The name of the property.
* @returns {*} The value of the specified property for the feed.
*/
getFeedProperty (feed, property) {
let res = this.config[property];
const f = this.config.feeds.find((feedItem) => feedItem.url === feed);
if (f && f[property]) res = f[property];
return res;
},
/**
* Generate an ordered list of items for this configured module.
* @param {object} feeds An object with feeds returned by the node helper.
@@ -188,7 +201,7 @@ Module.register("newsfeed", {
if (this.subscribedToFeed(feed)) {
for (let item of feedItems) {
item.sourceTitle = this.titleForFeed(feed);
if (!(this.config.ignoreOldItems && Date.now() - new Date(item.pubdate) > this.config.ignoreOlderThan)) {
if (!(this.getFeedProperty(feed, "ignoreOldItems") && Date.now() - new Date(item.pubdate) > this.getFeedProperty(feed, "ignoreOlderThan"))) {
newsItems.push(item);
}
}
@@ -312,8 +325,27 @@ Module.register("newsfeed", {
if (this.timer) clearInterval(this.timer);
this.timer = setInterval(() => {
this.activeItem++;
this.updateDom(this.config.animationSpeed);
/*
* When animations are enabled, don't update the DOM unless we are actually changing what we are displaying.
* (Animating from a headline to itself is unsightly.)
* Cases:
*
* Number of items | Number of items | Display
* at last update | right now | Behaviour
* ----------------------------------------------------
* 0 | 0 | do not update
* 0 | >0 | update
* 1 | 0 or >1 | update
* 1 | 1 | update only if item details (hash value) changed
* >1 | any | update
*
* (N.B. We set activeItemCount and activeItemHash in getTemplateData().)
*/
if (this.newsItems.length > 1 || this.newsItems.length !== this.activeItemCount || this.activeItemHash !== this.newsItems[0]?.hash) {
this.activeItem++; // this is OK if newsItems.Length==1; getTemplateData will wrap it around
this.updateDom(this.config.animationSpeed);
}
// Broadcast NewsFeed if needed
if (this.config.broadcastNewsFeeds) {

View File

@@ -1,16 +1,11 @@
/* MagicMirror²
* Node Helper: Newsfeed - NewsfeedFetcher
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
const stream = require("stream");
const crypto = require("node:crypto");
const stream = require("node:stream");
const FeedMe = require("feedme");
const iconv = require("iconv-lite");
const { htmlToText } = require("html-to-text");
const Log = require("logger");
const NodeHelper = require("node_helper");
const { scheduleTimer } = require("#module_functions");
/**
* Responsible for requesting an update on the set interval and broadcasting the data.
@@ -67,7 +62,8 @@ const NewsfeedFetcher = function (url, reloadInterval, encoding, logFeedWarnings
description: description,
pubdate: pubdate,
url: url,
useCorsProxy: useCorsProxy
useCorsProxy: useCorsProxy,
hash: crypto.createHash("sha256").update(`${pubdate} :: ${title} :: ${url}`).digest("hex")
});
} else if (logFeedWarnings) {
Log.warn("Can't parse feed item:");
@@ -84,12 +80,12 @@ const NewsfeedFetcher = function (url, reloadInterval, encoding, logFeedWarnings
parser.on("error", (error) => {
fetchFailedCallback(this, error);
scheduleTimer();
scheduleTimer(reloadTimer, reloadIntervalMS, fetchNews);
});
//"end" event is not broadcast if the feed is empty but "finish" is used for both
parser.on("finish", () => {
scheduleTimer();
scheduleTimer(reloadTimer, reloadIntervalMS, fetchNews);
});
parser.on("ttl", (minutes) => {
@@ -125,20 +121,10 @@ const NewsfeedFetcher = function (url, reloadInterval, encoding, logFeedWarnings
})
.catch((error) => {
fetchFailedCallback(this, error);
scheduleTimer();
scheduleTimer(reloadTimer, reloadIntervalMS, fetchNews);
});
};
/**
* Schedule the timer for the next update.
*/
const scheduleTimer = function () {
clearTimeout(reloadTimer);
reloadTimer = setTimeout(function () {
fetchNews();
}, reloadIntervalMS);
};
/* public methods */
/**

View File

@@ -1,10 +1,3 @@
/* MagicMirror²
* Node Helper: Newsfeed
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
const NodeHelper = require("node_helper");
const Log = require("logger");
const NewsfeedFetcher = require("./newsfeedfetcher");

View File

@@ -1,7 +1,7 @@
const util = require("util");
const exec = util.promisify(require("child_process").exec);
const fs = require("fs");
const path = require("path");
const util = require("node:util");
const exec = util.promisify(require("node:child_process").exec);
const fs = require("node:fs");
const path = require("node:path");
const Log = require("logger");
const BASE_DIR = path.normalize(`${__dirname}/../../../`);
@@ -128,7 +128,7 @@ class GitHelper {
const { stderr } = await this.execShell(`cd ${repo.folder} && git fetch -n --dry-run`);
// example output:
// From https://github.com/MichMich/MagicMirror
// From https://github.com/MagicMirrorOrg/MagicMirror
// e40ddd4..06389e3 develop -> origin/develop
// here the result is in stderr (this is a git default, don't ask why ...)
const matches = stderr.match(this.getRefRegex(gitInfo.current));

View File

@@ -1,3 +1,5 @@
const fs = require("node:fs");
const path = require("node:path");
const NodeHelper = require("node_helper");
const defaultModules = require("../defaultmodules");
const GitHelper = require("./git_helper");
@@ -14,8 +16,23 @@ module.exports = NodeHelper.create({
gitHelper: new GitHelper(),
updateHelper: null,
getModules (modules) {
if (this.config.useModulesFromConfig) {
return modules;
} else {
// get modules from modules-directory
const moduleDir = path.normalize(`${__dirname}/../../`);
const getDirectories = (source) => {
return fs.readdirSync(source, { withFileTypes: true })
.filter((dirent) => dirent.isDirectory() && dirent.name !== "default")
.map((dirent) => dirent.name);
};
return getDirectories(moduleDir);
}
},
async configureModules (modules) {
for (const moduleName of modules) {
for (const moduleName of this.getModules(modules)) {
if (!this.ignoreUpdateChecking(moduleName)) {
await this.gitHelper.add(moduleName);
}

View File

@@ -1,9 +1,11 @@
const Exec = require("child_process").exec;
const Spawn = require("child_process").spawn;
const commandExists = require("command-exists");
const Exec = require("node:child_process").exec;
const Spawn = require("node:child_process").spawn;
const fs = require("node:fs");
const Log = require("logger");
/* class Updater
/*
* class Updater
* Allow to self updating 3rd party modules from command defined in config
*
* [constructor] read value in config:
@@ -45,8 +47,8 @@ class Updater {
this.autoRestart = config.updateAutorestart;
this.moduleList = {};
this.updating = false;
this.usePM2 = false;
this.PM2 = null;
this.usePM2 = false; // don't use pm2 by default
this.PM2Id = null; // pm2 process number
this.version = global.version;
this.root_path = global.root_path;
Log.info("updatenotification: Updater Class Loaded!");
@@ -83,13 +85,15 @@ class Updater {
return updater;
}
// module updater with his proper command
// return object as result
//{
// error: <boolean>, // if error detected
// updated: <boolean>, // if updated successfully
// needRestart: <boolean> // if magicmirror restart required
//};
/*
* module updater with his proper command
* return object as result
* {
* error: <boolean>, // if error detected
* updated: <boolean>, // if updated successfully
* needRestart: <boolean> // if magicmirror restart required
* };
*/
updateProcess (module) {
let Result = {
error: false,
@@ -129,29 +133,30 @@ class Updater {
});
}
// restart rules (pm2 or npm start)
// restart rules (pm2 or node --run start)
restart () {
if (this.usePM2) this.pm2Restart();
else this.npmRestart();
else this.nodeRestart();
}
// restart MagicMiror with "pm2"
// restart MagicMiror with "pm2": use PM2Id for restart it
pm2Restart () {
Log.info("updatenotification: PM2 will restarting MagicMirror...");
Exec(`pm2 restart ${this.PM2}`, (err, std, sde) => {
const pm2 = require("pm2");
pm2.restart(this.PM2Id, (err, proc) => {
if (err) {
Log.error("updatenotification:[PM2] restart Error", err);
}
});
}
// restart MagicMiror with "npm start"
npmRestart () {
// restart MagicMiror with "node --run start"
nodeRestart () {
Log.info("updatenotification: Restarting MagicMirror...");
const out = process.stdout;
const err = process.stderr;
const subprocess = Spawn("npm start", { cwd: this.root_path, shell: true, detached: true, stdio: ["ignore", out, err] });
subprocess.unref();
const subprocess = Spawn("node --run start", { cwd: this.root_path, shell: true, detached: true, stdio: ["ignore", out, err] });
subprocess.unref(); // detach the newly launched process from the master process
process.exit();
}
@@ -159,53 +164,50 @@ class Updater {
check_PM2_Process () {
Log.info("updatenotification: Checking PM2 using...");
return new Promise((resolve) => {
commandExists("pm2")
.then(async () => {
var PM2_List = await this.PM2_GetList();
if (!PM2_List) {
if (fs.existsSync("/.dockerenv")) {
Log.info("updatenotification: Running in docker container, not using PM2 ...");
resolve(false);
return;
}
if (process.env.unique_id === undefined) {
Log.info("updatenotification: [PM2] You are not using pm2");
resolve(false);
return;
}
Log.debug(`updatenotification: [PM2] Search for pm2 id: ${process.env.pm_id} -- name: ${process.env.name} -- unique_id: ${process.env.unique_id}`);
const pm2 = require("pm2");
pm2.connect((err) => {
if (err) {
Log.error("updatenotification: [PM2]", err);
resolve(false);
return;
}
pm2.list((err, list) => {
if (err) {
Log.error("updatenotification: [PM2] Can't get process List!");
this.usePM2 = false;
resolve(false);
return;
}
PM2_List.forEach((pm) => {
if (pm.pm2_env.version === this.version && pm.pm2_env.status === "online" && pm.pm2_env.PWD.includes(this.root_path)) {
this.PM2 = pm.name;
list.forEach((pm) => {
Log.debug(`updatenotification: [PM2] found pm2 process id: ${pm.pm_id} -- name: ${pm.name} -- unique_id: ${pm.pm2_env.unique_id}`);
if (pm.pm2_env.status === "online" && process.env.name === pm.name && +process.env.pm_id === +pm.pm_id && process.env.unique_id === pm.pm2_env.unique_id) {
this.PM2Id = pm.pm_id;
this.usePM2 = true;
Log.info("updatenotification: You are using pm2 with", this.PM2);
Log.info(`updatenotification: [PM2] You are using pm2 with id: ${this.PM2Id} (${pm.name})`);
resolve(true);
} else {
Log.debug(`updatenotification: [PM2] pm2 process id: ${pm.pm_id} don't match...`);
}
});
if (!this.PM2) {
Log.info("updatenotification: You are not using pm2");
this.usePM2 = false;
pm2.disconnect();
if (!this.usePM2) {
Log.info("updatenotification: [PM2] You are not using pm2");
resolve(false);
}
})
.catch(() => {
Log.info("updatenotification: You are not using pm2");
this.usePM2 = false;
resolve(false);
});
});
}
// Get the list of pm2 process
PM2_GetList () {
return new Promise((resolve) => {
Exec("pm2 jlist", (err, std, sde) => {
if (err) {
resolve(null);
return;
}
try {
let result = JSON.parse(std);
resolve(result);
} catch (e) {
Log.error("updatenotification: [PM2] can't GetList!");
Log.debug("updatenotification: [PM2] GetList is not an JSON format", e);
resolve(null);
}
});
});
}
@@ -218,7 +220,7 @@ class Updater {
// search update module command
applyCommand (module) {
if (this.isMagicMirror(module.module)) return null;
if (this.isMagicMirror(module.module) || !this.updates.length) return null;
let command = null;
this.updates.forEach((updater) => {
if (updater[module]) command = updater[module];

View File

@@ -1,9 +1,3 @@
/* MagicMirror²
* Module: UpdateNotification
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*/
Module.register("updatenotification", {
defaults: {
updateInterval: 10 * 60 * 1000, // every 10 minutes
@@ -12,13 +6,14 @@ Module.register("updatenotification", {
sendUpdatesNotifications: false,
updates: [],
updateTimeout: 2 * 60 * 1000, // max update duration
updateAutorestart: false // autoRestart MM when update done ?
updateAutorestart: false, // autoRestart MM when update done ?
useModulesFromConfig: true // if `false` iterate over modules directory
},
suspended: false,
moduleList: {},
needRestart: false,
updates: {},
updates: [],
start () {
Log.info(`Starting module: ${this.name}`);
@@ -102,7 +97,7 @@ Module.register("updatenotification", {
const localRef = status.hash;
const remoteRef = status.tracking.replace(/.*\//, "");
return `<a href="https://github.com/MichMich/MagicMirror/compare/${localRef}...${remoteRef}" class="xsmall dimmed difflink" target="_blank">${text}</a>`;
return `<a href="https://github.com/MagicMirrorOrg/MagicMirror/compare/${localRef}...${remoteRef}" class="xsmall dimmed difflink" target="_blank">${text}</a>`;
});
},

View File

@@ -5,13 +5,14 @@
* @param {boolean} useCorsProxy A flag to indicate
* @param {Array.<{name: string, value:string}>} requestHeaders the HTTP headers to send
* @param {Array.<string>} expectedResponseHeaders the expected HTTP headers to receive
* @param {string} basePath The base path, default is "/"
* @returns {Promise} resolved when the fetch is done. The response headers is placed in a headers-property (provided the response does not already contain a headers-property).
*/
async function performWebRequest (url, type = "json", useCorsProxy = false, requestHeaders = undefined, expectedResponseHeaders = undefined) {
async function performWebRequest (url, type = "json", useCorsProxy = false, requestHeaders = undefined, expectedResponseHeaders = undefined, basePath = "/") {
const request = {};
let requestUrl;
if (useCorsProxy) {
requestUrl = getCorsUrl(url, requestHeaders, expectedResponseHeaders);
requestUrl = getCorsUrl(url, requestHeaders, expectedResponseHeaders, basePath);
} else {
requestUrl = url;
request.headers = getHeadersToSend(requestHeaders);
@@ -37,13 +38,14 @@ async function performWebRequest (url, type = "json", useCorsProxy = false, requ
* @param {string} url the url to fetch from
* @param {Array.<{name: string, value:string}>} requestHeaders the HTTP headers to send
* @param {Array.<string>} expectedResponseHeaders the expected HTTP headers to receive
* @param {string} basePath The base path, default is "/"
* @returns {string} to be used as URL when calling CORS-method on server.
*/
const getCorsUrl = function (url, requestHeaders, expectedResponseHeaders) {
const getCorsUrl = function (url, requestHeaders, expectedResponseHeaders, basePath = "/") {
if (!url || url.length < 1) {
throw new Error(`Invalid URL: ${url}`);
} else {
let corsUrl = `${location.protocol}//${location.host}/cors?`;
let corsUrl = `${location.protocol}//${location.host}${basePath}cors?`;
const requestHeaderString = getRequestHeaderString(requestHeaders);
if (requestHeaderString) corsUrl = `${corsUrl}sendheaders=${requestHeaderString}`;

View File

@@ -1,3 +1,8 @@
{% macro humidity() %}
{% if current.humidity %}
<span class="humidity"><span>{{ current.humidity | decimalSymbol }}</span><sup>&nbsp;<i class="wi wi-humidity humidity-icon"></i></sup></span>
{% endif %}
{% endmacro %}
{% if current %}
{% if not config.onlyTemp %}
<div class="normal medium">
@@ -7,8 +12,7 @@
{% if config.showWindDirection %}
<sup>
{% if config.showWindDirectionAsArrow %}
<i class="fas fa-long-arrow-alt-down"
style="transform:rotate({{ current.windFromDirection }}deg)"></i>
<i class="fas fa-long-arrow-alt-down" style="transform:rotate({{ current.windFromDirection }}deg)"></i>
{% else %}
{{ current.cardinalWindDirection() | translate }}
{% endif %}
@@ -16,8 +20,8 @@
</sup>
{% endif %}
</span>
{% if config.showHumidity and current.humidity %}
<span>{{ current.humidity | decimalSymbol }}</span><sup>&nbsp;<i class="wi wi-humidity humidity-icon"></i></sup>
{% if config.showHumidity === "wind" %}
{{ humidity() }}
{% endif %}
{% if config.showSun %}
<span class="wi dimmed wi-{{ current.nextSunAction() }}"></span>
@@ -37,28 +41,39 @@
{% endif %}
</div>
{% endif %}
<div class="large light">
<span class="wi weathericon wi-{{ current.weatherType }}"></span>
<span class="bright">{{ current.temperature | roundValue | unit("temperature") | decimalSymbol }}</span>
</div>
<div class="normal light indoor">
{% if config.showIndoorTemperature and indoor.temperature %}
<div>
<span class="fas fa-home"></span>
<span class="bright">{{ indoor.temperature | roundValue | unit("temperature") | decimalSymbol }}</span>
</div>
<div class="large">
{% if config.showIndoorTemperature and indoor.temperature or config.showIndoorHumidity and indoor.humidity %}
<span class="medium fas fa-home"></span>
<span style="display: inline-block">
{% if config.showIndoorTemperature and indoor.temperature %}
<sup class="small" style="position: relative; display: block; text-align: left;">
<span>
{{ indoor.temperature | roundValue | unit("temperature") | decimalSymbol }}
</span>
</sup>
{% endif %}
{% if config.showIndoorHumidity and indoor.humidity %}
<sub class="small" style="position: relative; display: block; text-align: left;">
<span>
{{ indoor.humidity | roundValue | unit("humidity") | decimalSymbol }}
</span>
</sub>
{% endif %}
</span>
{% endif %}
{% if config.showIndoorHumidity and indoor.humidity %}
<div>
<span class="fas fa-tint"></span>
<span class="bright">{{ indoor.humidity | roundValue | unit("humidity") | decimalSymbol }}</span>
</div>
<span class="light wi weathericon wi-{{ current.weatherType }}"></span>
<span class="light bright">{{ current.temperature | roundValue | unit("temperature") | decimalSymbol }}</span>
{% if config.showHumidity === "temp" %}
<span class="medium bright">{{ humidity() }}</span>
{% endif %}
</div>
{% if (config.showFeelsLike or config.showPrecipitationAmount or config.showPrecipitationProbability) and not config.onlyTemp %}
<div class="normal medium feelslike">
{% if config.showFeelsLike %}
<span class="dimmed">
{% if config.showHumidity === "feelslike" %}
{{ humidity() }}
{% endif %}
{{ "FEELS" | translate({DEGREE: current.feelsLike() | roundValue | unit("temperature") | decimalSymbol }) }}
</span>
<br />
@@ -76,6 +91,9 @@
{% endif %}
</div>
{% endif %}
{% if config.showHumidity === "below" %}
<span class="medium dimmed">{{ humidity() }}</span>
{% endif %}
{% else %}
<div class="dimmed light small">{{ "LOADING" | translate }}</div>
{% endif %}

View File

@@ -21,15 +21,25 @@
{% endif %}
</td>
{% endif %}
{% if config.showHumidity != "none" %}
<td class="align-left bright humidity-hourly">
{{ hour.humidity }}
<span class="wi wi-humidity humidity-icon"></span>
</td>
{% endif %}
{% if config.showPrecipitationAmount %}
<td class="align-right bright precipitation-amount">
{{ hour.precipitationAmount | unit("precip", hour.precipitationUnits) }}
</td>
{% if (not config.hideZeroes or hour.precipitationAmount>0) %}
<td class="align-right bright precipitation-amount">
{{ hour.precipitationAmount | unit("precip", hour.precipitationUnits) }}
</td>
{% endif %}
{% endif %}
{% if config.showPrecipitationProbability %}
{% if (not config.hideZeroes or hour.precipitationAmount>0) %}
<td class="align-right bright precipitation-prob">
{{ hour.precipitationProbability | unit('precip', '%') }}
{{ hour.precipitationProbability | unit('precip', '%') }}
</td>
{% endif %}
{% endif %}
</tr>
{% set currentStep = currentStep + 1 %}

View File

@@ -1,9 +1,6 @@
/* global WeatherProvider, WeatherObject, WeatherUtils */
/* MagicMirror²
* Module: Weather
* Provider: Environment Canada (EC)
*
/*
* This class is a provider for Environment Canada MSC Datamart
* Note that this is only for Canadian locations and does not require an API key (access is anonymous)
*
@@ -27,13 +24,9 @@
* with locations you can search under column B (English Names), with the corresponding siteCode under
* column A (Codes) and provCode under column C (Province).
*
* Original by Kevin Godin
*
* License to use Environment Canada (EC) data is detailed here:
* https://eccc-msc.github.io/open-data/licence/readme_en/
*
*/
WeatherProvider.register("envcanada", {
// Set the name of the provider for debugging and alerting purposes (eg. provide eye-catcher)
providerName: "Environment Canada",
@@ -45,10 +38,10 @@ WeatherProvider.register("envcanada", {
provCode: "ON"
},
//
// Set config values (equates to weather module config values). Also set values pertaining to caching of
// Today's temperature forecast (for use in the Forecast functions below)
//
/*
* Set config values (equates to weather module config values). Also set values pertaining to caching of
* Today's temperature forecast (for use in the Forecast functions below)
*/
setConfig (config) {
this.config = config;
@@ -58,17 +51,17 @@ WeatherProvider.register("envcanada", {
this.cacheCurrentTemp = 999;
},
//
// Called when the weather provider is started
//
/*
* Called when the weather provider is started
*/
start () {
Log.info(`Weather provider: ${this.providerName} started.`);
this.setFetchedLocation(this.config.location);
},
//
// Override the fetchCurrentWeather method to query EC and construct a Current weather object
//
/*
* Override the fetchCurrentWeather method to query EC and construct a Current weather object
*/
fetchCurrentWeather () {
this.fetchData(this.getUrl(), "xml")
.then((data) => {
@@ -86,9 +79,9 @@ WeatherProvider.register("envcanada", {
.finally(() => this.updateAvailable());
},
//
// Override the fetchWeatherForecast method to query EC and construct Forecast weather objects
//
/*
* Override the fetchWeatherForecast method to query EC and construct Forecast weather objects
*/
fetchWeatherForecast () {
this.fetchData(this.getUrl(), "xml")
.then((data) => {
@@ -106,9 +99,9 @@ WeatherProvider.register("envcanada", {
.finally(() => this.updateAvailable());
},
//
// Override the fetchWeatherHourly method to query EC and construct Forecast weather objects
//
/*
* Override the fetchWeatherHourly method to query EC and construct Forecast weather objects
*/
fetchWeatherHourly () {
this.fetchData(this.getUrl(), "xml")
.then((data) => {
@@ -126,36 +119,30 @@ WeatherProvider.register("envcanada", {
.finally(() => this.updateAvailable());
},
//////////////////////////////////////////////////////////////////////////////////
//
// Environment Canada methods - not part of the standard Provider methods
//
//////////////////////////////////////////////////////////////////////////////////
//
// Build the EC URL based on the Site Code and Province Code specified in the config params. Note that the
// URL defaults to the English version simply because there is no language dependency in the data
// being accessed. This is only pertinent when using the EC data elements that contain a textual forecast.
//
/*
* Build the EC URL based on the Site Code and Province Code specified in the config params. Note that the
* URL defaults to the English version simply because there is no language dependency in the data
* being accessed. This is only pertinent when using the EC data elements that contain a textual forecast.
*/
getUrl () {
return `https://dd.weather.gc.ca/citypage_weather/xml/${this.config.provCode}/${this.config.siteCode}_e.xml`;
},
//
// Generate a WeatherObject based on current EC weather conditions
//
/*
* Generate a WeatherObject based on current EC weather conditions
*/
generateWeatherObjectFromCurrentWeather (ECdoc) {
const currentWeather = new WeatherObject();
// There are instances where EC will update weather data and current temperature will not be
// provided. While this is a defect in the EC systems, we need to accommodate to avoid a current temp
// of NaN being displayed. Therefore... whenever we get a valid current temp from EC, we will cache
// the value. Whenever EC data is missing current temp, we will provide the cached value
// instead. This is reasonable since the cached value will typically be accurate within the previous
// hour. The only time this does not work as expected is when MM is restarted and the first query to
// EC finds no current temp. In this scenario, MM will end up displaying a current temp of null;
/*
* There are instances where EC will update weather data and current temperature will not be
* provided. While this is a defect in the EC systems, we need to accommodate to avoid a current temp
* of NaN being displayed. Therefore... whenever we get a valid current temp from EC, we will cache
* the value. Whenever EC data is missing current temp, we will provide the cached value
* instead. This is reasonable since the cached value will typically be accurate within the previous
* hour. The only time this does not work as expected is when MM is restarted and the first query to
* EC finds no current temp. In this scenario, MM will end up displaying a current temp of null;
*/
if (ECdoc.querySelector("siteData currentConditions temperature").textContent) {
currentWeather.temperature = ECdoc.querySelector("siteData currentConditions temperature").textContent;
this.cacheCurrentTemp = currentWeather.temperature;
@@ -169,19 +156,19 @@ WeatherProvider.register("envcanada", {
currentWeather.humidity = ECdoc.querySelector("siteData currentConditions relativeHumidity").textContent;
// Ensure showPrecipitationAmount is forced to false. EC does not really provide POP for current day
// and this feature for the weather module (current only) is sort of broken in that it wants
// to say POP but will display precip as an accumulated amount vs. a percentage.
/*
* Ensure showPrecipitationAmount is forced to false. EC does not really provide POP for current day
* and this feature for the weather module (current only) is sort of broken in that it wants
* to say POP but will display precip as an accumulated amount vs. a percentage.
*/
this.config.showPrecipitationAmount = false;
//
// If the module config wants to showFeelsLike... default to the current temperature.
// Check for EC wind chill and humidex values and overwrite the feelsLikeTemp value.
// This assumes that the EC current conditions will never contain both a wind chill
// and humidex temperature.
//
/*
* If the module config wants to showFeelsLike... default to the current temperature.
* Check for EC wind chill and humidex values and overwrite the feelsLikeTemp value.
* This assumes that the EC current conditions will never contain both a wind chill
* and humidex temperature.
*/
if (this.config.showFeelsLike) {
currentWeather.feelsLikeTemp = currentWeather.temperature;
@@ -194,16 +181,10 @@ WeatherProvider.register("envcanada", {
}
}
//
// Need to map EC weather icon to MM weatherType values
//
currentWeather.weatherType = this.convertWeatherType(ECdoc.querySelector("siteData currentConditions iconCode").textContent);
//
// Capture the sunrise and sunset values from EC data
//
const sunList = ECdoc.querySelectorAll("siteData riseSet dateTime");
currentWeather.sunrise = moment(sunList[1].querySelector("timeStamp").textContent, "YYYYMMDDhhmmss");
@@ -212,13 +193,11 @@ WeatherProvider.register("envcanada", {
return currentWeather;
},
//
// Generate an array of WeatherObjects based on EC weather forecast
//
/*
* Generate an array of WeatherObjects based on EC weather forecast
*/
generateWeatherObjectsFromForecast (ECdoc) {
// Declare an array to hold each day's forecast object
const days = [];
const weather = new WeatherObject();
@@ -232,37 +211,33 @@ WeatherProvider.register("envcanada", {
weather.precipitationAmount = null;
//
// The EC forecast is held in a 12-element array - Elements 0 to 11 - with each day encompassing
// 2 elements. the first element for a day details the Today (daytime) forecast while the second
// element details the Tonight (nightime) forecast. Element 0 is always for the current day.
//
// However... the forecast is somewhat 'rolling'.
//
// If the EC forecast is queried in the morning, then Element 0 will contain Current
// Today and Element 1 will contain Current Tonight. From there, the next 5 days of forecast will be
// contained in Elements 2/3, 4/5, 6/7, 8/9, and 10/11. This module will create a 6-day forecast using
// all of these Elements.
//
// But, if the EC forecast is queried in late afternoon, the Current Today forecast will be rolled
// off and Element 0 will contain Current Tonight. From there, the next 5 days will be contained in
// Elements 1/2, 3/4, 5/6, 7/8, and 9/10. As well, Elelement 11 will contain a forecast for a 6th day,
// but only for the Today portion (not Tonight). This module will create a 6-day forecast using
// Elements 0 to 11, and will ignore the additional Todat forecast in Element 11.
//
// We need to determine if Element 0 is showing the forecast for Current Today or Current Tonight.
// This is required to understand how Min and Max temperature will be determined, and to understand
// where the next day's (aka Tomorrow's) forecast is located in the forecast array.
//
/*
* The EC forecast is held in a 12-element array - Elements 0 to 11 - with each day encompassing
* 2 elements. the first element for a day details the Today (daytime) forecast while the second
* element details the Tonight (nightime) forecast. Element 0 is always for the current day.
*
* However... the forecast is somewhat 'rolling'.
*
* If the EC forecast is queried in the morning, then Element 0 will contain Current
* Today and Element 1 will contain Current Tonight. From there, the next 5 days of forecast will be
* contained in Elements 2/3, 4/5, 6/7, 8/9, and 10/11. This module will create a 6-day forecast using
* all of these Elements.
*
* But, if the EC forecast is queried in late afternoon, the Current Today forecast will be rolled
* off and Element 0 will contain Current Tonight. From there, the next 5 days will be contained in
* Elements 1/2, 3/4, 5/6, 7/8, and 9/10. As well, Elelement 11 will contain a forecast for a 6th day,
* but only for the Today portion (not Tonight). This module will create a 6-day forecast using
* Elements 0 to 11, and will ignore the additional Todat forecast in Element 11.
*
* We need to determine if Element 0 is showing the forecast for Current Today or Current Tonight.
* This is required to understand how Min and Max temperature will be determined, and to understand
* where the next day's (aka Tomorrow's) forecast is located in the forecast array.
*/
let nextDay = 0;
let lastDay = 0;
const currentTemp = ECdoc.querySelector("siteData currentConditions temperature").textContent;
//
// If the first Element is Current Today, look at Current Today and Current Tonight for the current day.
//
if (foreGroup[0].querySelector("period[textForecastName='Today']")) {
this.todaytempCacheMin = 0;
this.todaytempCacheMax = 0;
@@ -272,167 +247,144 @@ WeatherProvider.register("envcanada", {
this.setPrecipitation(weather, foreGroup, 0);
//
// Set the Element number that will reflect where the next day's forecast is located. Also set
// the Element number where the end of the forecast will be. This is important because of the
// rolling nature of the EC forecast. In the current scenario (Today and Tonight are present
// in elements 0 and 11, we know that we will have 6 full days of forecasts and we will use
// them. We will set lastDay such that we iterate through all 12 elements of the forecast.
//
/*
* Set the Element number that will reflect where the next day's forecast is located. Also set
* the Element number where the end of the forecast will be. This is important because of the
* rolling nature of the EC forecast. In the current scenario (Today and Tonight are present
* in elements 0 and 11, we know that we will have 6 full days of forecasts and we will use
* them. We will set lastDay such that we iterate through all 12 elements of the forecast.
*/
nextDay = 2;
lastDay = 12;
}
//
// If the first Element is Current Tonight, look at Tonight only for the current day.
//
if (foreGroup[0].querySelector("period[textForecastName='Tonight']")) {
this.setMinMaxTemps(weather, foreGroup, 0, false, currentTemp);
this.setPrecipitation(weather, foreGroup, 0);
//
// Set the Element number that will reflect where the next day's forecast is located. Also set
// the Element number where the end of the forecast will be. This is important because of the
// rolling nature of the EC forecast. In the current scenario (only Current Tonight is present
// in Element 0, we know that we will have 6 full days of forecasts PLUS a half-day and
// forecast in the final element. Because we will only use full day forecasts, we set the
// lastDay number to ensure we ignore that final half-day (in forecast Element 11).
//
/*
* Set the Element number that will reflect where the next day's forecast is located. Also set
* the Element number where the end of the forecast will be. This is important because of the
* rolling nature of the EC forecast. In the current scenario (only Current Tonight is present
* in Element 0, we know that we will have 6 full days of forecasts PLUS a half-day and
* forecast in the final element. Because we will only use full day forecasts, we set the
* lastDay number to ensure we ignore that final half-day (in forecast Element 11).
*/
nextDay = 1;
lastDay = 11;
}
//
// Need to map EC weather icon to MM weatherType values. Always pick the first Element's icon to
// reflect either Today or Tonight depending on what the forecast is showing in Element 0.
//
/*
* Need to map EC weather icon to MM weatherType values. Always pick the first Element's icon to
* reflect either Today or Tonight depending on what the forecast is showing in Element 0.
*/
weather.weatherType = this.convertWeatherType(foreGroup[0].querySelector("abbreviatedForecast iconCode").textContent);
// Push the weather object into the forecast array.
days.push(weather);
//
// Now do the rest of the forecast starting at nextDay. We will process each day using 2 EC
// forecast Elements. This will address the fact that the EC forecast always includes Today and
// Tonight for each day. This is why we iterate through the forecast by a a count of 2, with each
// iteration looking at the current Element and the next Element.
//
/*
* Now do the rest of the forecast starting at nextDay. We will process each day using 2 EC
* forecast Elements. This will address the fact that the EC forecast always includes Today and
* Tonight for each day. This is why we iterate through the forecast by a a count of 2, with each
* iteration looking at the current Element and the next Element.
*/
let lastDate = moment(baseDate, "YYYYMMDDhhmmss");
for (let stepDay = nextDay; stepDay < lastDay; stepDay += 2) {
let weather = new WeatherObject();
// Add 1 to the date to reflect the current forecast day we are building
lastDate = lastDate.add(1, "day");
weather.date = moment(lastDate);
// Capture the temperatures for the current Element and the next Element in order to set
// the Min and Max temperatures for the forecast
/*
* Capture the temperatures for the current Element and the next Element in order to set
* the Min and Max temperatures for the forecast
*/
this.setMinMaxTemps(weather, foreGroup, stepDay, true, currentTemp);
weather.precipitationAmount = null;
this.setPrecipitation(weather, foreGroup, stepDay);
//
// Need to map EC weather icon to MM weatherType values. Always pick the first Element icon.
//
weather.weatherType = this.convertWeatherType(foreGroup[stepDay].querySelector("abbreviatedForecast iconCode").textContent);
// Push the weather object into the forecast array.
days.push(weather);
}
return days;
},
//
// Generate an array of WeatherObjects based on EC hourly weather forecast
//
/*
* Generate an array of WeatherObjects based on EC hourly weather forecast
*/
generateWeatherObjectsFromHourly (ECdoc) {
// Declare an array to hold each hour's forecast object
const hours = [];
// Get local timezone UTC offset so that each hourly time can be calculated properly
const baseHours = ECdoc.querySelectorAll("siteData hourlyForecastGroup dateTime");
const hourOffset = baseHours[1].getAttribute("UTCOffset");
//
// The EC hourly forecast is held in a 24-element array - Elements 0 to 23 - with Element 0 holding
// the forecast for the next 'on the hour' timeslot. This means the array is a rolling 24 hours.
//
/*
* The EC hourly forecast is held in a 24-element array - Elements 0 to 23 - with Element 0 holding
* the forecast for the next 'on the hour' timeslot. This means the array is a rolling 24 hours.
*/
const hourGroup = ECdoc.querySelectorAll("siteData hourlyForecastGroup hourlyForecast");
for (let stepHour = 0; stepHour < 24; stepHour += 1) {
const weather = new WeatherObject();
// Determine local time by applying UTC offset to the forecast timestamp
const foreTime = moment(hourGroup[stepHour].getAttribute("dateTimeUTC"), "YYYYMMDDhhmmss");
const currTime = foreTime.add(hourOffset, "hours");
weather.date = moment(currTime);
// Capture the temperature
weather.temperature = hourGroup[stepHour].querySelector("temperature").textContent;
// Capture Likelihood of Precipitation (LOP) and unit-of-measure values
const precipLOP = hourGroup[stepHour].querySelector("lop").textContent * 1.0;
if (precipLOP > 0) {
weather.precipitationProbability = precipLOP;
}
//
// Need to map EC weather icon to MM weatherType values. Always pick the first Element icon.
//
weather.weatherType = this.convertWeatherType(hourGroup[stepHour].querySelector("iconCode").textContent);
// Push the weather object into the forecast array.
hours.push(weather);
}
return hours;
},
//
// Determine Min and Max temp based on a supplied Forecast Element index and a boolen that denotes if
// the next Forecast element should be considered - i.e. look at Today *and* Tonight vs.Tonight-only
//
/*
* Determine Min and Max temp based on a supplied Forecast Element index and a boolen that denotes if
* the next Forecast element should be considered - i.e. look at Today *and* Tonight vs.Tonight-only
*/
setMinMaxTemps (weather, foreGroup, today, fullDay, currentTemp) {
const todayTemp = foreGroup[today].querySelector("temperatures temperature").textContent;
const todayClass = foreGroup[today].querySelector("temperatures temperature").getAttribute("class");
//
// The following logic is largely aimed at accommodating the Current day's forecast whereby we
// can have either Current Today+Current Tonight or only Current Tonight.
//
// If fullDay is false, then we only have Tonight for the current day's forecast - meaning we have
// lost a min or max temp value for the day. Therefore, we will see if we were able to cache the the
// Today forecast for the current day. If we have, we will use them. If we do not have the cached values,
// it means that MM or the Computer has been restarted since the time EC rolled off Today from the
// forecast. In this scenario, we will simply default to the Current Conditions temperature and then
// check the Tonight temperature.
//
/*
* The following logic is largely aimed at accommodating the Current day's forecast whereby we
* can have either Current Today+Current Tonight or only Current Tonight.
*
* If fullDay is false, then we only have Tonight for the current day's forecast - meaning we have
* lost a min or max temp value for the day. Therefore, we will see if we were able to cache the the
* Today forecast for the current day. If we have, we will use them. If we do not have the cached values,
* it means that MM or the Computer has been restarted since the time EC rolled off Today from the
* forecast. In this scenario, we will simply default to the Current Conditions temperature and then
* check the Tonight temperature.x
*/
if (fullDay === false) {
if (this.todayCached === true) {
weather.minTemperature = this.todayTempCacheMin;
@@ -443,13 +395,12 @@ WeatherProvider.register("envcanada", {
}
}
//
// We will check to see if the current Element's temperature is Low or High and set weather values
// accordingly. We will also check the condition where fullDay is true *and* we are looking at forecast
// element 0. This is a special case where we will cache temperature values so that we have them later
// in the current day when the Current Today element rolls off and we have Current Tonight only.
//
/*
* We will check to see if the current Element's temperature is Low or High and set weather values
* accordingly. We will also check the condition where fullDay is true *and* we are looking at forecast
* element 0. This is a special case where we will cache temperature values so that we have them later
* in the current day when the Current Today element rolls off and we have Current Tonight only.
*/
if (todayClass === "low") {
weather.minTemperature = todayTemp;
if (today === 0 && fullDay === true) {
@@ -479,25 +430,24 @@ WeatherProvider.register("envcanada", {
}
},
//
// Check for a Precipitation forecast. EC can provide a forecast in 2 ways: either an accumulation figure
// or a POP percentage. If there is a POP, then that is what the module will show. If there is an accumulation,
// then it will be displayed ONLY if no POP is present.
//
// POP Logic: By default, we want to show the POP for 'daytime' since we are presuming that is what
// people are more interested in seeing. While EC provides a separate POP for daytime and nightime portions
// of each day, the weather module does not really allow for that view of a daily forecast. There we will
// ignore any nightime portion. There is an exception however! For the Current day, the EC data will only show
// the nightime forecast after a certain point in the afternoon. As such, we will be showing the nightime POP
// (if one exists) in that specific scenario.
//
// Accumulation Logic: Similar to POP, we want to show accumulation for 'daytime' since we presume that is what
// people are interested in seeing. While EC provides a separate accumulation for daytime and nightime portions
// of each day, the weather module does not really allow for that view of a daily forecast. There we will
// ignore any nightime portion. There is an exception however! For the Current day, the EC data will only show
// the nightime forecast after a certain point in that specific scenario.
//
/*
* Check for a Precipitation forecast. EC can provide a forecast in 2 ways: either an accumulation figure
* or a POP percentage. If there is a POP, then that is what the module will show. If there is an accumulation,
* then it will be displayed ONLY if no POP is present.
*
* POP Logic: By default, we want to show the POP for 'daytime' since we are presuming that is what
* people are more interested in seeing. While EC provides a separate POP for daytime and nightime portions
* of each day, the weather module does not really allow for that view of a daily forecast. There we will
* ignore any nightime portion. There is an exception however! For the Current day, the EC data will only show
* the nightime forecast after a certain point in the afternoon. As such, we will be showing the nightime POP
* (if one exists) in that specific scenario.
*
* Accumulation Logic: Similar to POP, we want to show accumulation for 'daytime' since we presume that is what
* people are interested in seeing. While EC provides a separate accumulation for daytime and nightime portions
* of each day, the weather module does not really allow for that view of a daily forecast. There we will
* ignore any nightime portion. There is an exception however! For the Current day, the EC data will only show
* the nightime forecast after a certain point in that specific scenario.
*/
setPrecipitation (weather, foreGroup, today) {
if (foreGroup[today].querySelector("precipitation accumulation")) {
weather.precipitationAmount = foreGroup[today].querySelector("precipitation accumulation amount").textContent * 1.0;
@@ -511,9 +461,9 @@ WeatherProvider.register("envcanada", {
}
},
//
// Convert the icons to a more usable name.
//
/*
* Convert the icons to a more usable name.
*/
convertWeatherType (weatherType) {
const weatherTypes = {
"00": "day-sunny",

View File

@@ -1,22 +1,20 @@
/* global WeatherProvider, WeatherObject */
/* MagicMirror²
* Module: Weather
* Provider: Open-Meteo
*
* By Andrés Vanegas
* MIT Licensed
*
* This class is a provider for Open-Meteo, based on Andrew Pometti's class
* for Weatherbit.
/*
* This class is a provider for Open-Meteo,
* see https://open-meteo.com/
*/
// https://www.bigdatacloud.com/docs/api/free-reverse-geocode-to-city-api
const GEOCODE_BASE = "https://api.bigdatacloud.net/data/reverse-geocode-client";
const OPEN_METEO_BASE = "https://api.open-meteo.com/v1";
WeatherProvider.register("openmeteo", {
// Set the name of the provider.
// Not strictly required, but helps for debugging.
/*
* Set the name of the provider.
* Not strictly required, but helps for debugging.
*/
providerName: "Open-Meteo",
// Set the default config properties that is specific to this provider
@@ -246,17 +244,17 @@ WeatherProvider.register("openmeteo", {
.add(Math.max(0, Math.min(7, this.config.maxNumberOfDays)), "days")
.endOf("day");
params["start_date"] = startDate.format("YYYY-MM-DD");
params.start_date = startDate.format("YYYY-MM-DD");
switch (this.config.type) {
case "hourly":
case "daily":
case "forecast":
params["end_date"] = endDate.format("YYYY-MM-DD");
params.end_date = endDate.format("YYYY-MM-DD");
break;
case "current":
params["current_weather"] = true;
params["end_date"] = params["start_date"];
params.current_weather = true;
params.end_date = params.start_date;
break;
default:
// Failsafe
@@ -264,7 +262,7 @@ WeatherProvider.register("openmeteo", {
}
return Object.keys(params)
.filter((key) => (params[key] ? true : false))
.filter((key) => (!!params[key]))
.map((key) => {
switch (key) {
case "hourly":
@@ -404,14 +402,14 @@ WeatherProvider.register("openmeteo", {
currentWeather.windFromDirection = weather.winddirection_10m_dominant;
currentWeather.sunrise = weather.sunrise;
currentWeather.sunset = weather.sunset;
currentWeather.temperature = parseFloat((weather.apparent_temperature_max + weather.apparent_temperature_min) / 2);
currentWeather.minTemperature = parseFloat(weather.apparent_temperature_min);
currentWeather.maxTemperature = parseFloat(weather.apparent_temperature_max);
currentWeather.weatherType = this.convertWeatherType(weather.weathercode, currentWeather.isDayTime());
currentWeather.temperature = parseFloat((weather.temperature_2m_max + weather.temperature_2m_min) / 2);
currentWeather.minTemperature = parseFloat(weather.temperature_2m_min);
currentWeather.maxTemperature = parseFloat(weather.temperature_2m_max);
currentWeather.weatherType = this.convertWeatherType(weather.weathercode, true);
currentWeather.rain = parseFloat(weather.rain_sum);
currentWeather.snow = parseFloat(weather.snowfall_sum * 10);
currentWeather.precipitationAmount = parseFloat(weather.precipitation_sum);
currentWeather.precipitationProbability = parseFloat(weather.precipitation_probability);
currentWeather.precipitationProbability = parseFloat(weather.precipitation_hours * 100 / 24);
currentWeather.uv_index = parseFloat(weather.uv_index_max);
days.push(currentWeather);
@@ -426,7 +424,7 @@ WeatherProvider.register("openmeteo", {
const now = moment();
weathers.hourly.forEach((weather, i) => {
if ((hours.length === 0 && weather.time.hour() <= now.hour()) || hours.length >= this.config.maxEntries) {
if ((hours.length === 0 && weather.time <= now) || hours.length >= this.config.maxEntries) {
return;
}
@@ -438,9 +436,9 @@ WeatherProvider.register("openmeteo", {
currentWeather.windFromDirection = weather.winddirection_10m;
currentWeather.sunrise = weathers.daily[h].sunrise;
currentWeather.sunset = weathers.daily[h].sunset;
currentWeather.temperature = parseFloat(weather.apparent_temperature);
currentWeather.minTemperature = parseFloat(weathers.daily[h].apparent_temperature_min);
currentWeather.maxTemperature = parseFloat(weathers.daily[h].apparent_temperature_max);
currentWeather.temperature = parseFloat(weather.temperature_2m);
currentWeather.minTemperature = parseFloat(weathers.daily[h].temperature_2m_min);
currentWeather.maxTemperature = parseFloat(weathers.daily[h].temperature_2m_max);
currentWeather.weatherType = this.convertWeatherType(weather.weathercode, currentWeather.isDayTime());
currentWeather.humidity = parseFloat(weather.relativehumidity_2m);
currentWeather.rain = parseFloat(weather.rain);
@@ -472,7 +470,7 @@ WeatherProvider.register("openmeteo", {
61: "rain-slight-intensity",
63: "rain-moderate-intensity",
65: "rain-heavy-intensity",
66: "freezing-rain-light-heavy-intensity",
66: "freezing-rain-light-intensity",
67: "freezing-rain-heavy-intensity",
71: "snow-fall-slight-intensity",
73: "snow-fall-moderate-intensity",

View File

@@ -1,27 +1,29 @@
/* global WeatherProvider, WeatherObject */
/* MagicMirror²
* Module: Weather
*
* By Michael Teeuw https://michaelteeuw.nl
* MIT Licensed.
*
* This class is the blueprint for a weather provider.
/*
* This class is a provider for Openweathermap,
* see https://openweathermap.org/
*/
WeatherProvider.register("openweathermap", {
// Set the name of the provider.
// This isn't strictly necessary, since it will fallback to the provider identifier
// But for debugging (and future alerts) it would be nice to have the real name.
/*
* Set the name of the provider.
* This isn't strictly necessary, since it will fallback to the provider identifier
* But for debugging (and future alerts) it would be nice to have the real name.
*/
providerName: "OpenWeatherMap",
// Set the default config properties that is specific to this provider
defaults: {
apiVersion: "2.5",
apiVersion: "3.0",
apiBase: "https://api.openweathermap.org/data/",
weatherEndpoint: "", // can be "onecall", "forecast" or "weather" (for current)
// weatherEndpoint is "/onecall" since API 3.0
// "/onecall", "/forecast" or "/weather" only for pro customers
weatherEndpoint: "/onecall",
locationID: false,
location: false,
lat: 0, // the onecall endpoint needs lat / lon values, it doesn't support the locationId
// the /onecall endpoint needs lat / lon values, it doesn't support the locationId
lat: 0,
lon: 0,
apiKey: ""
},
@@ -72,8 +74,11 @@ WeatherProvider.register("openweathermap", {
this.fetchData(this.getUrl())
.then((data) => {
if (!data) {
// Did not receive usable new data.
// Maybe this needs a better check?
/*
* Did not receive usable new data.
* Maybe this needs a better check?
*/
return;
}
@@ -88,30 +93,6 @@ WeatherProvider.register("openweathermap", {
.finally(() => this.updateAvailable());
},
/**
* Overrides method for setting config to check if endpoint is correct for hourly
* @param {object} config The configuration object
*/
setConfig (config) {
this.config = config;
if (!this.config.weatherEndpoint) {
switch (this.config.type) {
case "hourly":
this.config.weatherEndpoint = "/onecall";
break;
case "daily":
case "forecast":
this.config.weatherEndpoint = "/forecast";
break;
case "current":
this.config.weatherEndpoint = "/weather";
break;
default:
Log.error("weatherEndpoint not configured and could not resolve it based on type");
}
}
},
/** OpenWeatherMap Specific Methods - These are not part of the default provider methods */
/*
* Gets the complete url for the request
@@ -211,8 +192,10 @@ WeatherProvider.register("openweathermap", {
weather.weatherType = this.convertWeatherType(forecast.weather[0].icon);
}
// the same day as before
// add values from forecast to corresponding variables
/*
* the same day as before
* add values from forecast to corresponding variables
*/
minTemp.push(forecast.main.temp_min);
maxTemp.push(forecast.main.temp_max);
@@ -225,8 +208,10 @@ WeatherProvider.register("openweathermap", {
}
}
// last day
// calculate minimum/maximum temperature, specify rain amount
/*
* last day
* calculate minimum/maximum temperature, specify rain amount
*/
weather.minTemperature = Math.min.apply(null, minTemp);
weather.maxTemperature = Math.max.apply(null, maxTemp);
weather.rain = rain;
@@ -255,14 +240,18 @@ WeatherProvider.register("openweathermap", {
weather.rain = 0;
weather.snow = 0;
// forecast.rain not available if amount is zero
// The API always returns in millimeters
/*
* forecast.rain not available if amount is zero
* The API always returns in millimeters
*/
if (forecast.hasOwnProperty("rain") && !isNaN(forecast.rain)) {
weather.rain = forecast.rain;
}
// forecast.snow not available if amount is zero
// The API always returns in millimeters
/*
* forecast.snow not available if amount is zero
* The API always returns in millimeters
*/
if (forecast.hasOwnProperty("snow") && !isNaN(forecast.snow)) {
weather.snow = forecast.snow;
}
@@ -296,12 +285,12 @@ WeatherProvider.register("openweathermap", {
current.weatherType = this.convertWeatherType(data.current.weather[0].icon);
current.humidity = data.current.humidity;
current.uv_index = data.current.uvi;
if (data.current.hasOwnProperty("rain") && !isNaN(data.current["rain"]["1h"])) {
current.rain = data.current["rain"]["1h"];
if (data.current.hasOwnProperty("rain") && !isNaN(data.current.rain["1h"])) {
current.rain = data.current.rain["1h"];
precip = true;
}
if (data.current.hasOwnProperty("snow") && !isNaN(data.current["snow"]["1h"])) {
current.snow = data.current["snow"]["1h"];
if (data.current.hasOwnProperty("snow") && !isNaN(data.current.snow["1h"])) {
current.snow = data.current.snow["1h"];
precip = true;
}
if (precip) {
@@ -407,7 +396,8 @@ WeatherProvider.register("openweathermap", {
return weatherTypes.hasOwnProperty(weatherType) ? weatherTypes[weatherType] : null;
},
/* getParams(compliments)
/*
* getParams(compliments)
* Generates an url with api parameters based on the config.
*
* return String - URL params.

View File

@@ -1,18 +1,15 @@
/* global WeatherProvider, WeatherObject */
/* MagicMirror²
* Module: Weather
* Provider: Pirate Weather
*
* Written by Nicholas Hubbard https://github.com/nhubbard for formerly Dark Sky Provider
* Modified by Karsten Hassel for Pirate Weather
* MIT Licensed
*
* This class is a provider for Pirate Weather, it is a replacement for Dark Sky (same api).
/*
* This class is a provider for Pirate Weather, it is a replacement for Dark Sky (same api),
* see http://pirateweather.net/en/latest/
*/
WeatherProvider.register("pirateweather", {
// Set the name of the provider.
// Not strictly required, but helps for debugging.
/*
* Set the name of the provider.
* Not strictly required, but helps for debugging.
*/
providerName: "pirateweather",
// Set the default config properties that is specific to this provider

View File

@@ -1,14 +1,9 @@
/* global WeatherProvider, WeatherObject */
/* MagicMirror²
* Module: Weather
* Provider: SMHI
*
* By BuXXi https://github.com/buxxi
* MIT Licensed
*
* This class is a provider for SMHI (Sweden only). Metric system is the only
* supported unit.
/*
* This class is a provider for SMHI (Sweden only).
* Metric system is the only supported unit,
* see https://www.smhi.se/
*/
WeatherProvider.register("smhi", {
providerName: "SMHI",
@@ -144,9 +139,11 @@ WeatherProvider.register("smhi", {
currentWeather.weatherType = this.convertWeatherType(this.paramValue(weatherData, "Wsymb2"), currentWeather.isDayTime());
currentWeather.feelsLikeTemp = this.calculateApparentTemperature(weatherData);
// Determine the precipitation amount and category and update the
// weatherObject with it, the valuetype to use can be configured or uses
// median as default.
/*
* Determine the precipitation amount and category and update the
* weatherObject with it, the valuetype to use can be configured or uses
* median as default.
*/
let precipitationValue = this.paramValue(weatherData, this.config.precipitationValue);
switch (this.paramValue(weatherData, "pcat")) {
// 0 = No precipitation

View File

@@ -1,17 +1,16 @@
/* global WeatherProvider, WeatherObject, WeatherUtils */
/* MagicMirror²
* Module: Weather
*
* By Malcolm Oakes https://github.com/maloakes
* MIT Licensed.
*
* This class is a provider for UK Met Office Datapoint.
/*
* This class is a provider for UK Met Office Datapoint,
* see https://www.metoffice.gov.uk/
*/
WeatherProvider.register("ukmetoffice", {
// Set the name of the provider.
// This isn't strictly necessary, since it will fallback to the provider identifier
// But for debugging (and future alerts) it would be nice to have the real name.
/*
* Set the name of the provider.
* This isn't strictly necessary, since it will fallback to the provider identifier
* But for debugging (and future alerts) it would be nice to have the real name.
*/
providerName: "UK Met Office",
// Set the default config properties that is specific to this provider
@@ -26,8 +25,11 @@ WeatherProvider.register("ukmetoffice", {
this.fetchData(this.getUrl("3hourly"))
.then((data) => {
if (!data || !data.SiteRep || !data.SiteRep.DV || !data.SiteRep.DV.Location || !data.SiteRep.DV.Location.Period || data.SiteRep.DV.Location.Period.length === 0) {
// Did not receive usable new data.
// Maybe this needs a better check?
/*
* Did not receive usable new data.
* Maybe this needs a better check?
*/
return;
}
@@ -47,8 +49,11 @@ WeatherProvider.register("ukmetoffice", {
this.fetchData(this.getUrl("daily"))
.then((data) => {
if (!data || !data.SiteRep || !data.SiteRep.DV || !data.SiteRep.DV.Location || !data.SiteRep.DV.Location.Period || data.SiteRep.DV.Location.Period.length === 0) {
// Did not receive usable new data.
// Maybe this needs a better check?
/*
* Did not receive usable new data.
* Maybe this needs a better check?
*/
return;
}
@@ -91,8 +96,11 @@ WeatherProvider.register("ukmetoffice", {
if (periodDate.isSameOrAfter(moment.utc().startOf("day"))) {
// check this is the period we want, after today the diff will be -ve
if (moment().diff(periodDate, "minutes") > 0) {
// loop round the reports looking for the one we are in
// $ value specifies the time in minutes-of-the-day: 0, 180, 360,...1260
/*
* loop round the reports looking for the one we are in
* $ value specifies the time in minutes-of-the-day: 0, 180, 360,...1260
*/
for (const rep of period.Rep) {
const p = rep.$;
if (timeInMins >= p && timeInMins - 180 < p) {
@@ -122,8 +130,10 @@ WeatherProvider.register("ukmetoffice", {
generateWeatherObjectsFromForecast (forecasts) {
const days = [];
// loop round the (5) periods getting the data
// for each period array, Day is [0], Night is [1]
/*
* loop round the (5) periods getting the data
* for each period array, Day is [0], Night is [1]
*/
for (const period of forecasts.SiteRep.DV.Location.Period) {
const weather = new WeatherObject();

View File

@@ -1,12 +1,6 @@
/* global WeatherProvider, WeatherObject */
/* MagicMirror²
* Module: Weather
*
* By Malcolm Oakes https://github.com/maloakes
* Existing Met Office provider edited for new MetOffice Data Hub by CreepinJesus http://github.com/XBCreepinJesus
* MIT Licensed.
*
/*
* This class is a provider for UK Met Office Data Hub (the replacement for their Data Point services).
* For more information on Data Hub, see https://www.metoffice.gov.uk/services/data/datapoint/notifications/weather-datahub
* Data available:
@@ -18,9 +12,8 @@
* This provider requires longitude/latitude coordinates, rather than a location ID (as with the previous Met Office provider)
* Provide the following in your config.js file:
* weatherProvider: "ukmetofficedatahub",
* apiBase: "https://api-metoffice.apiconnect.ibmcloud.com/metoffice/production/v0/forecasts/point/",
* apiBase: "https://data.hub.api.metoffice.gov.uk/sitespecific/v0/point/",
* apiKey: "[YOUR API KEY]",
* apiSecret: "[YOUR API SECRET]",
* lat: [LATITUDE (DECIMAL)],
* lon: [LONGITUDE (DECIMAL)]
*
@@ -45,14 +38,13 @@ WeatherProvider.register("ukmetofficedatahub", {
// Set the default config properties that is specific to this provider
defaults: {
apiBase: "https://api-metoffice.apiconnect.ibmcloud.com/metoffice/production/v0/forecasts/point/",
apiBase: "https://data.hub.api.metoffice.gov.uk/sitespecific/v0/point/",
apiKey: "",
apiSecret: "",
lat: 0,
lon: 0
},
// Build URL with query strings according to DataHub API (https://metoffice.apiconnect.ibmcloud.com/metoffice/production/api)
// Build URL with query strings according to DataHub API (https://datahub.metoffice.gov.uk/docs/f/category/site-specific/type/site-specific/api-documentation#get-/point/hourly)
getUrl (forecastType) {
let queryStrings = "?";
queryStrings += `latitude=${this.config.lat}`;
@@ -63,14 +55,15 @@ WeatherProvider.register("ukmetofficedatahub", {
return this.config.apiBase + (this.config.apiBase.endsWith("/") ? "" : "/") + forecastType + queryStrings;
},
// Build the list of headers for the request
// For DataHub requests, the API key/secret are sent in the headers rather than as query strings.
// Headers defined according to Data Hub API (https://metoffice.apiconnect.ibmcloud.com/metoffice/production/api)
/*
* Build the list of headers for the request
* For DataHub requests, the API key/secret are sent in the headers rather than as query strings.
* Headers defined according to Data Hub API (https://datahub.metoffice.gov.uk/docs/f/category/site-specific/type/site-specific/api-documentation#get-/point/hourly)
*/
getHeaders () {
return {
accept: "application/json",
"x-ibm-client-id": this.config.apiKey,
"x-ibm-client-secret": this.config.apiSecret
apikey: this.config.apiKey
};
},
@@ -88,8 +81,11 @@ WeatherProvider.register("ukmetofficedatahub", {
.then((data) => {
// Check data is usable
if (!data || !data.features || !data.features[0].properties || !data.features[0].properties.timeSeries || data.features[0].properties.timeSeries.length === 0) {
// Did not receive usable new data.
// Maybe this needs a better check?
/*
* Did not receive usable new data.
* Maybe this needs a better check?
*/
Log.error("Possibly bad current/hourly data?");
Log.error(data);
return;
@@ -137,15 +133,19 @@ WeatherProvider.register("ukmetofficedatahub", {
currentWeather.precipitationProbability = forecastDataHours[hour].probOfPrecipitation;
currentWeather.feelsLikeTemp = forecastDataHours[hour].feelsLikeTemperature;
// Pass on full details, so they can be used in custom templates
// Note the units of the supplied data when using this (see top of file)
/*
* Pass on full details, so they can be used in custom templates
* Note the units of the supplied data when using this (see top of file)
*/
currentWeather.rawData = forecastDataHours[hour];
}
}
// Determine the sunrise/sunset times - (still) not supplied in UK Met Office data
// Passes {longitude, latitude} to SunCalc, could pass height to, but
// SunCalc.getTimes doesn't take that into account
/*
* Determine the sunrise/sunset times - (still) not supplied in UK Met Office data
* Passes {longitude, latitude} to SunCalc, could pass height to, but
* SunCalc.getTimes doesn't take that into account
*/
currentWeather.updateSunTime(this.config.lat, this.config.lon);
return currentWeather;
@@ -157,8 +157,11 @@ WeatherProvider.register("ukmetofficedatahub", {
.then((data) => {
// Check data is usable
if (!data || !data.features || !data.features[0].properties || !data.features[0].properties.timeSeries || data.features[0].properties.timeSeries.length === 0) {
// Did not receive usable new data.
// Maybe this needs a better check?
/*
* Did not receive usable new data.
* Maybe this needs a better check?
*/
Log.error("Possibly bad forecast data?");
Log.error(data);
return;
@@ -213,8 +216,10 @@ WeatherProvider.register("ukmetofficedatahub", {
forecastWeather.snow = forecastDataDays[day].dayProbabilityOfSnow;
forecastWeather.feelsLikeTemp = forecastDataDays[day].dayMaxFeelsLikeTemp;
// Pass on full details, so they can be used in custom templates
// Note the units of the supplied data when using this (see top of file)
/*
* Pass on full details, so they can be used in custom templates
* Note the units of the supplied data when using this (see top of file)
*/
forecastWeather.rawData = forecastDataDays[day];
dailyForecasts.push(forecastWeather);
@@ -229,9 +234,11 @@ WeatherProvider.register("ukmetofficedatahub", {
this.fetchedLocationName = name;
},
// Match the Met Office "significant weather code" to a weathericons.css icon
// Use: https://metoffice.apiconnect.ibmcloud.com/metoffice/production/node/264
// and: https://erikflowers.github.io/weather-icons/
/*
* Match the Met Office "significant weather code" to a weathericons.css icon
* Use: https://metoffice.apiconnect.ibmcloud.com/metoffice/production/node/264
* and: https://erikflowers.github.io/weather-icons/
*/
convertWeatherType (weatherType) {
const weatherTypes = {
0: "night-clear",

View File

@@ -1,18 +1,15 @@
/* global WeatherProvider, WeatherObject */
/* MagicMirror²
* Module: Weather
* Provider: Weatherbit
*
* By Andrew Pometti
* MIT Licensed
*
* This class is a provider for Weatherbit, based on Nicholas Hubbard's class
* for Dark Sky & Vince Peri's class for Weather.gov.
/*
* This class is a provider for Weatherbit,
* see https://www.weatherbit.io/
*/
WeatherProvider.register("weatherbit", {
// Set the name of the provider.
// Not strictly required, but helps for debugging.
/*
* Set the name of the provider.
* Not strictly required, but helps for debugging.
*/
providerName: "Weatherbit",
// Set the default config properties that is specific to this provider

View File

@@ -1,19 +1,15 @@
/* global WeatherProvider, WeatherObject, WeatherUtils */
/* MagicMirror²
* Module: Weather
* Provider: Weatherflow
*
* By Tobias Dreyem https://github.com/10bias
* MIT Licensed
*
/*
* This class is a provider for Weatherflow.
* Note that the Weatherflow API does not provide snowfall.
*/
WeatherProvider.register("weatherflow", {
// Set the name of the provider.
// Not strictly required, but helps for debugging
/*
* Set the name of the provider.
* Not strictly required, but helps for debugging
*/
providerName: "WeatherFlow",
// Set the default config properties that is specific to this provider
@@ -29,14 +25,20 @@ WeatherProvider.register("weatherflow", {
const currentWeather = new WeatherObject();
currentWeather.date = moment();
// Other available values: air_density, brightness, delta_t, dew_point,
// pressure_trend (i.e. rising/falling), sea_level_pressure, wind gust, and more.
currentWeather.humidity = data.current_conditions.relative_humidity;
currentWeather.temperature = data.current_conditions.air_temperature;
currentWeather.feelsLikeTemp = data.current_conditions.feels_like;
currentWeather.windSpeed = WeatherUtils.convertWindToMs(data.current_conditions.wind_avg);
currentWeather.windFromDirection = data.current_conditions.wind_direction;
currentWeather.weatherType = data.forecast.daily[0].icon;
currentWeather.weatherType = this.convertWeatherType(data.current_conditions.icon);
currentWeather.uv_index = data.current_conditions.uv;
currentWeather.sunrise = moment.unix(data.forecast.daily[0].sunrise);
currentWeather.sunset = moment.unix(data.forecast.daily[0].sunset);
this.setCurrentWeather(currentWeather);
this.fetchedLocationName = data.location_name;
})
.catch(function (request) {
Log.error("Could not load data ... ", request);
@@ -56,13 +58,27 @@ WeatherProvider.register("weatherflow", {
weather.minTemperature = forecast.air_temp_low;
weather.maxTemperature = forecast.air_temp_high;
weather.precipitationProbability = forecast.precip_probability;
weather.weatherType = forecast.icon;
weather.snow = 0;
weather.weatherType = this.convertWeatherType(forecast.icon);
// Must manually build UV and Precipitation from hourly
weather.precipitationAmount = 0.0; // This will sum up rain and snow
weather.precipitationUnits = "mm";
weather.uv_index = 0;
for (const hour of data.forecast.hourly) {
const hour_time = moment.unix(hour.time);
if (hour_time.day() === weather.date.day()) { // Iterate though until day is reached
// Get data from today
weather.uv_index = Math.max(weather.uv_index, hour.uv);
weather.precipitationAmount += (hour.precip ?? 0);
} else if (hour_time.diff(weather.date) >= 86400) {
break; // No more data to be found
}
}
days.push(weather);
}
this.setWeatherForecast(days);
this.fetchedLocationName = data.location_name;
})
.catch(function (request) {
Log.error("Could not load data ... ", request);
@@ -70,6 +86,63 @@ WeatherProvider.register("weatherflow", {
.finally(() => this.updateAvailable());
},
fetchWeatherHourly () {
this.fetchData(this.getUrl())
.then((data) => {
const hours = [];
for (const hour of data.forecast.hourly) {
const weather = new WeatherObject();
weather.date = moment.unix(hour.time);
weather.temperature = hour.air_temperature;
weather.feelsLikeTemp = hour.feels_like;
weather.humidity = hour.relative_humidity;
weather.windSpeed = hour.wind_avg;
weather.windFromDirection = hour.wind_direction;
weather.weatherType = this.convertWeatherType(hour.icon);
weather.precipitationProbability = hour.precip_probability;
weather.precipitationAmount = hour.precip; // NOTE: precipitation type is available
weather.precipitationUnits = "mm"; // Hardcoded via request, TODO: Add conversion
weather.uv_index = hour.uv;
hours.push(weather);
if (hours.length >= 48) break; // 10 days of hours are available, best to trim down.
}
this.setWeatherHourly(hours);
this.fetchedLocationName = data.location_name;
})
.catch(function (request) {
Log.error("Could not load data ... ", request);
})
.finally(() => this.updateAvailable());
},
convertWeatherType (weatherType) {
const weatherTypes = {
"clear-day": "day-sunny",
"clear-night": "night-clear",
cloudy: "cloudy",
foggy: "fog",
"partly-cloudy-day": "day-cloudy",
"partly-cloudy-night": "night-alt-cloudy",
"possibly-rainy-day": "day-rain",
"possibly-rainy-night": "night-alt-rain",
"possibly-sleet-day": "day-sleet",
"possibly-sleet-night": "night-alt-sleet",
"possibly-snow-day": "day-snow",
"possibly-snow-night": "night-alt-snow",
"possibly-thunderstorm-day": "day-thunderstorm",
"possibly-thunderstorm-night": "night-alt-thunderstorm",
rainy: "rain",
sleet: "sleet",
snow: "snow",
thunderstorm: "thunderstorm",
windy: "strong-wind"
};
return weatherTypes.hasOwnProperty(weatherType) ? weatherTypes[weatherType] : null;
},
// Create a URL from the config and base URL.
getUrl () {
return `${this.config.apiBase}better_forecast?station_id=${this.config.stationid}&units_temp=c&units_wind=kph&units_pressure=mb&units_precip=mm&units_distance=km&token=${this.config.token}`;

View File

@@ -1,22 +1,21 @@
/* global WeatherProvider, WeatherObject, WeatherUtils */
/* MagicMirror²
* Module: Weather
/*
* Provider: weather.gov
* https://weather-gov.github.io/api/general-faqs
*
* Original by Vince Peri
* MIT Licensed.
*
* This class is a provider for weather.gov.
* Note that this is only for US locations (lat and lon) and does not require an API key
* Since it is free, there are some items missing - like sunrise, sunset
*/
WeatherProvider.register("weathergov", {
// Set the name of the provider.
// This isn't strictly necessary, since it will fallback to the provider identifier
// But for debugging (and future alerts) it would be nice to have the real name.
/*
* Set the name of the provider.
* This isn't strictly necessary, since it will fallback to the provider identifier
* But for debugging (and future alerts) it would be nice to have the real name.
*/
providerName: "Weather.gov",
// Set the default config properties that is specific to this provider
@@ -39,7 +38,6 @@ WeatherProvider.register("weathergov", {
// Called to set the config, this config is the same as the weather module's config.
setConfig (config) {
this.config = config;
this.config.apiBase = "https://api.weather.gov";
this.fetchWxGovURLs(this.config);
},
@@ -104,8 +102,11 @@ WeatherProvider.register("weathergov", {
this.fetchData(this.forecastHourlyURL)
.then((data) => {
if (!data) {
// Did not receive usable new data.
// Maybe this needs a better check?
/*
* Did not receive usable new data.
* Maybe this needs a better check?
*/
return;
}
const hourly = this.generateWeatherObjectsFromHourly(data.properties.periods);
@@ -123,7 +124,7 @@ WeatherProvider.register("weathergov", {
* Get specific URLs
*/
fetchWxGovURLs (config) {
this.fetchData(`${config.apiBase}/points/${config.lat},${config.lon}`)
this.fetchData(`${config.apiBase}/${config.lat},${config.lon}`)
.then((data) => {
if (!data || !data.properties) {
// points URL did not respond with usable data.
@@ -217,7 +218,7 @@ WeatherProvider.register("weathergov", {
currentWeather.minTemperature = currentWeatherData.minTemperatureLast24Hours.value;
currentWeather.maxTemperature = currentWeatherData.maxTemperatureLast24Hours.value;
currentWeather.humidity = Math.round(currentWeatherData.relativeHumidity.value);
currentWeather.precipitationAmount = currentWeatherData.precipitationLastHour.value;
currentWeather.precipitationAmount = currentWeatherData.precipitationLastHour?.value ?? currentWeatherData.precipitationLast3Hours?.value;
if (currentWeatherData.heatIndex.value !== null) {
currentWeather.feelsLikeTemp = currentWeatherData.heatIndex.value;
} else if (currentWeatherData.windChill.value !== null) {
@@ -288,14 +289,18 @@ WeatherProvider.register("weathergov", {
weather.weatherType = this.convertWeatherType(forecast.shortForecast, forecast.isDaytime);
}
// the same day as before
// add values from forecast to corresponding variables
/*
* the same day as before
* add values from forecast to corresponding variables
*/
minTemp.push(forecast.temperature);
maxTemp.push(forecast.temperature);
}
// last day
// calculate minimum/maximum temperature
/*
* last day
* calculate minimum/maximum temperature
*/
weather.minTemperature = Math.min.apply(null, minTemp);
weather.maxTemperature = Math.max.apply(null, maxTemp);
@@ -308,8 +313,11 @@ WeatherProvider.register("weathergov", {
* Convert the icons to a more usable name.
*/
convertWeatherType (weatherType, isDaytime) {
//https://w1.weather.gov/xml/current_obs/weather.php
// There are way too many types to create, so lets just look for certain strings
/*
* https://w1.weather.gov/xml/current_obs/weather.php
* There are way too many types to create, so lets just look for certain strings
*/
if (weatherType.includes("Cloudy") || weatherType.includes("Partly")) {
if (isDaytime) {

View File

@@ -1,14 +1,7 @@
/* global WeatherProvider, WeatherObject */
/* MagicMirror²
* Module: Weather
* Provider: Yr.no
*
* By Magnus Marthinsen
* MIT Licensed
*
/*
* This class is a provider for Yr.no, a norwegian weather service.
*
* Terms of service: https://developer.yr.no/doc/TermsOfService/
*/
WeatherProvider.register("yr", {
@@ -30,6 +23,10 @@ WeatherProvider.register("yr", {
Log.error("The Yr weather provider requires local storage.");
throw new Error("Local storage not available");
}
if (this.config.updateInterval < 600000) {
Log.warn("The Yr weather provider requires a minimum update interval of 10 minutes (600 000 ms). The configuration has been adjusted to meet this requirement.");
this.delegate.config.updateInterval = 600000;
}
Log.info(`Weather provider: ${this.providerName} started.`);
},
@@ -41,7 +38,7 @@ WeatherProvider.register("yr", {
})
.catch((error) => {
Log.error(error);
throw new Error(error);
this.updateAvailable();
});
},
@@ -75,8 +72,11 @@ WeatherProvider.register("yr", {
getWeatherData () {
return new Promise((resolve, reject) => {
// If a user has several Yr-modules, for instance one current and one forecast, the API calls must be synchronized across classes.
// This is to avoid multiple similar calls to the API.
/*
* If a user has several Yr-modules, for instance one current and one forecast, the API calls must be synchronized across classes.
* This is to avoid multiple similar calls to the API.
*/
let shouldWait = localStorage.getItem("yrIsFetchingWeatherData");
if (shouldWait) {
const checkForGo = setInterval(function () {
@@ -123,7 +123,12 @@ WeatherProvider.register("yr", {
})
.catch((err) => {
Log.error(err);
reject("Unable to get weather data from Yr.");
if (weatherData) {
Log.warn("Using outdated cached weather data.");
resolve(weatherData);
} else {
reject("Unable to get weather data from Yr.");
}
})
.finally(() => {
localStorage.removeItem("yrIsFetchingWeatherData");
@@ -209,8 +214,11 @@ WeatherProvider.register("yr", {
},
getStellarData () {
// If a user has several Yr-modules, for instance one current and one forecast, the API calls must be synchronized across classes.
// This is to avoid multiple similar calls to the API.
/*
* If a user has several Yr-modules, for instance one current and one forecast, the API calls must be synchronized across classes.
* This is to avoid multiple similar calls to the API.
*/
return new Promise((resolve, reject) => {
let shouldWait = localStorage.getItem("yrIsFetchingStellarData");
if (shouldWait) {
@@ -498,7 +506,7 @@ WeatherProvider.register("yr", {
})
.catch((error) => {
Log.error(error);
throw new Error(error);
this.updateAvailable();
});
},
@@ -531,7 +539,15 @@ WeatherProvider.register("yr", {
getHourlyForecastFrom (weatherData) {
const series = [];
const now = moment({
year: moment().year(),
month: moment().month(),
day: moment().date(),
hour: moment().hour()
});
for (const forecast of weatherData.properties.timeseries) {
if (now.isAfter(moment(forecast.time))) continue;
forecast.symbol = forecast.data.next_1_hours?.summary?.symbol_code;
forecast.precipitationAmount = forecast.data.next_1_hours?.details?.precipitation_amount;
forecast.precipitationProbability = forecast.data.next_1_hours?.details?.probability_of_precipitation;
@@ -601,7 +617,7 @@ WeatherProvider.register("yr", {
})
.catch((error) => {
Log.error(error);
throw new Error(error);
this.updateAvailable();
});
}
});

View File

@@ -31,6 +31,7 @@
.weather .precipitation-amount,
.weather .precipitation-prob,
.weather .humidity-hourly,
.weather .uv-index {
padding-left: 20px;
padding-right: 0;

Some files were not shown because too many files have changed in this diff Show More