mirror of
https://github.com/MichMich/MagicMirror.git
synced 2025-10-17 01:42:18 +00:00
Compare commits
2237 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
5bf90ae31d | ||
|
b533e3d3e1 | ||
|
4d9df309c8 | ||
|
65126365a6 | ||
|
b595cdd31e | ||
|
e64870ca58 | ||
|
a40f8d5b3a | ||
|
61b8871ead | ||
|
4b5a3ed44d | ||
|
7d6b7b2691 | ||
|
3dba46b74f | ||
|
2767e31a28 | ||
|
40886bcf08 | ||
|
04dde74572 | ||
|
29f3ac065f | ||
|
d2b30b4f9c | ||
|
3a42663dea | ||
|
905d0ca409 | ||
|
7e2c78666e | ||
|
6a5f0225fe | ||
|
ddb01fca31 | ||
|
684a3cd49e | ||
|
ad5e42115b | ||
|
2d6b8d0c47 | ||
|
61471e5449 | ||
|
b6f7ab7a9c | ||
|
2d061be98e | ||
|
d6e97b8c76 | ||
|
9e44660746 | ||
|
03e6ca58ab | ||
|
94c63b0554 | ||
|
c7c8c40a70 | ||
|
91c726c706 | ||
|
c9805e7ac9 | ||
|
a4db0e40e3 | ||
|
305b55cb2a | ||
|
272ca1ac4f | ||
|
bbc6a1b38f | ||
|
0e93713464 | ||
|
8f60e103f9 | ||
|
9cc702241d | ||
|
0d61c44232 | ||
|
9a8faac316 | ||
|
05f710cb5c | ||
|
c6184769e7 | ||
|
515d1bd920 | ||
|
b19cb17bba | ||
|
c1e808bce6 | ||
|
d8b7292d4b | ||
|
edd5e2f5bc | ||
|
efc6cb73b2 | ||
|
ecd79dc34b | ||
|
cdfc8b825d | ||
|
301344c96d | ||
|
5279995c3b | ||
|
5176b06b59 | ||
|
ed61ac624d | ||
|
4da6e3ecee | ||
|
9e5561936a | ||
|
843cd0eff6 | ||
|
6b6ee934a1 | ||
|
aea57ffaf4 | ||
|
87b48661fa | ||
|
556fa44858 | ||
|
1c3e196508 | ||
|
9b6812ad0c | ||
|
b7944c7fa4 | ||
|
2fbedca746 | ||
|
340d04a48c | ||
|
460a383ffc | ||
|
52c4e3a256 | ||
|
4338f11eb1 | ||
|
42bab052e0 | ||
|
0cb377618e | ||
|
5e4d25b957 | ||
|
153d1853fa | ||
|
22a3448461 | ||
|
2cad869680 | ||
|
bc912a8ea4 | ||
|
db9176c284 | ||
|
06308210c0 | ||
|
63d9904370 | ||
|
caaeff5cb7 | ||
|
d8c93d3455 | ||
|
cb28e5fddc | ||
|
7d7ec1a00b | ||
|
a5bc8dfa3f | ||
|
d74f055180 | ||
|
73be6c35a6 | ||
|
24f74e1400 | ||
|
8900e069f3 | ||
|
1dfec119bb | ||
|
9e23d35f01 | ||
|
cd2b240308 | ||
|
749f366a4a | ||
|
420aaa92fa | ||
|
985698bbc3 | ||
|
f9c9139f20 | ||
|
f308e7541f | ||
|
cb7ccd7854 | ||
|
a4953028d0 | ||
|
3d6485588d | ||
|
51bb9fede7 | ||
|
269c429959 | ||
|
fcdc84a12a | ||
|
ecdd9734eb | ||
|
84fc2c65af | ||
|
c8849a17b6 | ||
|
d8b49218e9 | ||
|
e95023e8cc | ||
|
878710e2cf | ||
|
0677d0a810 | ||
|
9c98fea8f4 | ||
|
e958f33450 | ||
|
937080b011 | ||
|
aee5803dd2 | ||
|
f1f394b871 | ||
|
81a32b56f0 | ||
|
a6aae70a55 | ||
|
823eb23773 | ||
|
1ff51822df | ||
|
500147e130 | ||
|
d90de18d99 | ||
|
ba4f48662f | ||
|
d208437c05 | ||
|
01faa2e1d7 | ||
|
c630c387d6 | ||
|
a774718607 | ||
|
9430c70d0d | ||
|
f3e893fddb | ||
|
11e144ca64 | ||
|
fbceab707e | ||
|
5b2efc43b9 | ||
|
8d85d1aa2d | ||
|
b469fc7577 | ||
|
9db54831c8 | ||
|
9b88bde09a | ||
|
aad03a74c5 | ||
|
55eb6e2e5c | ||
|
ca07355873 | ||
|
11a59e26b2 | ||
|
ec6d9e3521 | ||
|
230accd31e | ||
|
a24a4a747e | ||
|
1e97b5c27a | ||
|
a314ea1aa3 | ||
|
a77128d5f7 | ||
|
1b2673367e | ||
|
ce10e91a60 | ||
|
5244b37d2c | ||
|
1239c6716b | ||
|
67f6258ab0 | ||
|
9f63172b43 | ||
|
bd8bfeb525 | ||
|
4918c4ef4b | ||
|
00d9ea9344 | ||
|
33537cde76 | ||
|
3d5db5c9ca | ||
|
fdf339514d | ||
|
937c4e485a | ||
|
837c060e1f | ||
|
00bacd7dde | ||
|
781031775e | ||
|
97aee3d375 | ||
|
34698751f2 | ||
|
3c31460f2f | ||
|
d5cb60b19c | ||
|
3a7cfe3208 | ||
|
f079cdad64 | ||
|
2822303138 | ||
|
e38de75520 | ||
|
2723604d3e | ||
|
82ee051c1a | ||
|
7bdf49b7e0 | ||
|
32521aba6b | ||
|
819c4cde1c | ||
|
776c486b1a | ||
|
bcd97120a4 | ||
|
312bfb8509 | ||
|
11c9a50931 | ||
|
94c0656bcd | ||
|
13313d0b25 | ||
|
3a20db1d76 | ||
|
00148b4cc8 | ||
|
a31546b1ff | ||
|
361b62b8e2 | ||
|
37327b77a7 | ||
|
7ef8a5bb11 | ||
|
11cfb8af32 | ||
|
7315f7d283 | ||
|
7d58eb718e | ||
|
651be76776 | ||
|
4a5c6f1d39 | ||
|
5745d71d6a | ||
|
db62b7421a | ||
|
4084c57789 | ||
|
f90bec985a | ||
|
90f911c529 | ||
|
6c88b106db | ||
|
cef69d1b97 | ||
|
f76a7fb331 | ||
|
3e7b8b0663 | ||
|
a6eb3ad037 | ||
|
9468749384 | ||
|
37417fa1bb | ||
|
217146351e | ||
|
818ec33cef | ||
|
cd1671830a | ||
|
a5fca87dd0 | ||
|
f06ce55626 | ||
|
853085e755 | ||
|
2b7accaf68 | ||
|
5533d93172 | ||
|
f0e8c865fe | ||
|
36400c0a83 | ||
|
c5383557b5 | ||
|
b645007884 | ||
|
63ac137206 | ||
|
808cbf8e0b | ||
|
8ed77ba0c7 | ||
|
66c74c51e4 | ||
|
7a272ef0ab | ||
|
60b817ec8e | ||
|
a41ecaf7cc | ||
|
d41afa0e53 | ||
|
a6284e05e5 | ||
|
e56f61441d | ||
|
7b4b7dffa2 | ||
|
77a214ef9c | ||
|
cf2723aafb | ||
|
499e99cfc5 | ||
|
a7b83e9fe3 | ||
|
964504b9c3 | ||
|
ec65e66c58 | ||
|
e694b080be | ||
|
70894b3938 | ||
|
fb7115fc13 | ||
|
a619fc4fef | ||
|
7c6c5fd06f | ||
|
2970568eab | ||
|
62cb3a610e | ||
|
f600c163ca | ||
|
77cb68e5ac | ||
|
c6314576aa | ||
|
515c183070 | ||
|
63b9c0e6b8 | ||
|
84893b1664 | ||
|
835668d96d | ||
|
2bce15dc6e | ||
|
8f1a212b52 | ||
|
5c08bde0fa | ||
|
98a84c031e | ||
|
ea1715384e | ||
|
d9a4ee4f65 | ||
|
62017c4661 | ||
|
702b98f510 | ||
|
69aafd7d6a | ||
|
c1559dd8c8 | ||
|
4df1895560 | ||
|
cac92da6e4 | ||
|
5d39d85215 | ||
|
99b4c43fd5 | ||
|
b2f59d6813 | ||
|
c7d79bb893 | ||
|
aa80c468c4 | ||
|
6008cba2db | ||
|
caf56671dc | ||
|
44eccf5ee4 | ||
|
8f96e4847c | ||
|
ae3e307f33 | ||
|
3fe0c758ed | ||
|
7240fb32d2 | ||
|
e23a3461ba | ||
|
727eb0cfd7 | ||
|
3796076360 | ||
|
ef9576f8c4 | ||
|
94fc4cb8a2 | ||
|
ccb248db91 | ||
|
e7de447725 | ||
|
7ff5429cb7 | ||
|
17c581b4aa | ||
|
41e5c2939f | ||
|
7e2ab51298 | ||
|
03f917fd9c | ||
|
d24e10a728 | ||
|
a17ac1c16e | ||
|
dd6b972be4 | ||
|
7d0c9ba0d9 | ||
|
6fa211634f | ||
|
1ca24c7f38 | ||
|
bcfbccae59 | ||
|
20b75ce6ed | ||
|
2ea15d7bf5 | ||
|
18e14c597f | ||
|
06d75999d7 | ||
|
7047a7cae6 | ||
|
20d2124867 | ||
|
3c7a85361e | ||
|
1ffbbdac99 | ||
|
eeccca8842 | ||
|
e2d2dbd2ba | ||
|
c61f0409fb | ||
|
806be39a6d | ||
|
6170b0d059 | ||
|
bca838495e | ||
|
e31a747250 | ||
|
4cf430e146 | ||
|
ef554cf6ec | ||
|
fcd91daee6 | ||
|
396c78b46a | ||
|
4677a3fd89 | ||
|
834ab5c6b9 | ||
|
1599e8f7ff | ||
|
7430704002 | ||
|
4d7b19c8cb | ||
|
40f535cf3c | ||
|
17425dcaf7 | ||
|
6b87fc64af | ||
|
35174b0348 | ||
|
fd53541719 | ||
|
7c68bff9f5 | ||
|
6c64991951 | ||
|
ca04ff0f37 | ||
|
7742575cab | ||
|
cdcdce702d | ||
|
c80e04fe8d | ||
|
c3b3ea107a | ||
|
1dc530c549 | ||
|
8b0b70e757 | ||
|
b508a629e8 | ||
|
abb0dadead | ||
|
e6fb18df56 | ||
|
43ba13f3bc | ||
|
ba705f5563 | ||
|
34e188ec1f | ||
|
b0d97dd170 | ||
|
7caeae61f5 | ||
|
416ace4c86 | ||
|
979041ee91 | ||
|
f0939b8af5 | ||
|
d7a7002bdd | ||
|
d9601de075 | ||
|
ef570558cf | ||
|
db3e81408f | ||
|
e8771cdea8 | ||
|
057eab2173 | ||
|
e2a7024eeb | ||
|
4650986dfa | ||
|
868b5e4617 | ||
|
f12860c7b1 | ||
|
8f751812a6 | ||
|
07a5092eb3 | ||
|
29c9c92ba6 | ||
|
edfa327158 | ||
|
869a6e66cc | ||
|
36abbfc048 | ||
|
cfc3e6d2f4 | ||
|
e38dbee6a6 | ||
|
68a7c857c0 | ||
|
80eef2ab8c | ||
|
1d652aa746 | ||
|
b07c43aa36 | ||
|
3880c8dc2c | ||
|
c0ab2ac297 | ||
|
de684dcb63 | ||
|
29ef1db86b | ||
|
5dfd8a61be | ||
|
358e2b3ccf | ||
|
4203065a06 | ||
|
bc4e0190a0 | ||
|
dd7004cbc9 | ||
|
bdc5c8f620 | ||
|
02d36e22ee | ||
|
331e8c4aa6 | ||
|
d622277c11 | ||
|
8f781ea4ab | ||
|
ebc1e5bf12 | ||
|
ce9a61622e | ||
|
e4891e699f | ||
|
d8765578c8 | ||
|
3a034ecec8 | ||
|
a3dea45089 | ||
|
de99c8a5e4 | ||
|
d3b8dbeea0 | ||
|
cff2f64155 | ||
|
7b8de35405 | ||
|
02ae0df2cc | ||
|
b386cea69d | ||
|
758ffb75a9 | ||
|
78fbc7f392 | ||
|
9c58472576 | ||
|
f8c4afc228 | ||
|
b169d65619 | ||
|
9bf0d4f804 | ||
|
4443f57f8a | ||
|
ea5d8590d5 | ||
|
5d5feb4c71 | ||
|
feb5351ec3 | ||
|
7630c25ef3 | ||
|
24238094e5 | ||
|
7cc9a03db8 | ||
|
2b2e8508d9 | ||
|
a70716f225 | ||
|
d9fcc46994 | ||
|
2d8acec6f0 | ||
|
cd06d8c63a | ||
|
a06ca55107 | ||
|
9686a9ba77 | ||
|
f7f4043ccd | ||
|
b7b55173a6 | ||
|
954253c7e2 | ||
|
cbe4d2cd7f | ||
|
40101129b5 | ||
|
4bb32c6d09 | ||
|
6e09ceeda6 | ||
|
d6a6a53623 | ||
|
4a97052708 | ||
|
3a4902ad4a | ||
|
77d14bc218 | ||
|
1d2a39a855 | ||
|
98b53b6b3d | ||
|
0148d8beaf | ||
|
5bfd84d3be | ||
|
351eb95feb | ||
|
56788f0933 | ||
|
017a376616 | ||
|
c5888cec66 | ||
|
3d5ad29eac | ||
|
c608636b7a | ||
|
1a97107b2d | ||
|
5ca3fbeaea | ||
|
44896db668 | ||
|
12efb87a23 | ||
|
9181be86ba | ||
|
053b01e036 | ||
|
86041d0968 | ||
|
bd87f63e91 | ||
|
b79b49e8f3 | ||
|
a0dde39d97 | ||
|
2e03868021 | ||
|
29384c2ba3 | ||
|
320743ab8d | ||
|
399e171083 | ||
|
184164b677 | ||
|
a8bd196234 | ||
|
239d425940 | ||
|
baa3c1461c | ||
|
fa8e398e90 | ||
|
6d9675a299 | ||
|
91e8ce62d4 | ||
|
06e641015f | ||
|
1c83059482 | ||
|
90b24d824a | ||
|
62457d0e48 | ||
|
90c96f7479 | ||
|
f87adebe41 | ||
|
8f24cc8d13 | ||
|
992802d196 | ||
|
8546d6730c | ||
|
0092289105 | ||
|
7c3923ad00 | ||
|
ef82039401 | ||
|
b01b9758e0 | ||
|
88b00f689b | ||
|
0a340d5d57 | ||
|
50545a83b8 | ||
|
4a57ff40d8 | ||
|
0238455a5a | ||
|
a53e963001 | ||
|
984608e23f | ||
|
f680c83d2d | ||
|
a79e51c76f | ||
|
2dfb349609 | ||
|
766f21b525 | ||
|
733dfa1467 | ||
|
63aa840b55 | ||
|
8b2d544576 | ||
|
d6046d2422 | ||
|
409939360f | ||
|
1d21f39fbc | ||
|
a477140a4b | ||
|
1bbf2d8ce6 | ||
|
40a65eec51 | ||
|
8431ebf2e8 | ||
|
bdcc0c5373 | ||
|
9cbf331533 | ||
|
77640714cc | ||
|
9457d95c3f | ||
|
c2ff949f2d | ||
|
ba8685a122 | ||
|
55464ed0dd | ||
|
fdf3691c87 | ||
|
aa6699cf3e | ||
|
b79b48baac | ||
|
5d22dbd99e | ||
|
4686bb5584 | ||
|
1f62b8f0b6 | ||
|
5759ed3728 | ||
|
827fbfb78f | ||
|
dc363de610 | ||
|
b9d6a235e3 | ||
|
ebc57fe494 | ||
|
e224ec4ae0 | ||
|
a5da347177 | ||
|
a257b15f86 | ||
|
a70cc53d82 | ||
|
1df2de9202 | ||
|
9e394ea349 | ||
|
b55685d610 | ||
|
2156aac046 | ||
|
6914465e3d | ||
|
f3847ec6f3 | ||
|
e1fe8d1d89 | ||
|
675c937a4a | ||
|
c8f53bdf8e | ||
|
3541d5adde | ||
|
b52da7c9fc | ||
|
de57daa3cd | ||
|
e70e011a9c | ||
|
99febb99f1 | ||
|
874d79be36 | ||
|
b33663c9f8 | ||
|
7e69fa39eb | ||
|
de06490539 | ||
|
40a30c24a0 | ||
|
de04c12d3c | ||
|
38fb53b058 | ||
|
ed617c5943 | ||
|
986337da0c | ||
|
8dd7621f29 | ||
|
88d862303d | ||
|
cc274ffebe | ||
|
28a108f79b | ||
|
b9f75bf7d2 | ||
|
39994d5797 | ||
|
8e28be6558 | ||
|
8a65bef004 | ||
|
b94dc5044b | ||
|
b853c00dd4 | ||
|
7a0bc81f48 | ||
|
10bc326490 | ||
|
1920f8158e | ||
|
0ed2ba0183 | ||
|
95adc0aec1 | ||
|
ebee80d10e | ||
|
63836185d9 | ||
|
d0195e0509 | ||
|
5d9bcd9918 | ||
|
db04c26d24 | ||
|
56b399655e | ||
|
24e15c0568 | ||
|
f0c516e82d | ||
|
f38203ef62 | ||
|
a77c026803 | ||
|
5b6306671c | ||
|
25610222bc | ||
|
c17f941fb9 | ||
|
ae6ab1d203 | ||
|
92accf99b4 | ||
|
b02702fe80 | ||
|
5c549ec6e5 | ||
|
af459a5a28 | ||
|
07770601f6 | ||
|
cc96b86b3a | ||
|
1547f4d8b2 | ||
|
75054fcc70 | ||
|
390b3b173b | ||
|
78daa65d28 | ||
|
3bbdd08d24 | ||
|
cec1f12918 | ||
|
d923ae2107 | ||
|
85931155e6 | ||
|
4fd87aca09 | ||
|
600e0ec7e3 | ||
|
51fbff1a4a | ||
|
03b1389ee5 | ||
|
8f014e9d82 | ||
|
cecc6f7561 | ||
|
62ba81c6a6 | ||
|
c5e3422fcd | ||
|
bd5a46b4ab | ||
|
3a972bbbab | ||
|
7768ea28bd | ||
|
75add44e86 | ||
|
7d94365cbf | ||
|
2d830fb8e7 | ||
|
633bf36fe7 | ||
|
c0a5e23d95 | ||
|
d3798344dd | ||
|
ed37460402 | ||
|
9b6ba65cdb | ||
|
42a9631926 | ||
|
676a8a6421 | ||
|
cdbf022ce0 | ||
|
db79e1271e | ||
|
d2b3efacf9 | ||
|
a2ab94f971 | ||
|
a0d92d764b | ||
|
649b78e3f2 | ||
|
e7df1c3e56 | ||
|
53833ae0c3 | ||
|
66b914774a | ||
|
fc89feec4e | ||
|
d311dbd9d5 | ||
|
f97aa67100 | ||
|
9a8add780c | ||
|
3b48f1d042 | ||
|
332b54e7a5 | ||
|
007b2f0c88 | ||
|
3f083862e7 | ||
|
39619d5277 | ||
|
d4fe01f9b9 | ||
|
6db61b4357 | ||
|
f245cbf7f2 | ||
|
6f2b04669f | ||
|
9a46081d0b | ||
|
3c7e507ca1 | ||
|
7117725e69 | ||
|
ba428c6cfe | ||
|
d76c924ad1 | ||
|
cad7debc5b | ||
|
40725aa2a2 | ||
|
6034891fed | ||
|
9dd9862d33 | ||
|
48c72e319b | ||
|
4b6208fd9c | ||
|
168904a159 | ||
|
28f1498ec3 | ||
|
d3028e10d3 | ||
|
5eb0b77a8a | ||
|
4aace5b95a | ||
|
044dbd4a65 | ||
|
5dbae7c9d7 | ||
|
ec44cb2761 | ||
|
b06cf55c0b | ||
|
b601f6a138 | ||
|
ddebc63488 | ||
|
35440822be | ||
|
f4c6bcfb8e | ||
|
6365c5c9ef | ||
|
dd0334d30d | ||
|
c462a44973 | ||
|
6f88f5db83 | ||
|
93617f62a2 | ||
|
61d5f39408 | ||
|
c1fddaa7dd | ||
|
188aa14d82 | ||
|
5c25dd5b6d | ||
|
7c579cf7b7 | ||
|
c755c823fa | ||
|
116588c237 | ||
|
f02c1e4dc7 | ||
|
c4e8cc1641 | ||
|
93e68ad147 | ||
|
7ba88a83f0 | ||
|
c9293327ce | ||
|
fa1f35a89e | ||
|
845ce7a711 | ||
|
2b40007563 | ||
|
217034c4a7 | ||
|
0b9d4f17ab | ||
|
7fb0ec12dd | ||
|
3581158a7b | ||
|
facfa73214 | ||
|
0ef4a86d42 | ||
|
d4ec4795c3 | ||
|
b13d0aa283 | ||
|
a6965342e7 | ||
|
752dfa5b7f | ||
|
87aa283f22 | ||
|
6598ae080f | ||
|
7c5e8a66e4 | ||
|
c9577bcdc5 | ||
|
8254c2e83c | ||
|
20a9ac841d | ||
|
ae86b75d89 | ||
|
93a0afe612 | ||
|
439027220b | ||
|
4a07272d7a | ||
|
81432b54a3 | ||
|
b84a6e0c02 | ||
|
37dc5a00e8 | ||
|
e6edf85fbe | ||
|
cb533a26f2 | ||
|
a7278f76a8 | ||
|
80bd32382f | ||
|
db21ced104 | ||
|
717c6555cb | ||
|
a412e4af5c | ||
|
3350bf1ac6 | ||
|
4aa3353a1d | ||
|
ff48a58537 | ||
|
08fa511d17 | ||
|
c295115ffc | ||
|
5fb14610ec | ||
|
e87c2350b7 | ||
|
44e691e840 | ||
|
b5a7234cf3 | ||
|
d12509957f | ||
|
f01e7b7e20 | ||
|
6aa156d956 | ||
|
ef5ea93de1 | ||
|
b4913f51f2 | ||
|
dc3e960e79 | ||
|
0fe79b5288 | ||
|
1f76bd1942 | ||
|
3545f80920 | ||
|
0b2d1564ef | ||
|
fdacf824b3 | ||
|
5c01a44644 | ||
|
4eb49d872b | ||
|
34e5f29419 | ||
|
f4910f0a8e | ||
|
c8c14611dc | ||
|
491201991e | ||
|
401f3574fd | ||
|
173a86172c | ||
|
9ecbff024a | ||
|
1b5be34be4 | ||
|
ceb3a997b6 | ||
|
b1ead7fec8 | ||
|
d534dbb006 | ||
|
e56377117b | ||
|
63483dc6c3 | ||
|
66ceafd010 | ||
|
dd793650c3 | ||
|
afd829307d | ||
|
09abdc0f12 | ||
|
ed4d17f578 | ||
|
aeeeb5a37b | ||
|
dcb2e51587 | ||
|
cbc2eaf908 | ||
|
8808031e7c | ||
|
23ac7213d3 | ||
|
add7b44d0b | ||
|
1e4b7599a7 | ||
|
54443b038a | ||
|
c3f03e3f95 | ||
|
18135624f6 | ||
|
11238d6b71 | ||
|
848f94b1e0 | ||
|
d47cfe9504 | ||
|
70dccff293 | ||
|
e40873710b | ||
|
b140ef3b7a | ||
|
3b7b74aa67 | ||
|
de8e5b2d69 | ||
|
afea33b0e3 | ||
|
b44fbc1e4f | ||
|
c4dee3dd8d | ||
|
091e024032 | ||
|
0e030f7f48 | ||
|
3341c9e3bf | ||
|
91ddc00f7e | ||
|
3049ba0b24 | ||
|
55a161fafe | ||
|
349af24c81 | ||
|
788f1c4b3e | ||
|
889af461c6 | ||
|
df86e59089 | ||
|
c6bf69cce4 | ||
|
e492012004 | ||
|
94c46f9881 | ||
|
1eaa9d32ea | ||
|
0e2e8d2e2a | ||
|
cfb39c6364 | ||
|
173499f496 | ||
|
1081049074 | ||
|
961dc85514 | ||
|
6434acd492 | ||
|
ccb27c89d8 | ||
|
8053256203 | ||
|
4abd7301fd | ||
|
d6fe5ab417 | ||
|
a739fbdf1d | ||
|
c90a1ab6dc | ||
|
05ef68e079 | ||
|
dee4a7f3c7 | ||
|
75753df0d8 | ||
|
30c5d78647 | ||
|
6bb4db3842 | ||
|
cc0907fcd7 | ||
|
20b018bcc7 | ||
|
aafe2fa8d0 | ||
|
ee7bd73b3f | ||
|
b67f3bd629 | ||
|
38b81e79f8 | ||
|
b73c549131 | ||
|
d21d9f0141 | ||
|
7bb85032a1 | ||
|
d90446ad28 | ||
|
8b5e2f5528 | ||
|
1bcc3ab7f1 | ||
|
3359c3cd45 | ||
|
af812f3c90 | ||
|
1e6201093b | ||
|
959ea69427 | ||
|
cea744a914 | ||
|
e8baf48764 | ||
|
41242a2ae1 | ||
|
f1dee488a7 | ||
|
3b4ff1818e | ||
|
497145b1b5 | ||
|
10eb41d319 | ||
|
4daf2e4a3d | ||
|
f3266a5111 | ||
|
27cac4e8b8 | ||
|
60b9a5b9da | ||
|
eaaa62a7f3 | ||
|
6ce732ec3d | ||
|
fb0cc61e09 | ||
|
be29b5daf8 | ||
|
f010adabd0 | ||
|
c93b263b1f | ||
|
15f34d6b54 | ||
|
d0eeb55999 | ||
|
08c0d39b23 | ||
|
d0ecde3277 | ||
|
45ec57afd7 | ||
|
b0cd053083 | ||
|
698a11be58 | ||
|
efb08fb1e1 | ||
|
f89bc8422e | ||
|
4bf4889a08 | ||
|
01ab8ba38e | ||
|
ae6d15e812 | ||
|
1abfbe1d34 | ||
|
d3095297c2 | ||
|
79d40d5644 | ||
|
008e305a84 | ||
|
0379611edd | ||
|
96d883c1c7 | ||
|
be0f262e37 | ||
|
1676adf071 | ||
|
a5d5630067 | ||
|
275956caba | ||
|
bf8ed87fc9 | ||
|
fb3afac097 | ||
|
eda8b037a9 | ||
|
8ef14f7a54 | ||
|
9974e35656 | ||
|
15bc5431b6 | ||
|
f767531d89 | ||
|
7285ada9dd | ||
|
b9b9773df9 | ||
|
c29a83b259 | ||
|
fa45e66da6 | ||
|
7cbcdddac9 | ||
|
a2f17900da | ||
|
fb7e97b8ad | ||
|
0c92a8a8e9 | ||
|
dcc59380e5 | ||
|
f9bf25f96d | ||
|
cbcbea8b08 | ||
|
62eb4f20da | ||
|
43d5311e5e | ||
|
a6f08a09d5 | ||
|
d93f5d7785 | ||
|
c7170e6dc2 | ||
|
bcf3ca7339 | ||
|
0388f5787a | ||
|
6514df9d96 | ||
|
8f5b9869dc | ||
|
580c5fe23f | ||
|
b0af5b26ba | ||
|
9e898932f6 | ||
|
1f873b93f6 | ||
|
f414707f11 | ||
|
505825056c | ||
|
38f7716738 | ||
|
a69d08b554 | ||
|
3ccdb64833 | ||
|
78d8bff599 | ||
|
a756fed70b | ||
|
3e2a1e3548 | ||
|
96b2f2b3a4 | ||
|
d81d7d4f68 | ||
|
20244c4fb5 | ||
|
b50d31ffe2 | ||
|
d709a44960 | ||
|
4e4d07ced6 | ||
|
d775bc9d7e | ||
|
85528761eb | ||
|
ad3eac9ddb | ||
|
613f9fccd2 | ||
|
3d1741c904 | ||
|
26be14ba67 | ||
|
daa0755920 | ||
|
305d60e09b | ||
|
d0029efd02 | ||
|
fb4d42bf5b | ||
|
20eec53b14 | ||
|
8343db44db | ||
|
649652e373 | ||
|
e37ed7c32d | ||
|
f9a525068b | ||
|
aa11e6d62e | ||
|
6802d152da | ||
|
3b40f393d8 | ||
|
020443ae8a | ||
|
1d0baccffc | ||
|
5426f0f329 | ||
|
790249dd1a | ||
|
446a201d25 | ||
|
b6538d5e18 | ||
|
edd6043059 | ||
|
fe4ffeb7f1 | ||
|
27b3875bfb | ||
|
e2dbe8a0a2 | ||
|
29fc7910b7 | ||
|
22e2fdc707 | ||
|
584786eb9f | ||
|
d803d9eaf9 | ||
|
bad6575d83 | ||
|
fbcb7ae836 | ||
|
2c1a1b10c8 | ||
|
155fb16a8a | ||
|
b1ab2ce96a | ||
|
f299ba6218 | ||
|
d167ad1923 | ||
|
93626e8154 | ||
|
d5040c091a | ||
|
868daef0f0 | ||
|
dc8e85e7f2 | ||
|
22d32d7ca3 | ||
|
2d500f8074 | ||
|
452cdc17c6 | ||
|
bcbfee0321 | ||
|
dab2e7ede3 | ||
|
d91acb8352 | ||
|
373dd8058e | ||
|
de6310e52a | ||
|
8c297a4a4c | ||
|
4eb5c817bc | ||
|
07e4b26b9e | ||
|
b63aa62985 | ||
|
ca701c0580 | ||
|
e37043a6a8 | ||
|
7c26975d14 | ||
|
47f8a43637 | ||
|
1238c0cefe | ||
|
4c35fda045 | ||
|
780124c2f5 | ||
|
38e0af41ce | ||
|
601e99eec0 | ||
|
745a2adee7 | ||
|
9e83234df1 | ||
|
e45eeadf7d | ||
|
9a778cea6b | ||
|
20823bfc87 | ||
|
be3d703692 | ||
|
e2df5739f0 | ||
|
7bb11d6436 | ||
|
80b84212cc | ||
|
4a1bee769b | ||
|
de99a7aeaf | ||
|
a0a02701b0 | ||
|
1314ae1555 | ||
|
67cf0e745c | ||
|
538a2acbf5 | ||
|
8d0e453666 | ||
|
ace04f0b30 | ||
|
f8e25d6c4a | ||
|
b2bc43da4f | ||
|
cb12e540d2 | ||
|
39955af2fa | ||
|
86e1f0615d | ||
|
dc81ab6dee | ||
|
f8cf6a65ae | ||
|
ba909c696d | ||
|
df0515cebf | ||
|
46c0e14d67 | ||
|
97d7733464 | ||
|
afda84ef09 | ||
|
61d6e74102 | ||
|
8d74258ce2 | ||
|
5dfba0b834 | ||
|
056370ec08 | ||
|
4e2c254558 | ||
|
38c2bdb447 | ||
|
0cee4717e2 | ||
|
221b04c466 | ||
|
237e9b7191 | ||
|
9457e44a88 | ||
|
80a9d40a44 | ||
|
0715325a63 | ||
|
0a026fef0f | ||
|
5fbf650d2d | ||
|
dabdde0c3f | ||
|
b6ca92a7ef | ||
|
62f7339170 | ||
|
eaec682ea7 | ||
|
12110a4442 | ||
|
df597f53b2 | ||
|
d7d40254d4 | ||
|
e7c4a2cce6 | ||
|
0eb1c0cea6 | ||
|
07d35a8513 | ||
|
16c887814e | ||
|
22a50b72fd | ||
|
a79e1b6ca1 | ||
|
995296ef53 | ||
|
f4d5996a88 | ||
|
ab732b5435 | ||
|
241ff5cb6e | ||
|
ec2169e079 | ||
|
c75662e720 | ||
|
d567fd4842 | ||
|
0776dfc80e | ||
|
79a662fb93 | ||
|
8b009b7ee9 | ||
|
c4face30cc | ||
|
d4dbb5cb51 | ||
|
1e27187652 | ||
|
3ff278291f | ||
|
4e8bf216df | ||
|
e7b9100f1c | ||
|
08aa9790f3 | ||
|
5f13fd2dca | ||
|
f4c6f42c38 | ||
|
6a10d08189 | ||
|
f646360af6 | ||
|
95f265ebbf | ||
|
39d0142993 | ||
|
da16172244 | ||
|
71aded0fae | ||
|
e173b3ea41 | ||
|
6c4f9466b9 | ||
|
664196c5ef | ||
|
c8d5044e7a | ||
|
d8c31fe560 | ||
|
516db855f5 | ||
|
9cdcf08ab1 | ||
|
326fa73b22 | ||
|
79cacefd07 | ||
|
07e28bfee6 | ||
|
980b017fbe | ||
|
4567fd1eb0 | ||
|
8c150c23f3 | ||
|
b4fd570269 | ||
|
681a845ef3 | ||
|
6e051d73c1 | ||
|
e381e1a313 | ||
|
2d03ff63cf | ||
|
309de631ed | ||
|
ad240cf52f | ||
|
99e3a47dde | ||
|
3fa810b7b8 | ||
|
bad7316b80 | ||
|
4757c36233 | ||
|
9ca6180207 | ||
|
30179ad977 | ||
|
b799609749 | ||
|
efb6994ae7 | ||
|
cd129fb055 | ||
|
880a977dd6 | ||
|
6eceffb403 | ||
|
795e33881c | ||
|
d310c3857f | ||
|
837e275bfd | ||
|
7be6031e19 | ||
|
8c53908cc4 | ||
|
589b54984a | ||
|
3f30ed5251 | ||
|
3f9181905a | ||
|
29f3a81666 | ||
|
5efc43260e | ||
|
e01794a07f | ||
|
5fde095a6f | ||
|
3237af2d85 | ||
|
953b666ebd | ||
|
417bb4bf37 | ||
|
a55213d88a | ||
|
ec84d190f4 | ||
|
1b0bad72de | ||
|
931055708d | ||
|
15fd570b49 | ||
|
ff9c6bac0a | ||
|
713111254b | ||
|
5b1462a3e8 | ||
|
2bf18d8bda | ||
|
7f2e643e62 | ||
|
ef172592b8 | ||
|
5e51a438a7 | ||
|
7f768059e6 | ||
|
ea70175a17 | ||
|
74a736691a | ||
|
86ff44adfc | ||
|
58b763e935 | ||
|
5c90cc59aa | ||
|
710ab44073 | ||
|
b28c5e6807 | ||
|
e5ead9ed44 | ||
|
d99897cf9d | ||
|
701a7cae02 | ||
|
068b6a5470 | ||
|
45d597ac49 | ||
|
a518d3f33f | ||
|
2f05228d91 | ||
|
335ae0105f | ||
|
62ce7a0e37 | ||
|
afa0fb8da1 | ||
|
763d835f4e | ||
|
0289872dcd | ||
|
2810141bd6 | ||
|
93ea22c69d | ||
|
daf76a311c | ||
|
b94271a725 | ||
|
1456aeedf2 | ||
|
4c6589a57e | ||
|
5b9a61b7db | ||
|
96e71695c5 | ||
|
2e7dd1bde3 | ||
|
2de543f5f9 | ||
|
a6ee20fca4 | ||
|
2d2f159e04 | ||
|
5568e0c2ad | ||
|
cb2cc0cb9e | ||
|
5e573ca980 | ||
|
dcb4a315a6 | ||
|
4bd36fc29e | ||
|
1a7971ec82 | ||
|
c1eda034b3 | ||
|
2294d722c7 | ||
|
7d053be6d1 | ||
|
7a508661eb | ||
|
c976242ce5 | ||
|
2b77c372a3 | ||
|
b61cc67997 | ||
|
de8db1a86d | ||
|
abfdf0e1c2 | ||
|
1d662e354b | ||
|
663e9a9b5e | ||
|
8535409962 | ||
|
cd5623b348 | ||
|
673e051bd5 | ||
|
66c949057e | ||
|
aed09f0c64 | ||
|
c05f306b0d | ||
|
739fb99ced | ||
|
7fc82ccead | ||
|
8ae947f59c | ||
|
d34b493b7d | ||
|
4df6e0ee7d | ||
|
aac4ef05e4 | ||
|
ea2f53e166 | ||
|
f144ec67ab | ||
|
7e42dcf0b5 | ||
|
87c4dc313a | ||
|
0d29339898 | ||
|
6d83f18490 | ||
|
0ba125c2d7 | ||
|
6abd120a5c | ||
|
5cf7e89ce6 | ||
|
353786cb61 | ||
|
586beea21e | ||
|
b80454a1f4 | ||
|
19f80cf506 | ||
|
d01100bb15 | ||
|
e0414e4eb9 | ||
|
1eb10e3c22 | ||
|
4772fbcd4a | ||
|
18b61e35be | ||
|
bb7faf0fb3 | ||
|
1603742adc | ||
|
8a830e40bb | ||
|
d8adcf5a84 | ||
|
1d9a404f77 | ||
|
26dcaf6078 | ||
|
a91e4014bf | ||
|
06af327e5e | ||
|
35e3b889c3 | ||
|
5ef6ba0258 | ||
|
12754ff135 | ||
|
d09a1e254f | ||
|
b89ee67daf | ||
|
7bd256c311 | ||
|
4add7cd0b3 | ||
|
5ac20cc4cf | ||
|
9d7b0487d5 | ||
|
59aa84f6c8 | ||
|
765b03c868 | ||
|
41ce3db8f9 | ||
|
00e3ef757c | ||
|
84dc0b2959 | ||
|
2e48099070 | ||
|
77779bbcd9 | ||
|
e08bc01c33 | ||
|
bf24ee369f | ||
|
876f12db89 | ||
|
8b84459e13 | ||
|
dccfcc9663 | ||
|
203e1cc9b9 | ||
|
b612f0cdec | ||
|
961301fbec | ||
|
2a38d99cf1 | ||
|
7903328c2d | ||
|
56d2b4a80c | ||
|
2c6ecaab5b | ||
|
45d289a65e | ||
|
318c8c68b0 | ||
|
fbd47a7f3b | ||
|
07533f5658 | ||
|
66b7e3e1f5 | ||
|
4fee4d1903 | ||
|
90d70beea2 | ||
|
a7297d2685 | ||
|
86ae704e86 | ||
|
2d1e993fe1 | ||
|
04b550e435 | ||
|
c492ea77f1 | ||
|
61d9112ba7 | ||
|
d7fe36de71 | ||
|
db0bd3fa2d | ||
|
551619e772 | ||
|
29bae230a4 | ||
|
83be49156f | ||
|
561ae102fb | ||
|
a05e69b855 | ||
|
8eb772d80b | ||
|
1590693547 | ||
|
66f93ee541 | ||
|
8893df118e | ||
|
2c77cb5ca5 | ||
|
8a101f9e9a | ||
|
ce98d0184d | ||
|
402dea3c8b | ||
|
223cf4b2b2 | ||
|
8fb7e79bb3 | ||
|
5a2d386976 | ||
|
96622533e0 | ||
|
8814ce05a9 | ||
|
c15148fc07 | ||
|
3404ebbbb8 | ||
|
51494cabc8 | ||
|
1eb326683e | ||
|
98bcfbef7e | ||
|
9416980096 | ||
|
b34505c086 | ||
|
a65edf52ca | ||
|
d1513f2575 | ||
|
12d20c35be | ||
|
9f822c0991 | ||
|
96c338859b | ||
|
a2464dce73 | ||
|
53476b723d | ||
|
ca92a0af5c | ||
|
6e6cd90f6d | ||
|
adc84e1f93 | ||
|
20687d915a | ||
|
12a34f0b09 | ||
|
e5e49e4347 | ||
|
9f61256e5e | ||
|
ac6e370a78 | ||
|
a9c2c2178a | ||
|
c67419bb55 | ||
|
631c270fc7 | ||
|
3c82dfc0a5 | ||
|
063574023b | ||
|
5f539b133b | ||
|
0bb52a6058 | ||
|
0db40bbb32 | ||
|
f66114e203 | ||
|
2fcc064b0f | ||
|
a4c441a1b7 | ||
|
cbb6e4d6f3 | ||
|
34361ccd1c | ||
|
c953936798 | ||
|
6fd2a6ef34 | ||
|
be05f1a71f | ||
|
0de65d9c0f | ||
|
a60f4e3bad | ||
|
ab30ea766b | ||
|
099a7c46b7 | ||
|
a7afcd9644 | ||
|
7c80eec755 | ||
|
07c50c20b6 | ||
|
08d841f6c5 | ||
|
6b144c5816 | ||
|
322cec0980 | ||
|
73a47b2853 | ||
|
0036ec2214 | ||
|
98dc69893e | ||
|
af48af5085 | ||
|
0b2279a113 | ||
|
ba63a44ec8 | ||
|
7c20d2f97c | ||
|
8e7369f0b5 | ||
|
5f80deb5b7 | ||
|
826fdbf342 | ||
|
7e5186c3c7 | ||
|
2bc5253725 | ||
|
f58787bb50 | ||
|
88a01d39ee | ||
|
ee88897b18 | ||
|
b26f9e316d | ||
|
0e486b45e1 | ||
|
f730d2fc27 | ||
|
26303c8617 | ||
|
a6485b61a4 | ||
|
7db07bca35 | ||
|
19bbe0fc1f | ||
|
2b2c2de583 | ||
|
b05534472c | ||
|
30aa8d469c | ||
|
c4282a3593 | ||
|
778107aae9 | ||
|
581af762f9 | ||
|
31e63b576b | ||
|
efb592dce5 | ||
|
fa5b936d7b | ||
|
4904bd53ef | ||
|
320ce372f5 | ||
|
7a803abec8 | ||
|
f34407fc43 | ||
|
b41bda569d | ||
|
fd2919fd1c | ||
|
dce8edf742 | ||
|
298e32aada | ||
|
2b2136867d | ||
|
c1830aa37c | ||
|
a3d4049c9c | ||
|
058b4bbe6c | ||
|
c4c7b2ed5b | ||
|
aee607ea81 | ||
|
5eea5939c0 | ||
|
ac53d64ffc | ||
|
9ebee8c03e | ||
|
93965fd98b | ||
|
59c25ef915 | ||
|
7e9c4848fb | ||
|
467b1ad4f1 | ||
|
f45bd18cc2 | ||
|
4f844abc0c | ||
|
b688dcd4ba | ||
|
d5e902679b | ||
|
eae21e1371 | ||
|
947c2e556d | ||
|
d68d4c2c76 | ||
|
1ef451c048 | ||
|
ec20748594 | ||
|
764f05b42a | ||
|
5c41e24b99 | ||
|
9725091233 | ||
|
8f8dfabe0f | ||
|
b9749bad61 | ||
|
31609a8aba | ||
|
28e8cc2675 | ||
|
033d3c92ab | ||
|
3484fcfd2a | ||
|
a8e18d7f99 | ||
|
db30b58ee9 | ||
|
3748488200 | ||
|
c53a20a577 | ||
|
dfcb2b610a | ||
|
95278a78ff | ||
|
400d577546 | ||
|
60cf6cec5e | ||
|
13901b9028 | ||
|
23454a918d | ||
|
fa64ecf513 | ||
|
bb8c0f1d9c | ||
|
6e33e063da | ||
|
e44893f91e | ||
|
f2c3fc20de | ||
|
d903fe400f | ||
|
22e4e4125a | ||
|
badddfe3d7 | ||
|
e14816dcfa | ||
|
4b83722a66 | ||
|
c798913fd2 | ||
|
636dbe5b95 | ||
|
ab28d0e09f | ||
|
a74efd285c | ||
|
3e1eb03517 | ||
|
fb90574d44 | ||
|
c0fb337dfb | ||
|
e7775bb9d9 | ||
|
64f2a67573 | ||
|
154e33a2c3 | ||
|
63ae2b8095 | ||
|
6165a6af6c | ||
|
4a70e3cd31 | ||
|
5ccf053cba | ||
|
5a6f5133af | ||
|
1a2b4f8260 | ||
|
5436050df1 | ||
|
d3f3946971 | ||
|
597a7f7b40 | ||
|
02f549d1dd | ||
|
0c096bb090 | ||
|
8bc6cd7fc9 | ||
|
65d9e5d1fc | ||
|
47c356692f | ||
|
ef9157174c | ||
|
7345807871 | ||
|
19b9d3737e | ||
|
db3be3d80a | ||
|
60c7522f22 | ||
|
60002793b0 | ||
|
9e5a4189d7 | ||
|
945cbdd3a7 | ||
|
f974fd0660 | ||
|
af9fdfa224 | ||
|
77c72d2bb3 | ||
|
8404617090 | ||
|
cc9a429689 | ||
|
44f50eba5b | ||
|
f4509e24c6 | ||
|
e17a40fdb2 | ||
|
181cb235df | ||
|
e3456cb74f | ||
|
e377552f12 | ||
|
9ab9e4894d | ||
|
5782979203 | ||
|
a4bb279da8 | ||
|
8df9549a42 | ||
|
de873c5f6f | ||
|
3425e929e9 | ||
|
60c5d96037 | ||
|
4b4c3ddb2f | ||
|
1ea50ea917 | ||
|
29f68d218d | ||
|
daad8bca69 | ||
|
f4408aa72c | ||
|
0117cd478b | ||
|
9ad22d7405 | ||
|
de4d0989e9 | ||
|
0c884c2669 | ||
|
5d7cfc1c10 | ||
|
fd2b070a6a | ||
|
455819566b | ||
|
b39113f0ae | ||
|
af0f1939a3 | ||
|
becb9fc43e | ||
|
8b9c274fdd | ||
|
0701f3496b | ||
|
09c03e8ca7 | ||
|
9285da6c12 | ||
|
6a0e16885d | ||
|
f0db135b1d | ||
|
4fb86bd699 | ||
|
c62082b924 | ||
|
e8f592c6e0 | ||
|
61935942cf | ||
|
f1d8bb84b7 | ||
|
7918448be2 | ||
|
f89f704a69 | ||
|
ae33de7e7c | ||
|
b23e474648 | ||
|
611bc26685 | ||
|
0dc39166ac | ||
|
8d970b7858 | ||
|
7033c4a182 | ||
|
2c0ca78265 | ||
|
0d3c03d1e3 | ||
|
b4dfce4a44 | ||
|
91ca3939b3 | ||
|
92db5d3a35 | ||
|
f252960aaf | ||
|
4aec39df7a | ||
|
15b19925f2 | ||
|
bfb376505b | ||
|
ec75ff5292 | ||
|
28eb0be4ad | ||
|
4d3b6b1486 | ||
|
d3fd9a188d | ||
|
41a15f90cb | ||
|
9c604a7886 | ||
|
8ad1d6fd97 | ||
|
a18e7eb089 | ||
|
1f5ea40bf6 | ||
|
44509e027c | ||
|
fe3758b1bb | ||
|
ebe2a30463 | ||
|
1216a26d13 | ||
|
65800853f4 | ||
|
ccb81179ab | ||
|
f2ea701d34 | ||
|
1d4aa27f1c | ||
|
bb08fe8113 | ||
|
e2099f0749 | ||
|
3c60feed02 | ||
|
5466e1b733 | ||
|
328f15c2ea | ||
|
873125abe1 | ||
|
5df818a19c | ||
|
a5dc3cd018 | ||
|
afe0e3c1d6 | ||
|
91e1f958f2 | ||
|
2a94ee55cc | ||
|
ccf612f536 | ||
|
c6fa0cc072 | ||
|
c282bb2fe1 | ||
|
72d18fd7e1 | ||
|
6802873cd1 | ||
|
1bdc46969c | ||
|
989ee0e281 | ||
|
0f27d646bb | ||
|
81aca500b3 | ||
|
50f2dded64 | ||
|
d26d94b62a | ||
|
2811f76714 | ||
|
67b21ad766 | ||
|
6d07d5dccb | ||
|
da0e3d5c8b | ||
|
b129fe908c | ||
|
f5c57e84c7 | ||
|
ceb4ef2642 | ||
|
1c235aa761 | ||
|
cfc8117c3c | ||
|
aa1f515fcf | ||
|
4fdd12bc48 | ||
|
34f04b1946 | ||
|
5770b9dc0e | ||
|
afe2b934de | ||
|
11fe6cfbb0 | ||
|
db10226005 | ||
|
a15b8077a3 | ||
|
a3836b5e17 | ||
|
f8d80422b2 | ||
|
9848f80630 | ||
|
6ea1732630 | ||
|
d97571ce0c | ||
|
1e3b866c8b | ||
|
2168838365 | ||
|
219021873d | ||
|
120b505361 | ||
|
347a2977fa | ||
|
c2e90864ac | ||
|
1027efd6e5 | ||
|
bd0de83d31 | ||
|
4d3523b677 | ||
|
03f15e0075 | ||
|
043779f4af | ||
|
25b5daf6a5 | ||
|
db444f5d7e | ||
|
16499d2fb8 | ||
|
ddff2b2982 | ||
|
e697ee72fa | ||
|
f98c59172b | ||
|
3badafaa82 | ||
|
cbf65a9355 | ||
|
365bc900b0 | ||
|
bd0da63f4c | ||
|
db0b663a3d | ||
|
fd7fe129e2 | ||
|
27253c360b | ||
|
ab226d16c8 | ||
|
d6394402b8 | ||
|
6be5fac953 | ||
|
c4435279de | ||
|
a9bdc8ad85 | ||
|
df2a5fc789 | ||
|
db87f9e15b | ||
|
5af2768d33 | ||
|
474695643f | ||
|
97ab88b39a | ||
|
3773d40201 | ||
|
b3fd01fe04 | ||
|
75c4ca77c2 | ||
|
692ddc60c7 | ||
|
1a296a8ca1 | ||
|
f5595dd4c3 | ||
|
11c0221f81 | ||
|
2d0aad3da9 | ||
|
ff19cb68b4 | ||
|
e62df3b3b1 | ||
|
1d024cc339 | ||
|
8bda91aafb | ||
|
fd9963e7eb | ||
|
dc81ca4f53 | ||
|
fb754f9bc7 | ||
|
7045f6571f | ||
|
50d9bccacf | ||
|
9064769185 | ||
|
5fc16bdbfb | ||
|
172e4e939d | ||
|
f914b728ff | ||
|
54857e843b | ||
|
64b34e98c7 | ||
|
1ccf74bca1 | ||
|
49a534a61b | ||
|
b8889c6a1f | ||
|
ccbc5c9d17 | ||
|
555e01ec87 | ||
|
7869f472c3 | ||
|
90f60f95f7 | ||
|
0f0a71a109 | ||
|
a43c8a2def | ||
|
cbafaf5d56 | ||
|
62e4e13f5a | ||
|
e69908abef | ||
|
6cb3cf8747 | ||
|
2f71a43420 | ||
|
f57ad57e62 | ||
|
03f5d9b102 | ||
|
6b17e1820c | ||
|
e0f6fca987 | ||
|
1fe95a5fe4 | ||
|
1257ecf100 | ||
|
4163304b24 | ||
|
d35f2c4a4f | ||
|
e5d5c5f9a7 | ||
|
6fcaec3ca8 | ||
|
a2892ad097 | ||
|
79c79146a5 | ||
|
cd37ba308c | ||
|
b35c0f7e39 | ||
|
14b1b649cb | ||
|
14c0307c09 | ||
|
42f22119f2 | ||
|
75f4771616 | ||
|
83f7cb2033 | ||
|
43a4c6198c | ||
|
8c2fafecd7 | ||
|
d004c0ccd1 | ||
|
406ae4e8c3 | ||
|
cd8bee1371 | ||
|
123392c549 | ||
|
42ffe213fd | ||
|
fd738e5c8b | ||
|
6f95b2c2ad | ||
|
f66c2b078c | ||
|
c6f5c120ba | ||
|
677e93430d | ||
|
a9a90c5545 | ||
|
ee0418e719 | ||
|
6fc1141477 | ||
|
b02920c43c | ||
|
049d249609 | ||
|
fc2a554415 | ||
|
42b806b500 | ||
|
aeb3ccaf09 | ||
|
86fdd91597 | ||
|
e68fea185d | ||
|
a3eaf9f473 | ||
|
e6a2b9f06e | ||
|
a78973702b | ||
|
354b745c39 | ||
|
ce6cd6acdc | ||
|
8e129143f1 | ||
|
6d50cbba6f | ||
|
7731878f36 | ||
|
9f659eef1b | ||
|
14cc642e54 | ||
|
c47852cd0a | ||
|
c3bfaa31ee | ||
|
832505a315 | ||
|
cb71667336 | ||
|
1032e97d58 | ||
|
b4271da13e | ||
|
e2dc5ef4f2 | ||
|
c75ee042a8 | ||
|
d474d518ca | ||
|
52b8dbcbb1 | ||
|
0d8d8f0426 | ||
|
ed12deae25 | ||
|
7f1e7c981d | ||
|
cc26688d82 | ||
|
a0fa3a6063 | ||
|
110a1a640d | ||
|
bbdc43c750 | ||
|
c73b9b4882 | ||
|
e249092f91 | ||
|
5c0b04bfc8 | ||
|
bc257f4951 | ||
|
e738ee0812 | ||
|
ebb2db17f3 | ||
|
4214293b76 | ||
|
ce3ee909bf | ||
|
09ba1e2470 | ||
|
68444b81cc | ||
|
d3c0b9a438 | ||
|
6e2f1f72c6 | ||
|
c82eec09b7 | ||
|
d4093d8c98 | ||
|
90616c82b6 | ||
|
de69fe1745 | ||
|
9bd42ac221 | ||
|
2f9a272696 | ||
|
552ea0356e | ||
|
ff6bd91ef7 | ||
|
835f20f872 | ||
|
1e9b35d18f | ||
|
3818e48218 | ||
|
5d63065057 | ||
|
ae41ed1d51 | ||
|
36ead2251a | ||
|
dc7093f68a | ||
|
6c79d2b008 | ||
|
422349c2d1 | ||
|
7dbfa0b203 | ||
|
57ea2ac039 | ||
|
a9e664e89d | ||
|
c0e2210da3 | ||
|
b13c6f283a | ||
|
8181b9a31c | ||
|
105e4f990d | ||
|
9670d74345 | ||
|
86e553e756 | ||
|
566ea9a110 | ||
|
f59f035a7e | ||
|
4c6d4f3caf | ||
|
8af87bac22 | ||
|
690567659c | ||
|
d9c7ee8976 | ||
|
95cf554de4 | ||
|
47a87a14f5 | ||
|
5e860b6850 | ||
|
9a983e7565 | ||
|
00197d131d | ||
|
9758f3c9d2 | ||
|
e7d7425b6e | ||
|
b566c81ae7 | ||
|
742837e7a1 | ||
|
5087dbd756 | ||
|
b893ae7c14 | ||
|
1f7863057f | ||
|
3dd3afd21f | ||
|
387d3b7335 | ||
|
782bfd058b | ||
|
c0d936fa4d | ||
|
63819c5757 | ||
|
08cbac6277 | ||
|
68c0a9aec4 | ||
|
1c585815a1 | ||
|
853ec7320f | ||
|
b8917a3c0e | ||
|
c4d70e7f9b | ||
|
7f1b11d19b | ||
|
02a32dea40 | ||
|
d9e20ea17a | ||
|
039c2fe0a6 | ||
|
a967e73f9e | ||
|
222e4154a1 | ||
|
56413ee94e | ||
|
93c07b2b1e | ||
|
27ed64a1af | ||
|
ad68106c3c | ||
|
a591cf1d21 | ||
|
03a4b8f5cf | ||
|
2d8d25808d | ||
|
a82fcce734 | ||
|
0734e136d0 | ||
|
2913120ff7 | ||
|
bd277b087a | ||
|
fc00966b8b | ||
|
495a76353f | ||
|
6ea225ed2a | ||
|
c1a5f59c42 | ||
|
49fb9108e9 | ||
|
4cb3b514ab | ||
|
c95a37130a | ||
|
29e82cc509 | ||
|
a4cb53fdb4 | ||
|
865dce6f68 | ||
|
1d02154d99 | ||
|
3a8d72db31 | ||
|
ec57a240d5 | ||
|
949f7587dc | ||
|
55cce646e0 | ||
|
4c3dce694a | ||
|
46d5b70391 | ||
|
08a102d182 | ||
|
1cf8e08d4b | ||
|
65a8b83150 | ||
|
f4c8db654c | ||
|
5c4d1c0259 | ||
|
a459f8b84c | ||
|
0d672420f7 | ||
|
2f7be0559a | ||
|
0623ae1f87 | ||
|
8ae946c2c5 | ||
|
bb75f6ffce | ||
|
fcfe83f0cc | ||
|
5cbcded929 | ||
|
2a95f792ec | ||
|
daa2808448 | ||
|
fc06ffdcee | ||
|
1601179081 | ||
|
7fe374b67e | ||
|
7a353bbe48 | ||
|
c103ff271b | ||
|
ab9e0f891a | ||
|
af85ef8cfb | ||
|
3cea6e5d0c | ||
|
6d1b0ae498 | ||
|
07d5b07748 | ||
|
d47b9cd5c0 | ||
|
d542c063d7 | ||
|
4bb3d33907 | ||
|
62bec25b6e | ||
|
3ba16f1773 | ||
|
c302030301 | ||
|
49abe2b11f | ||
|
544e7fce88 | ||
|
b9e7f018e2 | ||
|
f31049cf69 | ||
|
2b3b73b3f1 | ||
|
704bb5a848 | ||
|
01f7d7add2 | ||
|
831d8b6d36 | ||
|
2e9b6ead2e | ||
|
d71fd0ff2d | ||
|
6466bd4ba7 | ||
|
a97fa1abb6 | ||
|
6171e5cc6e | ||
|
456502893c | ||
|
443a90c7ba | ||
|
b8a72245dc | ||
|
d019f88e26 | ||
|
01cf4cc1ed | ||
|
396bbd83c8 | ||
|
92e0affb85 | ||
|
6552157894 | ||
|
af41e4892f | ||
|
09531b399a | ||
|
6251b77b28 | ||
|
0099b6d4a2 | ||
|
adb8de9754 | ||
|
8ac8b666bf | ||
|
095feddf73 | ||
|
4882a801d2 | ||
|
1a1736ca0e | ||
|
a7619771a6 | ||
|
6febcf3b94 | ||
|
3947deb7bd | ||
|
98855de71f | ||
|
8010e6220d | ||
|
09e6a6a4ad | ||
|
da772e6649 | ||
|
65b8f78ca1 | ||
|
23bcac2e55 | ||
|
e6a88eef35 | ||
|
6654c461a6 | ||
|
a48cb052c2 | ||
|
809d932087 | ||
|
19d906c5e4 | ||
|
2f933a90fd | ||
|
3607875714 | ||
|
fec8829041 | ||
|
f58e758a41 | ||
|
cebed0824f | ||
|
97120bd1f1 | ||
|
4237d0c7e3 | ||
|
243cdfefa2 | ||
|
a12a4cd8f2 | ||
|
980b8a2924 | ||
|
989dca5792 | ||
|
c9eb06bb70 | ||
|
af89906b81 | ||
|
de71b1b397 | ||
|
2decee1d87 | ||
|
6a184b069b | ||
|
48db615ac8 | ||
|
bb9caa4838 | ||
|
3c11c3fc16 | ||
|
6c1dbc5e61 | ||
|
21bf1dd1a3 | ||
|
78aa2b491c | ||
|
53d2c7e89f | ||
|
cdf78db629 | ||
|
15c5725829 | ||
|
96653170a2 | ||
|
eade89da48 | ||
|
9b86049964 | ||
|
9e2bbd50b6 | ||
|
0d18266ad1 | ||
|
83ee0534f2 | ||
|
8ad00025ad | ||
|
7d08a7c9cd | ||
|
c8d5a5319e | ||
|
a08fa721cf | ||
|
89bc3137ba | ||
|
4d8d30f897 | ||
|
d67e9468c0 | ||
|
7dda36ab97 | ||
|
32df3e80b1 | ||
|
3c33969d23 | ||
|
c2aec5ae36 | ||
|
7afc908c32 | ||
|
c66ecbdd29 | ||
|
e61bccab36 | ||
|
cfeef98261 | ||
|
c949548150 | ||
|
829ccfca88 | ||
|
950fa84d1c | ||
|
5666729fcf | ||
|
3a13886af9 | ||
|
db6e0ccf63 | ||
|
35f2ebc2aa | ||
|
60ac4a3e86 | ||
|
c966d34b07 | ||
|
a05d7059fb | ||
|
facc1dc944 | ||
|
df2ebbf384 | ||
|
e210471c7a | ||
|
f42d552dad | ||
|
edfd9e46b6 | ||
|
27644776f3 | ||
|
a4797dcc73 | ||
|
677312648b | ||
|
ace460c69b | ||
|
b922fe35ab | ||
|
222e2166ff | ||
|
7dc25ec425 | ||
|
980835981f | ||
|
e425adc230 | ||
|
2ea7ef327e | ||
|
6c9d33f05c | ||
|
c584b51726 | ||
|
3c8fa3382b | ||
|
e5c75259e0 | ||
|
f78e437a42 | ||
|
8f61b1d320 | ||
|
84f3c6f7e6 | ||
|
bfb6c001a0 | ||
|
f0fa9f2033 | ||
|
c82cc30968 | ||
|
b0cb14b515 | ||
|
7f86d2aa0a | ||
|
482dd4db76 | ||
|
0f44fd2290 | ||
|
690d461693 | ||
|
f1ca72aee9 | ||
|
a3a6fc0d15 | ||
|
4f4fe5f06b | ||
|
c59f47f4b5 | ||
|
0ae810b8c6 | ||
|
ac9f42a8fe | ||
|
eab7e56ece | ||
|
7329515a4d | ||
|
6d6bf2df3a | ||
|
3008bfbe0a | ||
|
9399517cfb | ||
|
b117fe222d | ||
|
62567264f0 | ||
|
c054b3b0de | ||
|
83fb5b4d1b | ||
|
07a86800c9 | ||
|
688b5f29b6 | ||
|
e311f17062 | ||
|
b4cdb22e24 | ||
|
b63194c0aa | ||
|
0bab32315c | ||
|
7e881dd850 | ||
|
d6aaafb069 | ||
|
731fcb8829 | ||
|
af0e94a4b7 | ||
|
deda869cc5 | ||
|
434089395a | ||
|
048985bdf4 | ||
|
70d6d4246d | ||
|
70befe900c | ||
|
9fd81bf6c7 | ||
|
a388fe3acb | ||
|
d4946d931a | ||
|
9812654bfa | ||
|
557426246c | ||
|
d0a3e8f789 | ||
|
50b37f2ddd | ||
|
e4197012f6 | ||
|
df00a1e0a3 | ||
|
41327bfb03 | ||
|
66ef72a040 | ||
|
af660bc631 | ||
|
18edb13e76 | ||
|
e05431c847 | ||
|
5c61f95093 | ||
|
9a407c727a | ||
|
cad655a15b | ||
|
1fa5c53b72 | ||
|
d01b1a706c | ||
|
678d5fc532 | ||
|
c4e01fa566 | ||
|
e694622b83 | ||
|
1d16c96ca4 | ||
|
ab1f34726b | ||
|
c9f201755e | ||
|
094ef592a7 | ||
|
e7493c38d1 | ||
|
6fd0fcfdb5 | ||
|
6da534a961 | ||
|
f26e43144e | ||
|
427529171c | ||
|
cd146cf822 | ||
|
ced412372c | ||
|
2f6e650c1b | ||
|
5c125ca9b4 | ||
|
89c0939d58 | ||
|
8ea955fb23 | ||
|
73a297f23f | ||
|
95f1382fbf | ||
|
80df01c8ee | ||
|
c2df864119 | ||
|
2cc9356c32 | ||
|
89234c0163 | ||
|
1b7fe286a6 | ||
|
7c2d797ed0 | ||
|
4d2eedc56b | ||
|
ece0d9301f | ||
|
cc10cd88d3 | ||
|
b9f308c832 | ||
|
6816bd8bad | ||
|
0e026de5bd | ||
|
a419ad201d | ||
|
a66a4f62bd | ||
|
e721d2204b | ||
|
f293cf6e81 | ||
|
0cde1d4969 | ||
|
bd49bd6e33 | ||
|
84dc1fa151 | ||
|
5858e862d9 | ||
|
8b004a549a | ||
|
4a53e4207c | ||
|
6510de5d29 | ||
|
a6191320a1 | ||
|
a75ff0c061 | ||
|
0d45eb91db | ||
|
95edbc16bb | ||
|
15a5e3c779 | ||
|
0433432e62 | ||
|
e7ca73bbad | ||
|
8d8374b8e2 | ||
|
4dc5bbe601 | ||
|
55371f9c78 | ||
|
af63f4098f | ||
|
2b4939a875 | ||
|
d5d22844ab | ||
|
7dab00be87 | ||
|
67582d388a | ||
|
0671e7d456 | ||
|
c9e6af96d0 | ||
|
ee48a56603 | ||
|
4c03f39437 | ||
|
d8d425c963 | ||
|
ec64ac9f1d | ||
|
7ed682c186 | ||
|
9dcb579741 | ||
|
19f837aa41 | ||
|
b267491934 | ||
|
a369dddde8 | ||
|
29d87d7c48 | ||
|
4847f50093 | ||
|
7c848b1253 | ||
|
607aa46032 | ||
|
430193891f | ||
|
cbb82ed635 | ||
|
1dfb72703a | ||
|
5edf377f4b | ||
|
43a33d267a | ||
|
c4048f4c7b | ||
|
501c89ae3a | ||
|
5899497aa7 | ||
|
2c758a9981 | ||
|
66eb99e506 | ||
|
b583140077 | ||
|
f378c93dd3 | ||
|
5d29fa5e62 | ||
|
54f04c9141 | ||
|
fc0c706100 | ||
|
02ac9fa0d7 | ||
|
ca95c75df3 | ||
|
4ff86795b9 | ||
|
30eaec29d3 | ||
|
742d38c9ec | ||
|
56a4597784 | ||
|
b2a7d3584b | ||
|
b8167f89e5 | ||
|
c916472b22 | ||
|
bdfe7c5e69 | ||
|
749475799a | ||
|
daf9c807b5 | ||
|
5dfecfdee3 | ||
|
d267c03ee2 | ||
|
864e3c7a50 | ||
|
747e1a818d | ||
|
f468dbf427 | ||
|
88572e90d4 | ||
|
41fc7dd73d | ||
|
c87c588c79 | ||
|
5ab4b57411 | ||
|
3c936c6957 | ||
|
0ca903a146 | ||
|
4e91919990 | ||
|
e023a68780 | ||
|
17452cd5b6 | ||
|
c76f2c8483 | ||
|
90207f9b68 | ||
|
0ec5371b61 | ||
|
8549aeb466 | ||
|
504d3cd131 | ||
|
83ed298eba | ||
|
a90f2cb156 | ||
|
1a54bafdd5 | ||
|
3cc186f7e4 | ||
|
a2497d7564 | ||
|
c01c882081 | ||
|
af279df5c9 | ||
|
1ea7ce2589 | ||
|
476c577bc1 | ||
|
e3b91c4d71 | ||
|
1e2d7acf4a | ||
|
1def120616 | ||
|
25ddf2c651 | ||
|
e5d384e808 | ||
|
63351553d8 | ||
|
4630740ac7 | ||
|
0ff4884d3a | ||
|
2dfdedf7b0 | ||
|
e1fa5fb180 | ||
|
4e47f9eb68 | ||
|
c4c8955bc2 | ||
|
f47b808478 | ||
|
493367da5e | ||
|
4ca185cf45 | ||
|
8f4effbb8d | ||
|
a4ba7f277e | ||
|
c3f97a0cf1 | ||
|
c1b8fc1233 | ||
|
a481638c03 | ||
|
c12dfc7b4d | ||
|
34bc527709 | ||
|
ee134d0d7c | ||
|
f795ee7fd9 | ||
|
1bba75881f | ||
|
34db2d9efa | ||
|
91dd308952 | ||
|
3d97e26cde | ||
|
104c1ecbec | ||
|
88266ec4e3 | ||
|
f5be159187 | ||
|
1194d86460 | ||
|
76d6dca63f | ||
|
1b69e62e2e | ||
|
e89839359f | ||
|
177d113cd9 | ||
|
853fa87012 | ||
|
a592ca25ff | ||
|
a8c9926fa7 | ||
|
bf5587fe09 | ||
|
7c8a27e894 | ||
|
d248b11ffc | ||
|
1282e010ee | ||
|
d5d1ca948e | ||
|
a08704e8ed | ||
|
2a8c0c0c08 | ||
|
2ae0c98b4c | ||
|
c427050a92 | ||
|
43a0829f44 | ||
|
e9b8b91861 | ||
|
6f104f5056 | ||
|
e720efabdc | ||
|
45cb770e41 | ||
|
3f1cc66767 | ||
|
d1f5118bb5 | ||
|
b90f1f786e | ||
|
c6f424201b | ||
|
a7db8cf7cd | ||
|
e2ed0f5e55 | ||
|
d000e3c8a9 | ||
|
cf465a1184 | ||
|
f3119824f4 | ||
|
ef069c1689 | ||
|
68e5a9dfda | ||
|
fd1a31afb6 | ||
|
6d7d4a15d9 | ||
|
518a7d0dcc | ||
|
a4bdfe6b7d | ||
|
281269aa0d | ||
|
33521ebd31 | ||
|
18ae08de8f | ||
|
3d3c4ba02f | ||
|
89917c1582 | ||
|
90c6758562 | ||
|
5be8084473 | ||
|
8a066a4ec0 | ||
|
b98237fa44 | ||
|
c4f9388668 | ||
|
0f44b27e54 | ||
|
10d05e1870 | ||
|
921557161d | ||
|
eb092b9f20 | ||
|
28ca8a9f9f | ||
|
d7be56df7a | ||
|
ce2c163f4b | ||
|
5272462368 | ||
|
42354a6728 | ||
|
754fe3df91 | ||
|
a7a0350c1a | ||
|
a8b2ca7cfe | ||
|
e82867820b | ||
|
13305d111e | ||
|
ae37fa2bc5 | ||
|
c81db752f6 | ||
|
5d9d71dee8 | ||
|
1f558d46a4 | ||
|
36eb899c3b | ||
|
e223d752cb | ||
|
fcb503e885 | ||
|
c1055234d8 | ||
|
35ec98cf13 | ||
|
66a9138666 | ||
|
279582ff21 | ||
|
a9540ffabe | ||
|
8f02cb83ed | ||
|
5e94c8be7b | ||
|
ea6e9af5da | ||
|
1bb72262ba | ||
|
61ace7bd97 | ||
|
1a417cc36f | ||
|
00a11f4343 | ||
|
491bbacddd | ||
|
1b9daa0adb | ||
|
ccdc981756 | ||
|
b44dcc9f30 | ||
|
479ceb14e4 | ||
|
50e41d1999 | ||
|
f6e2073de0 | ||
|
271aab9746 | ||
|
8d9bf5cf17 | ||
|
ceb7ed093e | ||
|
abdbcbb741 | ||
|
51ac07cd34 | ||
|
4b29698c6c | ||
|
f93285846a | ||
|
44347db52e | ||
|
f2749ff17f | ||
|
3735342dfa | ||
|
fed6e1e82f | ||
|
58a59b624a | ||
|
1338918a89 | ||
|
831e7cdb3f | ||
|
2b8583e652 | ||
|
b0220e4200 | ||
|
0d94ef10ce |
@@ -1,7 +1,5 @@
|
||||
vendor/
|
||||
vendor/*
|
||||
!/vendor/vendor.js
|
||||
/modules/**
|
||||
!/modules/default/**
|
||||
!/modules/node_helper
|
||||
!/modules/node_helper/**
|
||||
!/modules/default/defaultmodules.js
|
@@ -2,13 +2,24 @@
|
||||
"rules": {
|
||||
"indent": ["error", "tab"],
|
||||
"quotes": ["error", "double"],
|
||||
"semi": ["error"],
|
||||
"max-len": ["error", 250],
|
||||
"curly": "error",
|
||||
"camelcase": ["error", {"properties": "never"}]
|
||||
"camelcase": ["error", {"properties": "never"}],
|
||||
"no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 1 }],
|
||||
"no-trailing-spaces": ["error", {"ignoreComments": false }],
|
||||
"no-irregular-whitespace": ["error"]
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
"node": true,
|
||||
"es6": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
"ecmaVersion": 2017,
|
||||
"ecmaFeatures": {
|
||||
"globalReturn": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
50
.github/CONTRIBUTING.md
vendored
50
.github/CONTRIBUTING.md
vendored
@@ -3,57 +3,47 @@ Contribution Policy for MagicMirror²
|
||||
|
||||
Thanks for contributing to MagicMirror²!
|
||||
|
||||
We hold our code to standard, and these standards are documented below.
|
||||
We hold our code to standard, and these standards are documented below.
|
||||
|
||||
First, before you run the linters, you will need to install them all **and** install the development dependencies:
|
||||
If you wish to run both linters, use `grunt` without any arguments.
|
||||
|
||||
```bash
|
||||
(sudo) npm install -g jscs stylelint html-validator-cli
|
||||
npm install
|
||||
```
|
||||
### JavaScript: Run ESLint
|
||||
|
||||
### JavaScript: Run JSCS
|
||||
We use [ESLint](http://eslint.org) on our JavaScript files.
|
||||
|
||||
We use [JSCS](http://jscs.info) on our JavaScript files.
|
||||
Our ESLint configuration is in our .eslintrc.json and .eslintignore files.
|
||||
|
||||
Our JSCS configuration is in our .jscsrc file.
|
||||
|
||||
To run JSCS, use `npm run jscs`.
|
||||
To run ESLint, use `grunt eslint`.
|
||||
|
||||
### CSS: Run StyleLint
|
||||
|
||||
We use [StyleLint](http://stylelint.io) to lint our CSS. Our configuration is in our .stylelintrc file.
|
||||
|
||||
To run StyleLint, use `npm run stylelint`.
|
||||
To run StyleLint, use `grunt stylelint`.
|
||||
|
||||
### HTML: Run HTML Validator
|
||||
### Submitting Issues
|
||||
|
||||
We use [NU Validator](https://validator.w3.org/nu) to validate our HTML. The configuration is in the command in the package.json file.
|
||||
Please only submit reproducible issues.
|
||||
|
||||
To run HTML Validator, use `npm run htmlvalidator`.
|
||||
|
||||
## 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 - Problems installing or configuring your MagicMirror? Check out: https://forum.magicmirror.builders/category/10/troubleshooting
|
||||
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** [ Raspberry Pi 2/3, Windows, Mac OS X, Linux, Etc ... ]:
|
||||
**Platform**: Place your platform here... give us your web browser/Electron version *and* your hardware (Raspberry Pi 2/3, Windows, Mac, Linux, System V UNIX).
|
||||
|
||||
**Node Version** [ 0.12.13 or later ]:
|
||||
**Node Version**: Make sure it's version 0.12.13 or later.
|
||||
|
||||
**MagicMirror Version** [ V1 / V2-Beta ]:
|
||||
**MagicMirror Version**: Now that the versions have split, tell us if you are using the PHP version (v1) or the newer JavaScript version (v2).
|
||||
|
||||
**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.
|
||||
**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.
|
||||
**Steps to Reproduce**: List the step by step process to reproduce the issue.
|
||||
|
||||
**Expected Results:** Describe what you expected to see.
|
||||
**Expected Results**: Describe what you expected to see.
|
||||
|
||||
**Actual Results:** Describe what you actually saw.
|
||||
**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.)
|
||||
**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 (optional)
|
||||
**Additional Notes**: Provide any other relevant notes not previously mentioned. This is optional.
|
||||
|
23
.github/ISSUE_TEMPLATE.md
vendored
23
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,21 +1,24 @@
|
||||
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 - Problems installing or configuring your MagicMirror? Check out: https://forum.magicmirror.builders/category/10/troubleshooting
|
||||
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)
|
||||
|
||||
**Platform** [ Raspberry Pi 2/3, Windows, Mac OS X, Linux, Etc ... ]:
|
||||
When submitting a new issue, please supply the following information:
|
||||
|
||||
**Node Version** [ 0.12.13 or later ]:
|
||||
**Platform**: Place your platform here... give us your web browser/Electron version *and* your hardware (Raspberry Pi 2/3, Windows, Mac, Linux, System V UNIX).
|
||||
|
||||
**MagicMirror Version** [ V1 / V2-Beta ]:
|
||||
**Node Version**: Make sure it's version 0.12.13 or later.
|
||||
|
||||
**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.
|
||||
**MagicMirror Version**: Now that the versions have split, tell us if you are using the PHP version (v1) or the newer JavaScript version (v2).
|
||||
|
||||
**Steps to Reproduce:** List the step by step process to reproduce the issue.
|
||||
**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.
|
||||
|
||||
**Expected Results:** Describe what you expected to see.
|
||||
**Steps to Reproduce**: List the step by step process to reproduce the issue.
|
||||
|
||||
**Actual Results:** Describe what you actually saw.
|
||||
**Expected Results**: Describe what you expected to see.
|
||||
|
||||
**Configuration:** What does the used config.js file look like? (Don't forget to remove any sensitive information.)
|
||||
**Actual Results**: Describe what you actually saw.
|
||||
|
||||
**Additional Notes:** Provide any other relevant notes not previously mentioned (optional)
|
||||
**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.
|
||||
|
17
.github/PULL_REQUEST_TEMPLATE.md
vendored
17
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,9 +1,14 @@
|
||||
> Please send your PR's the develop branch.
|
||||
> Don't forget to add the change to changelog.md.
|
||||
> Please send your pull requests the develop branch.
|
||||
> Don't forget to add the change to CHANGELOG.md.
|
||||
|
||||
* Does the pull request solve a **related** issue? [yes | no]
|
||||
**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!
|
||||
|
||||
|
||||
* Does the pull request solve a **related** issue?
|
||||
* If so, can you reference the issue?
|
||||
* What does the pull request accomplish? (please list)
|
||||
* What does the pull request accomplish? Use a list if needed.
|
||||
* If it includes major visual changes please add screenshots.
|
||||
|
||||
|
||||
|
19
.github/stale.yml
vendored
Normal file
19
.github/stale.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# 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
|
29
.gitignore
vendored
29
.gitignore
vendored
@@ -11,11 +11,19 @@ coverage
|
||||
.grunt
|
||||
.lock-wscript
|
||||
build/Release
|
||||
node_modules
|
||||
/node_modules/**/*
|
||||
fonts/node_modules/**/*
|
||||
vendor/node_modules/**/*
|
||||
jspm_modules
|
||||
.npm
|
||||
.node_repl_history
|
||||
|
||||
# Visual Studio Code ignoramuses.
|
||||
.vscode/
|
||||
|
||||
# IDE Code ignoramuses.
|
||||
.idea/
|
||||
|
||||
# Various Windows ignoramuses.
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
@@ -51,16 +59,23 @@ Temporary Items
|
||||
.directory
|
||||
.Trash-*
|
||||
|
||||
# Various Magic Mirror ignoramuses and anti-ignoramuses.
|
||||
|
||||
# Don't ignore the node_helper nore module.
|
||||
!/modules/node_helper
|
||||
!/modules/node_helper/**
|
||||
|
||||
# Ignore all modules except the default modules.
|
||||
/modules/**
|
||||
!/modules/default
|
||||
!/modules/default/**
|
||||
!/modules/README.md**
|
||||
|
||||
# Ignore changes to the custom css files.
|
||||
/css/custom.css
|
||||
|
||||
# Vim
|
||||
## swap
|
||||
[._]*.s[a-w][a-z]
|
||||
[._]s[a-w][a-z]
|
||||
|
||||
## diff patch
|
||||
*.orig
|
||||
*.rej
|
||||
*.bak
|
||||
|
||||
!/tests/node_modules/**/*
|
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"extends": "stylelint-config-standard",
|
||||
"font-family-name-quotes": "double-where-recommended"
|
||||
}
|
5
.stylelintrc.json
Normal file
5
.stylelintrc.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "stylelint-config-standard",
|
||||
"font-family-name-quotes": "double-where-recommended",
|
||||
"block-no-empty": false
|
||||
}
|
22
.travis.yml
22
.travis.yml
@@ -1,9 +1,21 @@
|
||||
dist: trusty
|
||||
language: node_js
|
||||
node_js:
|
||||
- "6"
|
||||
- "5.1"
|
||||
- "4"
|
||||
- "0.12"
|
||||
- "10"
|
||||
before_install:
|
||||
- npm i -g npm
|
||||
before_script:
|
||||
- yarn danger ci
|
||||
- npm install grunt-cli -g
|
||||
script: grunt
|
||||
- "export DISPLAY=:99.0"
|
||||
- "sh -e /etc/init.d/xvfb start"
|
||||
- sleep 5
|
||||
script:
|
||||
- npm run test:e2e
|
||||
- npm run test:unit
|
||||
- grunt
|
||||
after_script:
|
||||
- npm list
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
|
622
CHANGELOG.md
Normal file → Executable file
622
CHANGELOG.md
Normal file → Executable file
@@ -1,7 +1,625 @@
|
||||
# MagicMirror² Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
❤️ **Donate:** Enjoying MagicMirror²? [Please consider a donation!](https://magicmirror.builders/donate) With your help we can continue to improve the MagicMirror² core.
|
||||
|
||||
## [2.10.1] - 2020-01-10
|
||||
|
||||
### Changed
|
||||
- Updated README.md: Added links to the official documentation website and remove links to broken installer.
|
||||
|
||||
## [2.10.0] - 2020-01-01
|
||||
|
||||
ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`.
|
||||
|
||||
### Added
|
||||
- Timestamps in log output.
|
||||
- Padding in dateheader mode of the calendar module.
|
||||
- New upgrade script to help users consume regular updates installers/upgrade-script.sh.
|
||||
- New script to help setup pm2, without install installers/fixuppm2.sh.
|
||||
|
||||
### 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 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.
|
||||
- Only check for xwindows running if not on macOS.
|
||||
|
||||
### Fixed
|
||||
- Fixed issue in weatherforecast module where predicted amount of rain was not using the decimal symbol specified in config.js.
|
||||
- Module header now updates correctly, if a module need to dynamically show/hide its header based on a condition.
|
||||
- Fix handling of config.js for serverOnly mode commented out.
|
||||
- Fixed issue in calendar module where the debug script didn't work correctly with authentication
|
||||
- Fixed issue that some full day events were not correctly recognized as such
|
||||
- Display full day events lasting multiple days as happening today instead of some days ago if they are still ongoing
|
||||
|
||||
## [2.9.0] - 2019-10-01
|
||||
|
||||
ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues running Electron, make sure your [Raspbian is up to date](https://www.raspberrypi.org/documentation/raspbian/updating.md).
|
||||
|
||||
### Added
|
||||
- Spanish translation for "PRECIP".
|
||||
- Adding a Malay (Malaysian) translation for MagicMirror².
|
||||
- Add test check URLs of vendors 200 and 404 HTTP CODE.
|
||||
- Add tests for new weather module and helper to stub ajax requests.
|
||||
|
||||
### Updated
|
||||
- Updatenotification module: Display update notification for a limited (configurable) time.
|
||||
- Enabled e2e/vendor_spec.js tests.
|
||||
- The css/custom.css will be rename after the next release. We've add into `run-start.sh` a instruction by GIT to ignore with `--skip-worktree` and `rm --cached`. [#1540](https://github.com/MichMich/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 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.
|
||||
|
||||
## [2.8.0] - 2019-07-01
|
||||
|
||||
ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues running Electron, make sure your [Raspbian is up to date](https://www.raspberrypi.org/documentation/raspbian/updating.md).
|
||||
|
||||
### Added
|
||||
- Option to show event location in calendar
|
||||
- Finnish translation for "Feels" and "Weeks"
|
||||
- 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 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
|
||||
- Added suncalc.js dependency to calculate sun times (not provided in UK Met Office feed)
|
||||
- Added "tempUnits" and "windUnits" to allow, for example, temp in metric (i.e. celsius) and wind in imperial (i.e. mph). These will override "units" if specified, otherwise the "units" value will be used.
|
||||
- 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 "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
|
||||
|
||||
### Updated
|
||||
- English translation for "Feels" to "Feels like"
|
||||
- Fixed the example calender url in `config.js.sample`
|
||||
- Update `ical.js` to solve various calendar issues.
|
||||
- Update weather city list url [#1676](https://github.com/MichMich/MagicMirror/issues/1676)
|
||||
- Only update clock once per minute when seconds aren't shown
|
||||
|
||||
### 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
|
||||
- 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)
|
||||
- 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
|
||||
|
||||
### Updated installer
|
||||
- give non-pi2+ users (pi0, odroid, jetson nano, mac, windows, ...) option to continue install
|
||||
- use current username vs hardcoded 'pi' to support non-pi install
|
||||
- check for npm installed. node install doesn't do npm anymore
|
||||
- check for mac as part of PM2 install, add install option string
|
||||
- update pm2 config with current username instead of hard coded 'pi'
|
||||
- check for screen saver config, "/etc/xdg/lxsession", bypass if not setup
|
||||
|
||||
## [2.7.1] - 2019-04-02
|
||||
|
||||
Fixed `package.json` version number.
|
||||
|
||||
## [2.7.0] - 2019-04-01
|
||||
|
||||
ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues running Electron, make sure your [Raspbian is up to date](https://www.raspberrypi.org/documentation/raspbian/updating.md).
|
||||
|
||||
### Added
|
||||
- Italian translation for "Feels"
|
||||
- Basic Klingon (tlhIngan Hol) translations
|
||||
- Disabled the screensaver on raspbian with installation script
|
||||
- Added option to truncate the number of vertical lines a calendar item can span if `wrapEvents` is enabled.
|
||||
- Danish translation for "Feels" and "Weeks"
|
||||
- Added option to split multiple day events in calendar to separate numbered events
|
||||
- Slovakian translation
|
||||
- Alerts now can contain Font Awesome icons
|
||||
- Notifications display time can be set in request
|
||||
- Newsfeed: added support for `ARTICLE_INFO_REQUEST` notification
|
||||
- Add `name` config option for calendars to be sent along with event broadcasts
|
||||
|
||||
### Updated
|
||||
- Bumped the Electron dependency to v3.0.13 to support the most recent Raspbian. [#1500](https://github.com/MichMich/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 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).
|
||||
- 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: 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)
|
||||
- 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)
|
||||
- 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).
|
||||
- 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).
|
||||
- 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)
|
||||
- Added weather.gov as a new weather provider for US locations
|
||||
|
||||
## [2.6.0] - 2019-01-01
|
||||
|
||||
ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`. If you are having issues updating, make sure you are running the latest version of Node.
|
||||
|
||||
### ✨ Experimental ✨
|
||||
- New default [module weather](modules/default/weather). This module will eventually replace the current `currentweather` and `weatherforecast` modules. The new module is still pretty experimental, but it's included so you can give it a try and help us improve this module. Please give us you feedback using [this forum post](https://forum.magicmirror.builders/topic/9335/default-weather-module-refactoring).
|
||||
|
||||
A huge, huge, huge thanks to user @fewieden for all his hard work on the new `weather` module!
|
||||
|
||||
### Added
|
||||
- Possibility to add classes to the cell of symbol, title and time of the events of calendar.
|
||||
- Font-awesome 5, still has 4 for backwards compatibility.
|
||||
- Missing `showEnd` in calendar documentation
|
||||
- Screenshot for the new feed module
|
||||
- Screenshot for the compliments module
|
||||
- Screenshot for the clock module
|
||||
- Screenshot for the current weather
|
||||
- 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)
|
||||
- Documentation for the existing `scale` option in the Weather Forecast module.
|
||||
|
||||
### Fixed
|
||||
- Allow to parse recurring calendar events where the start date is before 1900
|
||||
- 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)
|
||||
|
||||
### Updated
|
||||
- The default calendar setting `showEnd` is changed to `false`.
|
||||
|
||||
### Changed
|
||||
- The Weather Forecast module by default displays the ° symbol after every numeric value to be consistent with the Current Weather module.
|
||||
|
||||
|
||||
## [2.5.0] - 2018-10-01
|
||||
|
||||
### Added
|
||||
- Romanian translation for "Feels"
|
||||
- Support multi-line compliments
|
||||
- Simplified Chinese translation for "Feels"
|
||||
- Polish translate for "Feels"
|
||||
- French translate for "Feels"
|
||||
- Translations for newsfeed module
|
||||
- Support for toggling news article in fullscreen
|
||||
- Hungarian translation for "Feels" and "Week"
|
||||
- Spanish translation for "Feels"
|
||||
- Add classes instead of inline style to the message from the module Alert
|
||||
- Support for events having a duration instead of an end
|
||||
- Support for showing end of events through config parameters showEnd and dateEndFormat
|
||||
|
||||
### Fixed
|
||||
- Fixed gzip encoded calendar loading issue #1400.
|
||||
- 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 weather city ID link in sample config
|
||||
- Fixed issue with clientonly not updating with IP address and port provided on command line.
|
||||
|
||||
### Updated
|
||||
|
||||
- Updated Simplified Chinese translation
|
||||
- Swedish translations
|
||||
- Hungarian translations for the updatenotification module
|
||||
- Updated Norsk bokmål translation
|
||||
- Updated Norsk nynorsk translation
|
||||
- Consider multi days event as full day events
|
||||
|
||||
## [2.4.1] - 2018-07-04
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix weather parsing issue #1332.
|
||||
|
||||
## [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).
|
||||
|
||||
ℹ️ **Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
|
||||
|
||||
### Added
|
||||
|
||||
- Enabled translation of feelsLike for module currentweather
|
||||
- Added support for on-going calendar events
|
||||
- Added scroll up in fullscreen newsfeed article view
|
||||
- Changed fullscreen newsfeed width from 100% to 100vw (better results)
|
||||
- Added option to calendar module that colors only the symbol instead of the whole line
|
||||
- Added option for new display format in the calendar module with date headers with times/events below.
|
||||
- Ability to fetch compliments from a remote server
|
||||
- Add regex filtering to calendar module
|
||||
- Customize classes for table
|
||||
- Added option to newsfeed module to only log error parsing a news article if enabled
|
||||
- Add update translations for Português Brasileiro
|
||||
|
||||
### Changed
|
||||
- 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)
|
||||
|
||||
### 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)
|
||||
- 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 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)
|
||||
- `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)
|
||||
|
||||
### Updated
|
||||
- Updated Italian translation
|
||||
- Updated German translation
|
||||
- Updated Dutch translation
|
||||
|
||||
## [2.3.1] - 2018-04-01
|
||||
|
||||
### Fixed
|
||||
- Downgrade electron to 1.4.15 to solve the black screen issue.[#1243](https://github.com/MichMich/MagicMirror/issues/1243)
|
||||
|
||||
## [2.3.0] - 2018-04-01
|
||||
|
||||
### Added
|
||||
|
||||
- Add new settings in compliments module: setting time intervals for morning and afternoon
|
||||
- Add system notification `MODULE_DOM_CREATED` for notifying each module when their Dom has been fully loaded.
|
||||
- Add types for module.
|
||||
- Implement Danger.js to notify contributors when CHANGELOG.md is missing in PR.
|
||||
- Allow to scroll in full page article view of default newsfeed module with gesture events from [MMM-Gestures](https://github.com/thobach/MMM-Gestures)
|
||||
- Changed 'compliments.js' - update DOM if remote compliments are loaded instead of waiting one updateInterval to show custom compliments
|
||||
- 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)
|
||||
- New currentweather module config option: `useKMPHwind`: adds an option to see wind speed in Kmph instead of just m/s or Beaufort.
|
||||
- Add dc:date to parsing in newsfeed module, which allows parsing of more rss feeds.
|
||||
|
||||
### Changed
|
||||
- Add link to GitHub repository which contains the respective Dockerfile.
|
||||
- Optimized automated unit tests cloneObject, cmpVersions
|
||||
- Update notifications use now translation templates instead of normal strings.
|
||||
- Yarn can be used now as an installation tool
|
||||
- Changed Electron dependency to v1.7.13.
|
||||
|
||||
### Fixed
|
||||
- News article in fullscreen (iframe) is now shown in front of modules.
|
||||
- Forecast respects maxNumberOfDays regardless of endpoint.
|
||||
- Fix exception on translation of objects.
|
||||
|
||||
## [2.2.2] - 2018-01-02
|
||||
|
||||
### Added
|
||||
|
||||
- Add missing `package-lock.json`.
|
||||
|
||||
### Changed
|
||||
|
||||
- Changed Electron dependency to v1.7.10.
|
||||
|
||||
## [2.2.1] - 2018-01-01
|
||||
|
||||
### Fixed
|
||||
- Fixed linting errors.
|
||||
|
||||
## [2.2.0] - 2018-01-01
|
||||
|
||||
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
|
||||
|
||||
### Changed
|
||||
- Calender week is now handled with a variable translation in order to move number language specific.
|
||||
- Reverted the Electron dependency back to 1.4.15 since newer version don't seem to work on the Raspberry Pi very well.
|
||||
|
||||
### Added
|
||||
- Add option to use [Nunjucks](https://mozilla.github.io/nunjucks/) templates in modules. (See `helloworld` module as an example.)
|
||||
- Add Bulgarian translations for MagicMirror² and Alert module.
|
||||
- Add graceful shutdown of modules by calling `stop` function of each `node_helper` on SIGINT before exiting.
|
||||
- Link update subtext to Github diff of current version versus tracking branch.
|
||||
- Add Catalan translation.
|
||||
- Add ability to filter out newsfeed items based on prohibited words found in title (resolves #1071)
|
||||
- Add options to truncate description support of a feed in newsfeed module
|
||||
- Add reloadInterval option for particular feed in newsfeed module
|
||||
- Add no-cache entries of HTTP headers in newsfeed module (fetcher)
|
||||
- Add Czech translation.
|
||||
- Add option for decimal symbols other than the decimal point for temperature values in both default weather modules: WeatherForecast and CurrentWeather.
|
||||
|
||||
### Fixed
|
||||
- Fixed issue with calendar module showing more than `maximumEntries` allows
|
||||
- WeatherForecast and CurrentWeather are now using HTTPS instead of HTTP
|
||||
- Correcting translation for Indonesian language
|
||||
- Fix issue where calendar icons wouldn't align correctly
|
||||
|
||||
## [2.1.3] - 2017-10-01
|
||||
|
||||
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
|
||||
|
||||
### Changed
|
||||
- Remove Roboto fonts files inside `fonts` and these are installed by npm install command.
|
||||
|
||||
### Added
|
||||
- Add `clientonly` script to start only the electron client for a remote server.
|
||||
- Add symbol and color properties of event when `CALENDAR_EVENTS` notification is broadcasted from `default/calendar` module.
|
||||
- Add `.vscode/` folder to `.gitignore` to keep custom Visual Studio Code config out of git.
|
||||
- Add unit test the capitalizeFirstLetter function of newsfeed module.
|
||||
- Add new unit tests for function `shorten` in calendar module.
|
||||
- Add new unit tests for function `getLocaleSpecification` in calendar module.
|
||||
- Add unit test for js/class.js.
|
||||
- Add unit tests for function `roundValue` in currentweather module.
|
||||
- Add test e2e showWeek feature in spanish language.
|
||||
- Add warning Log when is used old authentication method in the calendar module.
|
||||
- Add test e2e for helloworld module with default config text.
|
||||
- Add ability for `currentweather` module to display indoor humidity via INDOOR_HUMIDITY notification.
|
||||
- Add Welsh (Cymraeg) translation.
|
||||
- Add Slack badge to Readme.
|
||||
|
||||
### Updated
|
||||
- Changed 'default.js' - listen on all attached interfaces by default.
|
||||
- Add execution of `npm list` after the test are ran in Travis CI.
|
||||
- Change hooks for the vendors e2e tests.
|
||||
- Add log when clientonly failed on starting.
|
||||
- Add warning color when are using full ip whitelist.
|
||||
- Set version of the `express-ipfilter` on 0.3.1.
|
||||
|
||||
### 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 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.
|
||||
- Workaround for the WeatherForecast API limitation.
|
||||
|
||||
## [2.1.2] - 2017-07-01
|
||||
|
||||
### 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))
|
||||
- Fix the dockerfile to have it running from the first time.
|
||||
|
||||
### Added
|
||||
- Add in option to wrap long calendar events to multiple lines using `wrapEvents` configuration option.
|
||||
- Add test e2e `show title newsfeed` for newsfeed module.
|
||||
- Add task to check configuration file.
|
||||
- Add test check URLs of vendors.
|
||||
- Add test of match current week number on clock module with showWeek configuration.
|
||||
- Add test default modules present modules/default/defaultmodules.js.
|
||||
- Add unit test calendar_modules function capFirst.
|
||||
- Add test for check if exists the directories present in defaults modules.
|
||||
- Add support for showing wind direction as an arrow instead of abbreviation in currentWeather module.
|
||||
- Add support for writing translation functions to support flexible word order
|
||||
- Add test for check if exits the directories present in defaults modules.
|
||||
- Add calendar option to set a separate date format for full day events.
|
||||
- Add ability for `currentweather` module to display indoor temperature via INDOOR_TEMPERATURE notification
|
||||
- Add ability to change the path of the `custom.css`.
|
||||
- Add translation Dutch to Alert module.
|
||||
- Added Romanian translation.
|
||||
|
||||
### Updated
|
||||
- Added missing keys to Polish translation.
|
||||
- Added missing key to German translation.
|
||||
- Added better translation with flexible word order to Finnish translation.
|
||||
|
||||
### 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).
|
||||
- Fix double message about port when server is starting
|
||||
- Corrected Swedish translations for TODAY/TOMORROW/DAYAFTERTOMORROW.
|
||||
- Removed unused import from js/electron.js
|
||||
- Made calendar.js respect config.timeFormat irrespective of locale setting.
|
||||
- Fixed alignment of analog clock when a large calendar is displayed in the same side bar.
|
||||
|
||||
## [2.1.1] - 2017-04-01
|
||||
|
||||
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
|
||||
|
||||
### Changed
|
||||
- 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))
|
||||
- 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.
|
||||
- Added `DAYAFTERTOMORROW`, `UPDATE_NOTIFICATION` and `UPDATE_NOTIFICATION_MODULE` to Finnish translations.
|
||||
- Run `npm test` on Travis automatically.
|
||||
- Show the splash screen image even when is reboot or halted.
|
||||
- Added some missing translation strings in the sv.json file.
|
||||
- Run task jsonlint to check translation files.
|
||||
- Restructured Test Suite.
|
||||
|
||||
### Added
|
||||
- Added Docker support (Pull Request [#673](https://github.com/MichMich/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)
|
||||
- Add use pm2 for manager process into Installer RaspberryPi script.
|
||||
- Russian Translation.
|
||||
- Afrikaans Translation.
|
||||
- Add postinstall script to notify user that MagicMirror installed successfully despite warnings from NPM.
|
||||
- Init tests using mocha.
|
||||
- Option to use RegExp in Calendar's titleReplace.
|
||||
- Hungarian Translation.
|
||||
- Icelandic Translation.
|
||||
- Add use a script to prevent when is run by SSH session set DISPLAY environment.
|
||||
- Enable ability to set configuration file by the environment variable called MM_CONFIG_FILE.
|
||||
- Option to give each calendar a different color.
|
||||
- Option for colored min-temp and max-temp.
|
||||
- Add test e2e helloworld.
|
||||
- Add test e2e environment.
|
||||
- Add `chai-as-promised` npm module to devDependencies.
|
||||
- Basic set of tests for clock module.
|
||||
- Run e2e test in Travis.
|
||||
- Estonian Translation.
|
||||
- Add test for compliments module for parts of day.
|
||||
- Korean Translation.
|
||||
- Added console warning on startup when deprecated config options are used.
|
||||
- Add option to display temperature unit label to the current weather module.
|
||||
- Added ability to disable wrapping of news items.
|
||||
- Added in the ability to hide events in the calendar module based on simple string filters.
|
||||
- Updated Norwegian translation.
|
||||
- Added hideLoading option for News Feed module.
|
||||
- Added configurable dateFormat to clock module.
|
||||
- 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 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
|
||||
- Added test for MM_PORT environment variable.
|
||||
- Added a configurable Week section to the clock module.
|
||||
|
||||
### Fixed
|
||||
- Update .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))
|
||||
- If units is 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.
|
||||
- Fix newsfeed module bug (removeStartTags)
|
||||
- Fix when is set MM_PORT environment variable.
|
||||
- Fixed missing animation on `this.show(speed)` when module is alone in a region.
|
||||
|
||||
## [2.1.0] - 2016-12-31
|
||||
|
||||
**Note:** This update uses new dependencies. Please update using the following command: `git pull && npm install`
|
||||
|
||||
### Added
|
||||
- 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)).
|
||||
- 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 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.
|
||||
- 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 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
|
||||
- Added option `disabled` for modules.
|
||||
- Added option `address` to set bind address.
|
||||
- Added option `onlyTemp` for currentweather module to show show only current temperature and weather icon.
|
||||
- Added option `remoteFile` to compliments module to load compliment array from filesystem.
|
||||
- Added option `zoom` to scale the whole mirror display with a given factor.
|
||||
- Added option `roundTemp` for currentweather and weatherforecast modules to display temperatures rounded to nearest integer.
|
||||
- Added abilty set the classes option to compliments module for style and text size of compliments.
|
||||
- Added ability to configure electronOptions
|
||||
- Calendar module: option to hide private events
|
||||
- Add root_path for global vars
|
||||
|
||||
### Updated
|
||||
- Modified translations for Frysk.
|
||||
- Modified core English translations.
|
||||
- Updated package.json as a result of Snyk security update.
|
||||
- Improve object instantiation to prevent reference errors.
|
||||
- Improve logger. `Log.log()` now accepts multiple arguments.
|
||||
- Remove extensive logging in newsfeed node helper.
|
||||
- Calendar times are now uniformly capitalized.
|
||||
- Modules are now secure, and Helmet is now used to prevent abuse of the Mirror's API.
|
||||
|
||||
### Fixed
|
||||
- Solve an issue where module margins would appear when the first module of a section was hidden.
|
||||
- Solved visual display errors on chrome, if all modules in one of the right sections are hidden.
|
||||
- Global and Module default config values are no longer modified when setting config values.
|
||||
- Hide a region if all modules in a region are hidden. Prevention unwanted margins.
|
||||
- Replaced `electron-prebuilt` package with `electron` in order to fix issues that would happen after 2017.
|
||||
- Documentation of alert module
|
||||
|
||||
## [2.0.5] - 2016-09-20
|
||||
|
||||
### Added
|
||||
- Added ability to remove tags from the beginning or end of newsfeed items in 'newsfeed.js'.
|
||||
- Added ability to define "the day after tomorrow" for calendar events (Definition for German and Dutch already included).
|
||||
- Added CII Badge (we are compliant with the CII Best Practices)
|
||||
- Add support for doing http basic auth when loading calendars
|
||||
- Add the ability to turn off and on the date display in the Clock Module
|
||||
|
||||
### Fixed
|
||||
- Fix typo in installer.
|
||||
- Add message to unsupported Pi error to mention that Pi Zeros must use server only mode, as ARMv6 is unsupported. Closes #374.
|
||||
- Fix API url for weather API.
|
||||
|
||||
### Updated
|
||||
- Force fullscreen when kioskmode is active.
|
||||
- Update the .github templates and information with more modern information.
|
||||
- Update the Gruntfile with a more functional StyleLint implementation.
|
||||
|
||||
## [2.0.4] - 2016-08-07
|
||||
|
||||
### Added
|
||||
- Brazilian Portuguese Translation.
|
||||
- Option to enable Kiosk mode.
|
||||
- Added ability to start the app with Dev Tools.
|
||||
- Added ability to turn off the date display in `clock.js` when in analog mode.
|
||||
- Greek Translation
|
||||
|
||||
### 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))
|
||||
- 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))
|
||||
|
||||
### Updated
|
||||
- Updated package.json to fix possible vulnerabilities. (Using Snyk)
|
||||
- Updated weathericons
|
||||
- Updated default weatherforecast to work with the new icons.
|
||||
- More detailed error message in case config file couldn't be loaded.
|
||||
|
||||
## [2.0.3] - 2016-07-12
|
||||
### Added
|
||||
- Add max newsitems parameter to the newsfeed module.
|
||||
- Translations for Simplified Chinese, Traditional Chinese and Japanese.
|
||||
- Polish Translation
|
||||
- Add an analog clock in addition to the digital one.
|
||||
|
||||
### 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))
|
||||
|
||||
### Changed
|
||||
- Added default string to calendar titleReplace.
|
||||
|
||||
## [2.0.2] - 2016-06-05
|
||||
### Added
|
||||
- Norwegian Translations (nb and nn)
|
||||
@@ -10,7 +628,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
### Fixed
|
||||
- Added reference to Italian Translation.
|
||||
- Added the missing NE translation to all languages. [#334](https://github.com/MichMich/MagicMirror/issues/344)
|
||||
- Added the missing NE translation to all languages. [#344](https://github.com/MichMich/MagicMirror/issues/344)
|
||||
- Added proper User-Agent string to calendar call.
|
||||
|
||||
### Changed
|
||||
@@ -34,4 +652,4 @@ It includes (but is not limited to) the following features:
|
||||
|
||||
## [1.0.0] - 2014-02-16
|
||||
### Initial release of MagicMirror.
|
||||
This was part of the blogpost: http://michaelteeuw.nl/post/83916869600/magic-mirror-part-vi-production-of-the
|
||||
This was part of the blogpost: [http://michaelteeuw.nl/post/83916869600/magic-mirror-part-vi-production-of-the](http://michaelteeuw.nl/post/83916869600/magic-mirror-part-vi-production-of-the)
|
||||
|
101
Gruntfile.js
101
Gruntfile.js
@@ -4,25 +4,102 @@ module.exports = function(grunt) {
|
||||
pkg: grunt.file.readJSON("package.json"),
|
||||
eslint: {
|
||||
options: {
|
||||
fix: "true",
|
||||
configFile: ".eslintrc.json"
|
||||
},
|
||||
target: ["js/*.js", "modules/default/*.js", "serveronly/*.js", "*.js"]
|
||||
target: [
|
||||
"js/*.js",
|
||||
"modules/default/*.js",
|
||||
"modules/default/*/*.js",
|
||||
"serveronly/*.js",
|
||||
"clientonly/*.js",
|
||||
"*.js",
|
||||
"tests/**/*.js",
|
||||
"!modules/default/alert/notificationFx.js",
|
||||
"!modules/default/alert/modernizr.custom.js",
|
||||
"!modules/default/alert/classie.js",
|
||||
"config/*",
|
||||
"translations/translations.js",
|
||||
"vendor/vendor.js",
|
||||
"modules/node_modules/node_helper/index.js"
|
||||
]
|
||||
},
|
||||
postcss: {
|
||||
lint: {
|
||||
stylelint: {
|
||||
simple: {
|
||||
options: {
|
||||
processors: [
|
||||
require("stylelint")({"extends": "stylelint-config-standard", "font-family-name-quotes": "double-where-recommended"}),
|
||||
require("postcss-reporter")({ clearMessages: true })
|
||||
]
|
||||
configFile: ".stylelintrc.json"
|
||||
},
|
||||
dist: {
|
||||
src: "**/**/**/**/**/**/**/**.css"
|
||||
src: [
|
||||
"css/main.css",
|
||||
"modules/default/calendar/calendar.css",
|
||||
"modules/default/clock/clock_styles.css",
|
||||
"modules/default/currentweather/currentweather.css",
|
||||
"modules/default/weatherforcast/weatherforcast.css"
|
||||
]
|
||||
}
|
||||
},
|
||||
jsonlint: {
|
||||
main: {
|
||||
src: [
|
||||
"package.json",
|
||||
".eslintrc.json",
|
||||
".stylelintrc.json",
|
||||
"installers/pm2_MagicMirror.json",
|
||||
"translations/*.json",
|
||||
"modules/default/*/translations/*.json",
|
||||
"vendor/package.json"
|
||||
],
|
||||
options: {
|
||||
reporter: "jshint"
|
||||
}
|
||||
}
|
||||
},
|
||||
markdownlint: {
|
||||
all: {
|
||||
options: {
|
||||
config: {
|
||||
"default": true,
|
||||
"line-length": false,
|
||||
"blanks-around-headers": false,
|
||||
"no-duplicate-header": false,
|
||||
"no-inline-html": false,
|
||||
"MD010": false,
|
||||
"MD001": false,
|
||||
"MD031": false,
|
||||
"MD040": false,
|
||||
"MD002": false,
|
||||
"MD029": false,
|
||||
"MD041": false,
|
||||
"MD032": false,
|
||||
"MD036": false,
|
||||
"MD037": false,
|
||||
"MD009": false,
|
||||
"MD018": false,
|
||||
"MD012": false,
|
||||
"MD026": false,
|
||||
"MD038": false
|
||||
}
|
||||
},
|
||||
src: [
|
||||
"README.md",
|
||||
"CHANGELOG.md",
|
||||
"LICENSE.md",
|
||||
"modules/README.md",
|
||||
"modules/default/**/*.md",
|
||||
"!modules/default/calendar/vendor/ical.js/readme.md"
|
||||
]
|
||||
}
|
||||
},
|
||||
yamllint: {
|
||||
all: [
|
||||
".travis.yml"
|
||||
]
|
||||
}
|
||||
});
|
||||
grunt.loadNpmTasks("grunt-eslint");
|
||||
grunt.loadNpmTasks("grunt-postcss");
|
||||
grunt.registerTask("default", ["eslint", "postcss:lint"]);
|
||||
};
|
||||
grunt.loadNpmTasks("grunt-stylelint");
|
||||
grunt.loadNpmTasks("grunt-jsonlint");
|
||||
grunt.loadNpmTasks("grunt-yamllint");
|
||||
grunt.loadNpmTasks("grunt-markdownlint");
|
||||
grunt.registerTask("default", ["eslint", "stylelint", "jsonlint", "markdownlint", "yamllint"]);
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
The MIT License (MIT)
|
||||
=====================
|
||||
|
||||
Copyright © 2016 Michael Teeuw
|
||||
Copyright © 2016-2019 Michael Teeuw
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
|
133
README.md
133
README.md
@@ -3,127 +3,42 @@
|
||||
<p align="center">
|
||||
<a href="https://david-dm.org/MichMich/MagicMirror"><img src="https://david-dm.org/MichMich/MagicMirror.svg" alt="Dependency Status"></a>
|
||||
<a href="https://david-dm.org/MichMich/MagicMirror#info=devDependencies"><img src="https://david-dm.org/MichMich/MagicMirror/dev-status.svg" alt="devDependency Status"></a>
|
||||
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-v5.10.1-brightgreen.svg" alt="Node Version"></a>
|
||||
<a href="https://bestpractices.coreinfrastructure.org/projects/347"><img src="https://bestpractices.coreinfrastructure.org/projects/347/badge"></a>
|
||||
<a href="http://choosealicense.com/licenses/mit"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License"></a>
|
||||
<a href="https://travis-ci.org/MichMich/MagicMirror"><img src="https://travis-ci.org/MichMich/MagicMirror.svg" alt="Travis"></a>
|
||||
<a href="https://travis-ci.com/MichMich/MagicMirror"><img src="https://travis-ci.com/MichMich/MagicMirror.svg" alt="Travis"></a>
|
||||
<a href="https://snyk.io/test/github/MichMich/MagicMirror"><img src="https://snyk.io/test/github/MichMich/MagicMirror/badge.svg" alt="Known Vulnerabilities" data-canonical-src="https://snyk.io/test/github/MichMich/MagicMirror" style="max-width:100%;"></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](http://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](http://michaelteeuw.nl/tagged/magicmirror) with the incredible help of a [growing community of contributors](https://github.com/MichMich/MagicMirror/graphs/contributors).
|
||||
|
||||
MagicMirror² focuses on a modular plugin system and uses [Electron](http://electron.atom.io/) as an application wrapper. So no more web server or browser installs necessary!
|
||||
|
||||
## Table Of Contents
|
||||
## Documentation
|
||||
For the full documentation including **[installation instructions](https://docs.magicmirror.builders/getting-started/installation.html)**, please visit our dedicated documentation website: [https://docs.magicmirror.builders](https://docs.magicmirror.builders).
|
||||
|
||||
- [Usage](#usage)
|
||||
- [Configuration](#configuration)
|
||||
- [Modules](#modules)
|
||||
- [Known Issues](#known-issues)
|
||||
- [community](#community)
|
||||
- [Contributing Guidelines](#contributing-guidelines)
|
||||
|
||||
## Usage
|
||||
|
||||
#### Raspberry Pi Support
|
||||
Electron, the app wrapper around MagicMirror², only supports the Raspberry Pi 2 & 3. The Raspberry Pi 1 is currently **not** supported. If you want to run this on a Raspberry Pi 1, use the [server only](#server-only) feature and setup a fullscreen browser yourself.
|
||||
|
||||
#### Automatic Installer (Raspberry Pi Only!)
|
||||
|
||||
Execute the following command on your Raspberry Pi to install MagicMirror²:
|
||||
````
|
||||
curl -sL https://raw.githubusercontent.com/MichMich/MagicMirror/master/installers/raspberry.sh | bash
|
||||
````
|
||||
|
||||
#### Manual Installation
|
||||
|
||||
1. Download and install the latest Node.js version.
|
||||
2. Clone the repository and check out the beta branch: `git clone https://github.com/MichMich/MagicMirror`
|
||||
3. Enter the repository: `cd ~/MagicMirror`
|
||||
4. Install and run the app: `npm install && npm start`
|
||||
|
||||
**Important:** `npm start` does **not** work via SSH, use `DISPLAY=:0 nohup npm start &` instead. This starts the mirror on the remote display.
|
||||
|
||||
#### Server Only
|
||||
|
||||
In some cases, you want to start the application without an actual app window. In this case, execute the following command from the MagicMirror folder: `node serveronly`. This will start the server, after which you can open the application in your browser of choice.
|
||||
|
||||
#### Raspberry Configuration & Auto Start.
|
||||
|
||||
The following wiki links are helpful in the configuration of your MagicMirror² operating system:
|
||||
- [Configuring the Raspberry Pi](https://github.com/MichMich/MagicMirror/wiki/Configuring-the-Raspberry-Pi)
|
||||
- [Auto Starting MagicMirror](https://github.com/MichMich/MagicMirror/wiki/Auto-Starting-MagicMirror)
|
||||
|
||||
#### Updating you MagicMirror²
|
||||
|
||||
If you want to update your MagicMirror² to the latest version, use your terminal to go to your Magic Mirror folder and type the following command:
|
||||
|
||||
````
|
||||
git pull
|
||||
````
|
||||
|
||||
If you changed nothing more than the config or the modules, this should work without any problems.
|
||||
Type `git status` to see your changes, if there are any, you can reset them with `git reset --hard`. After that, git pull should be possible.
|
||||
|
||||
## Configuration
|
||||
|
||||
1. Duplicate `config/config.js.sample` to `config/config.js`.
|
||||
2. Modify your required settings.
|
||||
|
||||
The following properties can be configured:
|
||||
|
||||
|
||||
| **Option** | **Description** |
|
||||
| --- | --- |
|
||||
| `port` | The port on which the MagicMirror² server will run on. The default value is `8080`. |
|
||||
| `language` | The language of the interface. (Note: Not all elements will be localized.) Possible values are `en`, `nl`, `ru`, `fr`, etc., but the default value is `en`. |
|
||||
| `timeFormat` | The form of time notation that will be used. Possible values are `12` or `24`. The default is `24`. |
|
||||
| `units` | The units that will be used in the default weather modules. Possible values are `metric` or `imperial`. The default is `metric`. |
|
||||
| `modules` | An array of active modules. **The array must contain objects. See the next table below for more information.** |
|
||||
|
||||
Module configuration:
|
||||
|
||||
| **Option** | **Description** |
|
||||
| --- | --- |
|
||||
| `module` | The name of the module. This can also contain the subfolder. Valid examples include `clock`, `default/calendar` and `custommodules/mymodule`. |
|
||||
| `position` | The location of the module in which the module will be loaded. Possible values are `top_ bar`, `top_left`, `top_center`, `top_right`, `upper_third`, `middle_center`, `lower_third`, `bottom_left`, `bottom_center`, `bottom_right`, `bottom_bar`, `fullscreen_above`, and `fullscreen_below`. This field is optional but most modules require this field to set. Check the documentation of the module for more information. Multiple modules with the same position will be ordered based on the order in the configuration file. |
|
||||
| `classes` | Additional classes which are passed to the module. The field is optional. |
|
||||
| `header` | To display a header text above the module, add the header property. This field is optional. |
|
||||
| `config` | An object with the module configuration properties. Check the documentation of the module for more information. This field is optional, unless the module requires extra configuration. |
|
||||
|
||||
## Modules
|
||||
|
||||
The following modules are installed by default.
|
||||
|
||||
- [**Clock**](modules/default/clock)
|
||||
- [**Calendar**](modules/default/calendar)
|
||||
- [**Current Weather**](modules/default/currentweather)
|
||||
- [**Weather Forecast**](modules/default/weatherforecast)
|
||||
- [**News Feed**](modules/default/newsfeed)
|
||||
- [**Compliments**](modules/default/compliments)
|
||||
- [**Hello World**](modules/default/helloworld)
|
||||
- [**Alert**](modules/default/alert)
|
||||
|
||||
For more available modules, check out out the wiki page: [MagicMirror² Modules](https://github.com/MichMich/MagicMirror/wiki/MagicMirror²-Modules). If you want to build your own modules, check out the [MagicMirror² Module Development Documentation](modules) and don't forget to add it to the wiki and the [forum](https://forum.magicmirror.builders/category/7/showcase)!
|
||||
|
||||
## Known issues
|
||||
|
||||
- Electron seems to have some issues on certain Raspberry Pi 2's. See [#145](https://github.com/MichMich/MagicMirror/issues/145).
|
||||
- MagicMirror² (Electron) sometimes quits without an error after an extended period of use. See [#150](https://github.com/MichMich/MagicMirror/issues/150).
|
||||
|
||||
## Community
|
||||
|
||||
The community around the MagicMirror² is constantly growing. We even have a [forum](https://forum.magicmirror.builders) now where you can share your ideas, ask questions, help others and get inspired by other builders. We would love to see you there!
|
||||
## Links
|
||||
- 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)
|
||||
- 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)
|
||||
|
||||
## Contributing Guidelines
|
||||
|
||||
Contributions of all kinds are welcome, not only in the form of code but also with regards bug reports and documentation.
|
||||
Contributions of all kinds are welcome, not only in the form of code but also with regards bug reports and documentation. For the full contribution guidelines, check out: [https://docs.magicmirror.builders/getting-started/contributing.html](https://docs.magicmirror.builders/getting-started/contributing.html)
|
||||
|
||||
Please keep the following in mind:
|
||||
|
||||
- **Bug Reports**: Make sure you're running the latest version. If the issue(s) still persist: please open a clearly documented issue with a clear title.
|
||||
- **Minor Bug Fixes**: Please send a pull request with a clear explanation of the issue or a link to the issue it solves.
|
||||
- **Major Bug Fixes**: please discuss your approach in an GitHub issue before you start to alter a big part of the code.
|
||||
- **New Features**: please please discuss in a GitHub issue before you start to alter a big part of the code. Without discussion upfront, the pull request will not be accepted / merged.
|
||||
## Enjoying MagicMirror? Consider a donation!
|
||||
|
||||
Thanks for your help in making MagicMirror² better!
|
||||
MagicMirror² is opensource 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.
|
||||
|
||||
To donate, please follow [this](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=G5D8E9MR5DTD2&source=url) link.
|
||||
|
||||
<p align="center">
|
||||
<br>
|
||||
<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>
|
||||
|
104
clientonly/index.js
Normal file
104
clientonly/index.js
Normal file
@@ -0,0 +1,104 @@
|
||||
/* jshint esversion: 6 */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Use separate scope to prevent global scope pollution
|
||||
(function () {
|
||||
var config = {};
|
||||
|
||||
// Helper function to get server address/hostname from either the commandline or env
|
||||
function getServerAddress() {
|
||||
// Helper function to get command line parameters
|
||||
// Assumes that a cmdline parameter is defined with `--key [value]`
|
||||
function getCommandLineParameter(key, defaultValue = undefined) {
|
||||
var index = process.argv.indexOf(`--${key}`);
|
||||
var value = index > -1 ? process.argv[index + 1] : undefined;
|
||||
return value !== undefined ? String(value) : defaultValue;
|
||||
}
|
||||
|
||||
// Prefer command line arguments over environment variables
|
||||
["address", "port"].forEach((key) => {
|
||||
config[key] = getCommandLineParameter(key, process.env[key.toUpperCase()]);
|
||||
});
|
||||
}
|
||||
|
||||
function getServerConfig(url) {
|
||||
// Return new pending promise
|
||||
return new Promise((resolve, reject) => {
|
||||
// Select http or https module, depending on reqested url
|
||||
const lib = url.startsWith("https") ? require("https") : require("http");
|
||||
const request = lib.get(url, (response) => {
|
||||
var configData = "";
|
||||
|
||||
// Gather incoming data
|
||||
response.on("data", function(chunk) {
|
||||
configData += chunk;
|
||||
});
|
||||
// Resolve promise at the end of the HTTP/HTTPS stream
|
||||
response.on("end", function() {
|
||||
resolve(JSON.parse(configData));
|
||||
});
|
||||
});
|
||||
|
||||
request.on("error", function(error) {
|
||||
reject(new Error(`Unable to read config from server (${url} (${error.message}`));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function fail(message, code = 1) {
|
||||
if (message !== undefined && typeof message === "string") {
|
||||
console.log(message);
|
||||
} else {
|
||||
console.log("Usage: 'node clientonly --address 192.168.1.10 --port 8080'");
|
||||
}
|
||||
process.exit(code);
|
||||
}
|
||||
|
||||
getServerAddress();
|
||||
|
||||
(config.address && config.port) || fail();
|
||||
|
||||
// Only start the client if a non-local server was provided
|
||||
if (["localhost", "127.0.0.1", "::1", "::ffff:127.0.0.1", undefined].indexOf(config.address) === -1) {
|
||||
getServerConfig(`http://${config.address}:${config.port}/config/`)
|
||||
.then(function (configReturn) {
|
||||
// Pass along the server config via an environment variable
|
||||
var env = Object.create(process.env);
|
||||
var options = { env: env };
|
||||
configReturn.address = config.address;
|
||||
configReturn.port = config.port;
|
||||
env.config = JSON.stringify(configReturn);
|
||||
|
||||
// Spawn electron application
|
||||
const electron = require("electron");
|
||||
const child = require("child_process").spawn(electron, ["js/electron.js"], options);
|
||||
|
||||
// Pipe all child process output to current stdout
|
||||
child.stdout.on("data", function (buf) {
|
||||
process.stdout.write(`Client: ${buf}`);
|
||||
});
|
||||
|
||||
// Pipe all child process errors to current stderr
|
||||
child.stderr.on("data", function (buf) {
|
||||
process.stderr.write(`Client: ${buf}`);
|
||||
});
|
||||
|
||||
child.on("error", function (err) {
|
||||
process.stdout.write(`Client: ${err}`);
|
||||
});
|
||||
|
||||
child.on("close", (code) => {
|
||||
if (code !== 0) {
|
||||
console.log(`There something wrong. The clientonly is not running code ${code}`);
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
.catch(function (reason) {
|
||||
fail(`Unable to connect to server: (${reason})`);
|
||||
});
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}());
|
@@ -2,62 +2,84 @@
|
||||
*
|
||||
* By Michael Teeuw http://michaelteeuw.nl
|
||||
* MIT Licensed.
|
||||
*
|
||||
* For more information how you can configurate this file
|
||||
* See https://github.com/MichMich/MagicMirror#configuration
|
||||
*
|
||||
*/
|
||||
|
||||
var config = {
|
||||
address: "localhost", // Address to listen on, can be:
|
||||
// - "localhost", "127.0.0.1", "::1" to listen on loopback interface
|
||||
// - another specific IPv4/6 to listen on a specific interface
|
||||
// - "", "0.0.0.0", "::" to listen on any interface
|
||||
// Default, when address config is left out, is "localhost"
|
||||
port: 8080,
|
||||
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"], // Set [] to allow all IP addresses
|
||||
// or add a specific IPv4 of 192.168.1.5 :
|
||||
// ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.1.5"],
|
||||
// or IPv4 range of 192.168.3.0 --> 192.168.3.15 use CIDR format :
|
||||
// ["127.0.0.1", "::ffff:127.0.0.1", "::1", "::ffff:192.168.3.0/28"],
|
||||
|
||||
language: 'en',
|
||||
language: "en",
|
||||
timeFormat: 24,
|
||||
units: 'metric',
|
||||
|
||||
units: "metric",
|
||||
// serverOnly: true/false/"local" ,
|
||||
// local for armv6l processors, default
|
||||
// starts serveronly and then starts chrome browser
|
||||
// false, default for all NON-armv6l devices
|
||||
// true, force serveronly mode, because you want to.. no UI on this device
|
||||
|
||||
modules: [
|
||||
{
|
||||
module: 'alert',
|
||||
module: "alert",
|
||||
},
|
||||
{
|
||||
module: 'clock',
|
||||
position: 'top_left'
|
||||
module: "updatenotification",
|
||||
position: "top_bar"
|
||||
},
|
||||
{
|
||||
module: 'calendar',
|
||||
header: 'US Holidays',
|
||||
position: 'top_left',
|
||||
module: "clock",
|
||||
position: "top_left"
|
||||
},
|
||||
{
|
||||
module: "calendar",
|
||||
header: "US Holidays",
|
||||
position: "top_left",
|
||||
config: {
|
||||
calendars: [
|
||||
{
|
||||
symbol: 'calendar-check-o ',
|
||||
url: 'webcal://www.calendarlabs.com/templates/ical/US-Holidays.ics'
|
||||
}
|
||||
symbol: "calendar-check",
|
||||
url: "webcal://www.calendarlabs.com/ical-calendar/ics/76/US_Holidays.ics" }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
module: 'compliments',
|
||||
position: 'lower_third'
|
||||
module: "compliments",
|
||||
position: "lower_third"
|
||||
},
|
||||
{
|
||||
module: 'currentweather',
|
||||
position: 'top_right',
|
||||
module: "currentweather",
|
||||
position: "top_right",
|
||||
config: {
|
||||
location: 'New York',
|
||||
locationID: '', //ID from bulk.openweather.org/sample/
|
||||
appid: 'YOUR_OPENWEATHER_API_KEY'
|
||||
location: "New York",
|
||||
locationID: "", //ID from http://bulk.openweathermap.org/sample/city.list.json.gz; unzip the gz file and find your city
|
||||
appid: "YOUR_OPENWEATHER_API_KEY"
|
||||
}
|
||||
},
|
||||
{
|
||||
module: 'weatherforecast',
|
||||
position: 'top_right',
|
||||
header: 'Weather Forecast',
|
||||
module: "weatherforecast",
|
||||
position: "top_right",
|
||||
header: "Weather Forecast",
|
||||
config: {
|
||||
location: 'New York',
|
||||
locationID: '5128581', //ID from bulk.openweather.org/sample/
|
||||
appid: 'YOUR_OPENWEATHER_API_KEY'
|
||||
location: "New York",
|
||||
locationID: "5128581", //ID from http://bulk.openweathermap.org/sample/city.list.json.gz; unzip the gz file and find your city
|
||||
appid: "YOUR_OPENWEATHER_API_KEY"
|
||||
}
|
||||
},
|
||||
{
|
||||
module: 'newsfeed',
|
||||
position: 'bottom_bar',
|
||||
module: "newsfeed",
|
||||
position: "bottom_bar",
|
||||
config: {
|
||||
feeds: [
|
||||
{
|
||||
@@ -66,7 +88,9 @@ var config = {
|
||||
}
|
||||
],
|
||||
showSourceTitle: true,
|
||||
showPublishDate: true
|
||||
showPublishDate: true,
|
||||
broadcastNewsFeeds: true,
|
||||
broadcastNewsUpdates: true
|
||||
}
|
||||
},
|
||||
]
|
||||
@@ -74,4 +98,4 @@ var config = {
|
||||
};
|
||||
|
||||
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||
if (typeof module !== 'undefined') {module.exports = config;}
|
||||
if (typeof module !== "undefined") {module.exports = config;}
|
||||
|
@@ -1,14 +0,0 @@
|
||||
/*****************************************************
|
||||
* Magic Mirror *
|
||||
* Custom CSS *
|
||||
* *
|
||||
* By Michael Teeuw http://michaelteeuw.nl *
|
||||
* MIT Licensed. *
|
||||
* *
|
||||
* Add any custom CSS below. *
|
||||
* Changes to this files will be ignored by GIT. *
|
||||
*****************************************************/
|
||||
|
||||
body {
|
||||
|
||||
}
|
44
css/main.css
44
css/main.css
@@ -1,10 +1,11 @@
|
||||
html {
|
||||
cursor: none;
|
||||
overflow:hidden;
|
||||
overflow: hidden;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
body {
|
||||
@@ -94,7 +95,7 @@ body {
|
||||
header {
|
||||
text-transform: uppercase;
|
||||
font-size: 15px;
|
||||
font-family: "Roboto Condensed";
|
||||
font-family: "Roboto Condensed", Arial, Helvetica, sans-serif;
|
||||
font-weight: 400;
|
||||
border-bottom: 1px solid #666;
|
||||
line-height: 15px;
|
||||
@@ -113,11 +114,22 @@ sup {
|
||||
*/
|
||||
|
||||
.module {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.module:first-child {
|
||||
margin-top: 0;
|
||||
.region.bottom .module {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.no-wrap {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.pre-line {
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -134,10 +146,16 @@ sup {
|
||||
left: -60px;
|
||||
right: -60px;
|
||||
bottom: -60px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.region.fullscreen * {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.region.right {
|
||||
right: 0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.region.top {
|
||||
@@ -148,6 +166,10 @@ sup {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.region.bottom .container {
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.region.top .container:empty {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@@ -172,10 +194,6 @@ sup {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.region.bottom .container {
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
.region.bottom .container:empty {
|
||||
margin-top: 0;
|
||||
}
|
||||
@@ -218,10 +236,6 @@ sup {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.region.right {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.region table {
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
|
17
dangerfile.js
Normal file
17
dangerfile.js
Normal file
@@ -0,0 +1,17 @@
|
||||
import { danger, fail, warn } from "danger";
|
||||
|
||||
// Check if the CHANGELOG.md file has been edited
|
||||
// Fail the build and post a comment reminding submitters to do so if it wasn't changed
|
||||
if (!danger.git.modified_files.includes("CHANGELOG.md")) {
|
||||
warn("Please include an updated `CHANGELOG.md` file.<br>This way we can keep track of all the contributions.");
|
||||
}
|
||||
|
||||
// Check if the PR request is send to the master branch.
|
||||
// This should only be done by MichMich.
|
||||
if (danger.github.pr.base.ref === "master" && danger.github.pr.user.login !== "MichMich") {
|
||||
// Check if the PR body or title includes the text: #accepted.
|
||||
// If not, the PR will fail.
|
||||
if ((danger.github.pr.body + danger.github.pr.title).includes("#accepted")) {
|
||||
fail("Please send all your pull requests to the `develop` branch.<br>Pull requests on the `master` branch will not be accepted.");
|
||||
}
|
||||
}
|
@@ -1,202 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
12
fonts/package-lock.json
generated
Normal file
12
fonts/package-lock.json
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "magicmirror-fonts",
|
||||
"requires": true,
|
||||
"lockfileVersion": 1,
|
||||
"dependencies": {
|
||||
"roboto-fontface": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/roboto-fontface/-/roboto-fontface-0.8.0.tgz",
|
||||
"integrity": "sha512-ZYzRkETgBrdEGzL5JSKimvjI2CX7ioyZCkX2BpcfyjqI+079W0wHAyj5W4rIZMcDSOHgLZtgz1IdDi/vU77KEQ=="
|
||||
}
|
||||
}
|
||||
}
|
15
fonts/package.json
Normal file
15
fonts/package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"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": {
|
||||
"roboto-fontface": "^0.8.0"
|
||||
}
|
||||
}
|
@@ -5,9 +5,9 @@
|
||||
src:
|
||||
local("Roboto Thin"),
|
||||
local("Roboto-Thin"),
|
||||
url("Roboto-Thin/Roboto-Thin.woff2") format("woff2"),
|
||||
url("Roboto-Thin/Roboto-Thin.woff") format("woff"),
|
||||
url("Roboto-Thin/Roboto-Thin.ttf") format("truetype");
|
||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Thin.woff2") format("woff2"),
|
||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Thin.woff") format("woff"),
|
||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Thin.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@@ -17,9 +17,9 @@
|
||||
src:
|
||||
local("Roboto Condensed Light"),
|
||||
local("RobotoCondensed-Light"),
|
||||
url("RobotoCondensed-Light/RobotoCondensed-Light.woff2") format("woff2"),
|
||||
url("RobotoCondensed-Light/RobotoCondensed-Light.woff") format("woff"),
|
||||
url("RobotoCondensed-Light/RobotoCondensed-Light.ttf") format("truetype");
|
||||
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Light.woff2") format("woff2"),
|
||||
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Light.woff") format("woff"),
|
||||
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Light.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@@ -29,9 +29,9 @@
|
||||
src:
|
||||
local("Roboto Condensed"),
|
||||
local("RobotoCondensed-Regular"),
|
||||
url("RobotoCondensed-Regular/RobotoCondensed-Regular.woff2") format("woff2"),
|
||||
url("RobotoCondensed-Regular/RobotoCondensed-Regular.woff") format("woff"),
|
||||
url("RobotoCondensed-Regular/RobotoCondensed-Regular.ttf") format("truetype");
|
||||
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Regular.woff2") format("woff2"),
|
||||
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Regular.woff") format("woff"),
|
||||
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@@ -41,9 +41,9 @@
|
||||
src:
|
||||
local("Roboto Condensed Bold"),
|
||||
local("RobotoCondensed-Bold"),
|
||||
url("RobotoCondensed-Bold/RobotoCondensed-Bold.woff2") format("woff2"),
|
||||
url("RobotoCondensed-Bold/RobotoCondensed-Bold.woff") format("woff"),
|
||||
url("RobotoCondensed-Bold/RobotoCondensed-Bold.ttf") format("truetype");
|
||||
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Bold.woff2") format("woff2"),
|
||||
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Bold.woff") format("woff"),
|
||||
url("node_modules/roboto-fontface/fonts/roboto-condensed/Roboto-Condensed-Bold.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@@ -53,9 +53,9 @@
|
||||
src:
|
||||
local("Roboto"),
|
||||
local("Roboto-Regular"),
|
||||
url("Roboto-Regular/Roboto-Regular.woff2") format("woff2"),
|
||||
url("Roboto-Regular/Roboto-Regular.woff") format("woff"),
|
||||
url("Roboto-Regular/Roboto-Regular.ttf") format("truetype");
|
||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Regular.woff2") format("woff2"),
|
||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Regular.woff") format("woff"),
|
||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@@ -65,9 +65,9 @@
|
||||
src:
|
||||
local("Roboto Medium"),
|
||||
local("Roboto-Medium"),
|
||||
url("Roboto-Medium/Roboto-Medium.woff2") format("woff2"),
|
||||
url("Roboto-Medium/Roboto-Medium.woff") format("woff"),
|
||||
url("Roboto-Medium/Roboto-Medium.ttf") format("truetype");
|
||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Medium.woff2") format("woff2"),
|
||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Medium.woff") format("woff"),
|
||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Medium.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@@ -77,9 +77,9 @@
|
||||
src:
|
||||
local("Roboto Bold"),
|
||||
local("Roboto-Bold"),
|
||||
url("Roboto-Bold/Roboto-Bold.woff2") format("woff2"),
|
||||
url("Roboto-Bold/Roboto-Bold.woff") format("woff"),
|
||||
url("Roboto-Bold/Roboto-Bold.ttf") format("truetype");
|
||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Bold.woff2") format("woff2"),
|
||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Bold.woff") format("woff"),
|
||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Bold.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@@ -89,7 +89,7 @@
|
||||
src:
|
||||
local("Roboto Light"),
|
||||
local("Roboto-Light"),
|
||||
url("Roboto-Light/Roboto-Light.woff2") format("woff2"),
|
||||
url("Roboto-Light/Roboto-Light.woff") format("woff"),
|
||||
url("Roboto-Light/Roboto-Light.ttf") format("truetype");
|
||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Light.woff2") format("woff2"),
|
||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Light.woff") format("woff"),
|
||||
url("node_modules/roboto-fontface/fonts/roboto/Roboto-Light.ttf") format("truetype");
|
||||
}
|
||||
|
7
fonts/yarn.lock
Normal file
7
fonts/yarn.lock
Normal file
@@ -0,0 +1,7 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
roboto-fontface@^0.8.0:
|
||||
version "0.8.0"
|
||||
resolved "https://registry.yarnpkg.com/roboto-fontface/-/roboto-fontface-0.8.0.tgz#031a83c8f79932801a57d83bf743f37250163499"
|
15
index.html
15
index.html
@@ -1,13 +1,23 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Magic Mirror</title>
|
||||
<title>MagicMirror²</title>
|
||||
<meta name="google" content="notranslate" />
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
|
||||
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="mobile-web-app-capable" content="yes">
|
||||
|
||||
<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">
|
||||
<!-- custom.css is loaded by the loader.js to make sure it's loaded after the module css files. -->
|
||||
|
||||
<script type="text/javascript">
|
||||
var version = "#VERSION#";
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="region fullscreen below"><div class="container"></div></div>
|
||||
@@ -28,8 +38,9 @@
|
||||
</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="js/defaults.js"></script>
|
||||
<script type="text/javascript" src="config/config.js"></script>
|
||||
<script type="text/javascript" src="#CONFIG_FILE#"></script>
|
||||
<script type="text/javascript" src="vendor/vendor.js"></script>
|
||||
<script type="text/javascript" src="modules/default/defaultmodules.js"></script>
|
||||
<script type="text/javascript" src="js/logger.js"></script>
|
||||
|
15
installers/dumpactivemodules.js
Normal file
15
installers/dumpactivemodules.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const config = require('../config/config.js');const fs=require('fs');
|
||||
for(let m of config.modules){
|
||||
if(!(m.disabled || false)){
|
||||
try {
|
||||
let f=fs.statSync(m.module);
|
||||
if(f.isDirectory()){
|
||||
f1=fs.statSync(m.module+'/package.json');
|
||||
if (f1.isFile()){
|
||||
console.log(m.module);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ex) {}
|
||||
}
|
||||
}
|
183
installers/fixuppm2.sh
Executable file
183
installers/fixuppm2.sh
Executable file
@@ -0,0 +1,183 @@
|
||||
#!/bin/bash
|
||||
# Define the tested version of Node.js.
|
||||
NODE_TESTED="v10.1.0"
|
||||
NPM_TESTED="V6.0.0"
|
||||
USER=`whoami`
|
||||
PM2_FILE=pm2_MagicMirror.json
|
||||
mac=$(uname -s)
|
||||
if [ $mac == 'Darwin' ]; then
|
||||
cmd=greadlink
|
||||
else
|
||||
cmd=readlink
|
||||
fi
|
||||
|
||||
if [ -d ~/MagicMirror ]; then
|
||||
# put the log where the script is located
|
||||
logdir=$(dirname $($cmd -f "$0"))
|
||||
# if the script was execute from the web
|
||||
if [[ $logdir != *"MagicMirror/installers"* ]]; then
|
||||
# use the MagicMirror/installers folder
|
||||
cd ~/MagicMirror/installers >/dev/null
|
||||
logdir=$(pwd)
|
||||
cd - >/dev/null
|
||||
fi
|
||||
logfile=$logdir/pm2_setup.log
|
||||
echo the log will be saved in $logfile
|
||||
date +"pm2 setup starting - %a %b %e %H:%M:%S %Z %Y" >>$logfile
|
||||
echo system is $(uname -a) >> $logfile
|
||||
if [ "$mac" == "Darwin" ]; then
|
||||
echo the os is macOS $(sw_vers -productVersion) >> $logfile
|
||||
else
|
||||
echo the os is $(lsb_release -a 2>/dev/null) >> $logfile
|
||||
fi
|
||||
node_installed=$(which node)
|
||||
if [ "$node_installed." == "." ]; then
|
||||
# node not installed
|
||||
echo Installing node >>$logfile
|
||||
if [ $mac == 'Darwin' ]; then
|
||||
brew install node
|
||||
else
|
||||
NODE_STABLE_BRANCH="10.x"
|
||||
curl -sL https://deb.nodesource.com/setup_$NODE_STABLE_BRANCH | sudo -E bash -
|
||||
sudo apt-get install -y nodejs
|
||||
fi
|
||||
fi
|
||||
node_version=$(node -v)
|
||||
echo node version $node_version >>$logfile
|
||||
npm_installed=$(which npm)
|
||||
if [ "$npm_installed." == "." ]; then
|
||||
# npm not installed
|
||||
echo Installing npm >>$logfile
|
||||
if [ $mac != 'Darwin' ]; then
|
||||
sudo apt-get install -y npm
|
||||
fi
|
||||
fi
|
||||
# get latest
|
||||
echo force installing latest npm version via npm >>$logfile
|
||||
#sudo npm i -g npm
|
||||
npm_version=$(npm -v)
|
||||
echo npm version $npm_version >>$logfile
|
||||
# assume pm2 will be found on the path
|
||||
pm2cmd=pm2
|
||||
up=""
|
||||
if [ $mac == 'Darwin' ]; then
|
||||
up="--unsafe-perm"
|
||||
launchctl=launchctl
|
||||
launchctl_path=$(which $launchctl)
|
||||
`export PATH=$PATH:${launchctl_path%/$launchctl}`
|
||||
fi
|
||||
# check to see if already installed
|
||||
pm2_installed=$(which $pm2cmd)
|
||||
if [ "$pm2_installed." != "." ]; then
|
||||
# does it work?
|
||||
echo pm2 installed >> $logfile
|
||||
pm2_fails=$(pm2 list | grep -i -m 1 "App Name" | wc -l )
|
||||
if [ $pm2_fails != 1 ]; then
|
||||
# uninstall it
|
||||
echo pm2 installed, but does not work, uninstalling >> $logfile
|
||||
sudo npm uninstall $up -g pm2
|
||||
# force reinstall
|
||||
pm2_installed=
|
||||
fi
|
||||
fi
|
||||
# in not installed
|
||||
if [ "$pm2_installed." == "." ]; then
|
||||
# install it.
|
||||
echo pm2 not installed, installing >>$logfile
|
||||
result=$(sudo npm install $up -g pm2)
|
||||
# if this is a mac
|
||||
if [ $mac == 'Darwin' ]; then
|
||||
echo this is a mac, fixup for path >>$logfile
|
||||
# get the location of pm2 install
|
||||
# parse the npm install output to get the command
|
||||
pm2cmd=`echo $result | awk -F - '{print $1}' | tr -d '[:space:]'`
|
||||
c='/pm2'
|
||||
# get the path only
|
||||
echo ${pm2cmd%$c} >installers/pm2path
|
||||
fi
|
||||
fi
|
||||
# remove MagicMirror if defined
|
||||
$pm2cmd delete MagicMirror >/dev/null 2>&1
|
||||
cd ~/MagicMirror
|
||||
echo get the pm2 platform specific startup command >>$logfile
|
||||
# get the platform specific pm2 startup command
|
||||
v=$($pm2cmd startup | tail -n 1)
|
||||
if [ $mac != 'Darwin' ]; then
|
||||
# check to see if we can get the OS package name (Ubuntu)
|
||||
if [ $(which lsb_release| wc -l) >0 ]; then
|
||||
# fix command
|
||||
# if ubuntu 18.04, pm2 startup gets something wrong
|
||||
if [ $(lsb_release -r | grep -m1 18.04 | wc -l) > 0 ]; then
|
||||
v=$(echo $v | sed 's/\/bin/\/bin:\/bin/')
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
echo startup command = $v >>$logfile
|
||||
# execute the command returned
|
||||
$v 2>&1 >>$logfile
|
||||
echo pm2 startup command done >>$logfile
|
||||
# is this is mac
|
||||
# need to fix pm2 startup, only on catalina
|
||||
if [ $mac == 'Darwin' ]; then
|
||||
if [ $(sw_vers -productVersion | head -c 6) == '10.15.' ]; then
|
||||
# only do if the faulty tag is present (pm2 may fix this, before the script is fixed)
|
||||
if [ $(grep -m 1 UserName /Users/$USER/Library/LaunchAgents/pm2.$USER.plist | wc -l) -eq 1 ]; then
|
||||
# copy the pm2 startup file config
|
||||
cp /Users/$USER/Library/LaunchAgents/pm2.$USER.plist .
|
||||
# edit out the UserName key/value strings
|
||||
sed -e '/UserName/{N;d;}' pm2.$USER.plist > pm2.$USER.plist.new
|
||||
# copy the file back
|
||||
sudo cp pm2.$USER.plist.new /Users/$USER/Library/LaunchAgents/pm2.$USER.plist
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# if the user is no pi, we have to fixup the pm2 json file
|
||||
echo configure the pm2 config file for MagicMirror >>$logfile
|
||||
if [ "$USER" != "pi" ]; then
|
||||
echo the user is not pi >>$logfile
|
||||
# go to the installers folder`
|
||||
cd installers
|
||||
# edit the startup script for the right user
|
||||
echo change mm.sh >>$logfile
|
||||
if [ ! -e mm_temp.sh ]; then
|
||||
echo save copy of mm.sh >> $logfile
|
||||
cp mm.sh mm_temp.sh
|
||||
fi
|
||||
if [ $(grep pi mm_temp.sh | wc -l) -gt 0 ]; then
|
||||
echo change hard coded pi username >> $logfile
|
||||
sed 's/pi/'$USER'/g' mm_temp.sh >mm.sh
|
||||
else
|
||||
echo change relative home path to hard coded path >> $logfile
|
||||
hf=$(echo $HOME |sed 's/\//\\\//g')
|
||||
sed 's/\~/'$hf'/g' mm_temp.sh >mm.sh
|
||||
fi
|
||||
# edit the pms config file for the right user
|
||||
echo change $PM2_FILE >>$logfile
|
||||
sed 's/pi/'$USER'/g' $PM2_FILE > pm2_MagicMirror_new.json
|
||||
# make sure to use the updated file
|
||||
PM2_FILE=pm2_MagicMirror_new.json
|
||||
# if this is a mac
|
||||
if [ $mac == 'Darwin' ]; then
|
||||
# copy the path file to the system paths list
|
||||
sudo cp ./pm2path /etc/paths.d
|
||||
# change the name of the home path for mac
|
||||
sed 's/home/Users/g' $PM2_FILE > pm2_MagicMirror_new1.json
|
||||
# make sure to use the updated file
|
||||
PM2_FILE=pm2_MagicMirror_new1.json
|
||||
fi
|
||||
echo now using this config file $PM2_FILE >>$logfile
|
||||
# go back one cd level
|
||||
cd - >/dev/null
|
||||
fi
|
||||
echo start MagicMirror via pm2 now >>$logfile
|
||||
# tell pm2 to start the app defined in the config file
|
||||
$pm2cmd start $HOME/MagicMirror/installers/$PM2_FILE
|
||||
# tell pm2 to save that configuration, for start at boot
|
||||
echo save MagicMirror pm2 config now >>$logfile
|
||||
$pm2cmd save
|
||||
date +"pm2 setup completed - %a %b %e %H:%M:%S %Z %Y" >>$logfile
|
||||
else
|
||||
echo It appears MagicMirror has not been installed on this system
|
||||
echo please run the installer, "raspberry.sh" first
|
||||
fi
|
2
installers/mm.sh
Executable file
2
installers/mm.sh
Executable file
@@ -0,0 +1,2 @@
|
||||
cd ~/MagicMirror
|
||||
DISPLAY=:0 npm start
|
7
installers/pm2_MagicMirror.json
Normal file
7
installers/pm2_MagicMirror.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"apps" : [{
|
||||
"name" : "MagicMirror",
|
||||
"script" : "/home/pi/MagicMirror/installers/mm.sh",
|
||||
"watch" : ["/home/pi/MagicMirror/config/config.js"]
|
||||
}]
|
||||
}
|
2
installers/postinstall/postinstall.sh
Normal file
2
installers/postinstall/postinstall.sh
Normal file
@@ -0,0 +1,2 @@
|
||||
echo "\033[32mMagicMirror installation successful!"
|
||||
exit 0
|
587
installers/raspberry.sh
Normal file → Executable file
587
installers/raspberry.sh
Normal file → Executable file
@@ -1,9 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#!/bin/bash
|
||||
# This is an installer script for MagicMirror2. It works well enough
|
||||
# that it can detect if you have Node installed, run a binary script
|
||||
# and then download and run MagicMirror2.
|
||||
|
||||
if [ $USER == 'root' ]; then
|
||||
echo Please logon as a user to execute the MagicMirror installation, not root
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "\e[0m"
|
||||
echo '$$\ $$\ $$\ $$\ $$\ $$\ $$$$$$\'
|
||||
echo '$$$\ $$$ | \__| $$$\ $$$ |\__| $$ __$$\'
|
||||
@@ -18,101 +22,548 @@ echo ' \$$$$$$ |'
|
||||
echo ' \______/'
|
||||
echo -e "\e[0m"
|
||||
|
||||
# Define the tested version of Node.js.
|
||||
NODE_TESTED="v5.1.0"
|
||||
doInstall=1
|
||||
true=1
|
||||
false=0
|
||||
# Define the tested version of Node.js.
|
||||
NODE_TESTED="v10.1.0"
|
||||
NPM_TESTED="V6.0.0"
|
||||
USER=`whoami`
|
||||
PM2_FILE=pm2_MagicMirror.json
|
||||
force_arch=
|
||||
pm2setup=$false
|
||||
|
||||
#Determine which Pi is running.
|
||||
ARM=$(uname -m)
|
||||
trim() {
|
||||
local var="$*"
|
||||
# remove leading whitespace characters
|
||||
var="${var#"${var%%[![:space:]]*}"}"
|
||||
# remove trailing whitespace characters
|
||||
var="${var%"${var##*[![:space:]]}"}"
|
||||
echo -n "$var"
|
||||
}
|
||||
|
||||
#Check the Raspberry Pi version.
|
||||
if [ "$ARM" != "armv7l" ]; then
|
||||
echo -e "\e[91mSorry, your Raspberry Pi is not supported."
|
||||
echo -e "\e[91mPlease run MagicMirror on a Raspberry Pi 2 or 3."
|
||||
exit;
|
||||
|
||||
|
||||
mac=$(uname -s)
|
||||
if [ $mac == 'Darwin' ]; then
|
||||
echo this is a mac | tee -a $logfile
|
||||
cmd=greadlink
|
||||
else
|
||||
cmd=readlink
|
||||
fi
|
||||
|
||||
#define helper methods.
|
||||
function version_gt() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" != "$1"; }
|
||||
function command_exists () { type "$1" &> /dev/null ;}
|
||||
|
||||
# Installing helper tools
|
||||
echo -e "\e[96mInstalling helper tools ...\e[90m"
|
||||
sudo apt-get install curl wget git build-essential unzip || exit
|
||||
# put the log where the script is located
|
||||
logdir=$(dirname $($cmd -f "$0"))
|
||||
# if the script was execute from the web
|
||||
if [[ $logdir != *"MagicMirror/installers"* ]]; then
|
||||
# use the MagicMirror/installers folder, if setup
|
||||
if [ -d MagicMirror ]; then
|
||||
cd ~/MagicMirror/installers >/dev/null
|
||||
logdir=$(pwd)
|
||||
cd - >/dev/null
|
||||
else
|
||||
# use the users home folder if initial install
|
||||
logdir=$HOME
|
||||
fi
|
||||
fi
|
||||
logfile=$logdir/install.log
|
||||
echo install log being saved to $logfile
|
||||
|
||||
# Determine which Pi is running.
|
||||
date +"install starting - %a %b %e %H:%M:%S %Z %Y" >>$logfile
|
||||
ARM=$(uname -m)
|
||||
echo installing on $ARM processor system >>$logfile
|
||||
echo the os is $(lsb_release -a 2>/dev/null) >> $logfile
|
||||
# Check the Raspberry Pi version.
|
||||
if [ "$ARM" != "armv7l" ]; then
|
||||
read -p "this appears not to be a Raspberry Pi 2 or 3, do you want to continue installation (y/N)?" choice
|
||||
if [[ $choice =~ ^[Nn]$ ]]; then
|
||||
echo user stopped install on $ARM hardware >>$logfile
|
||||
echo -e "\e[91mSorry, your Raspberry Pi is not supported."
|
||||
echo -e "\e[91mPlease run MagicMirror on a Raspberry Pi 2 or 3."
|
||||
echo -e "\e[91mIf this is a Pi Zero, the setup will configure to run in server only mode wih a local browser."
|
||||
exit;
|
||||
fi
|
||||
#if [ "$ARM" == "armv6l" ]; then
|
||||
# echo forcing armv71 architecture for pi 0 >>$logfile
|
||||
# force_arch=-'--arch=armv7l'
|
||||
# fi
|
||||
fi
|
||||
|
||||
# Define helper methods.
|
||||
function command_exists () { type "$1" &> /dev/null ;}
|
||||
function verlte() { [ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ];}
|
||||
function verlt() { [ "$1" = "$2" ] && return 1 || verlte $1 $2 ;}
|
||||
|
||||
# Update before first apt-get
|
||||
if [ $mac != 'Darwin' ]; then
|
||||
echo -e "\e[96mUpdating packages ...\e[90m" | tee -a $logfile
|
||||
upgrade=$false
|
||||
update=$(sudo apt-get update 2>&1)
|
||||
echo $update >> $logfile
|
||||
update_rc=$?
|
||||
if [ $update_rc -ne 0 ]; then
|
||||
echo -e "\e[91mUpdate failed, retrying installation ...\e[90m" | tee -a $logfile
|
||||
if [ $(echo $update | grep "apt-secure" | wc -l) -eq 1 ]; then
|
||||
update=$(sudo apt-get update --allow-releaseinfo-change 2>&1)
|
||||
update_rc=$?
|
||||
echo $update >> $logfile
|
||||
if [ $update_rc -ne 0 ]; then
|
||||
echo "second apt-get update failed" $update | tee -a $logfile
|
||||
exit 1
|
||||
else
|
||||
echo "second apt-get update completed ok" >> $logfile
|
||||
upgrade=$true
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "apt-get update completed ok" >> $logfile
|
||||
upgrade=$true
|
||||
fi
|
||||
if [ $upgrade -eq $true ]; then
|
||||
upgrade_result=$(sudo apt-get upgrade 2>&1)
|
||||
upgrade_rc=$?
|
||||
echo apt upgrade result ="rc=$upgrade_rc $upgrade_result" >> $logfile
|
||||
fi
|
||||
|
||||
# Installing helper tools
|
||||
echo -e "\e[96mInstalling helper tools ...\e[90m" | tee -a $logfile
|
||||
sudo apt-get --assume-yes install curl wget git build-essential unzip || exit
|
||||
fi
|
||||
|
||||
# Check if we need to install or upgrade Node.js.
|
||||
echo -e "\e[96mCheck current Node installation ...\e[0m"
|
||||
echo -e "\e[96mCheck current Node installation ...\e[0m" | tee -a $logfile
|
||||
NODE_INSTALL=false
|
||||
if command_exists node; then
|
||||
echo -e "\e[0mNode currently installed. Checking version number.";
|
||||
echo -e "\e[0mNode currently installed. Checking version number." | tee -a $logfile
|
||||
NODE_CURRENT=$(node -v)
|
||||
echo -e "\e[0mMinimum Node version: \e[1m$NODE_TESTED\e[0m"
|
||||
echo -e "\e[0mInstalled Node version: \e[1m$NODE_CURRENT\e[0m"
|
||||
if version_gt $NODE_TESTED $NODE_CURRENT; then
|
||||
echo -e "\e[96mNode should be upgraded.\e[0m"
|
||||
NODE_INSTALL=true
|
||||
if [ "$NODE_CURRENT." == "." ]; then
|
||||
NODE_CURRENT="V1.0.0"
|
||||
echo forcing low Node version >> $logfile
|
||||
fi
|
||||
echo -e "\e[0mMinimum Node version: \e[1m$NODE_TESTED\e[0m" | tee -a $logfile
|
||||
echo -e "\e[0mInstalled Node version: \e[1m$NODE_CURRENT\e[0m" | tee -a $logfile
|
||||
if verlte $NODE_CURRENT $NODE_TESTED; then
|
||||
echo -e "\e[96mNode should be upgraded.\e[0m" | tee -a $logfile
|
||||
NODE_INSTALL=true
|
||||
|
||||
#Check if a node process is currenlty running.
|
||||
#If so abort installation.
|
||||
if pgrep "node" > /dev/null; then
|
||||
echo -e "\e[91mA Node process is currently running. Can't upgrade."
|
||||
echo "Please quit all Node processes and restart the installer."
|
||||
exit;
|
||||
# Check if a node process is currenlty running.
|
||||
# If so abort installation.
|
||||
if pgrep "node" > /dev/null; then
|
||||
echo -e "\e[91mA Node process is currently running. Can't upgrade." | tee -a $logfile
|
||||
echo "Please quit all Node processes and restart the installer." | tee -a $logfile
|
||||
echo $(ps -ef | grep node | grep -v \-\-color) | tee -a $logfile
|
||||
exit;
|
||||
fi
|
||||
|
||||
else
|
||||
echo -e "\e[92mNo Node.js upgrade nessecery.\e[0m"
|
||||
else
|
||||
echo -e "\e[92mNo Node.js upgrade necessary.\e[0m" | tee -a $logfile
|
||||
fi
|
||||
|
||||
else
|
||||
echo -e "\e[93mNode.js is not installed.\e[0m";
|
||||
echo -e "\e[93mNode.js is not installed.\e[0m" | tee -a $logfile
|
||||
NODE_INSTALL=true
|
||||
fi
|
||||
|
||||
# Install or upgare node if nessecery.
|
||||
# Install or upgrade node if necessary.
|
||||
if $NODE_INSTALL; then
|
||||
|
||||
echo -e "\e[96mInstalling Node.js ...\e[90m"
|
||||
|
||||
#Fetch the latest version of Node.js from the selected branch
|
||||
#The NODE_STABLE_BRANCH variable will need to be manually adjusted when a new branch is released. (e.g. 7.x)
|
||||
#Only tested (stable) versions are recommended as newer versions could break MagicMirror.
|
||||
|
||||
NODE_STABLE_BRANCH="6.x"
|
||||
curl -sL https://deb.nodesource.com/setup_$NODE_STABLE_BRANCH | sudo -E bash -
|
||||
sudo apt-get install -y nodejs
|
||||
echo -e "\e[92mNode.js installation Done!\e[0m"
|
||||
echo -e "\e[96mInstalling Node.js ...\e[90m" | tee -a $logfile
|
||||
|
||||
# Fetch the latest version of Node.js from the selected branch
|
||||
# The NODE_STABLE_BRANCH variable will need to be manually adjusted when a new branch is released. (e.g. 7.x)
|
||||
# Only tested (stable) versions are recommended as newer versions could break MagicMirror.
|
||||
if [ $mac == 'Darwin' ]; then
|
||||
brew install node
|
||||
else
|
||||
NODE_STABLE_BRANCH="10.x"
|
||||
# sudo apt-get install --only-upgrade libstdc++6
|
||||
node_info=$(curl -sL https://deb.nodesource.com/setup_$NODE_STABLE_BRANCH | sudo -E bash - )
|
||||
echo Node release info = $node_info >> $logfile
|
||||
if [ "$(echo $node_info | grep "not currently supported")." == "." ]; then
|
||||
sudo apt-get install -y nodejs
|
||||
else
|
||||
echo node $NODE_STABLE_BRANCH version installer not available, doing manually >>$logfile
|
||||
# no longer supported install
|
||||
sudo apt-get install -y --only-upgrade libstdc++6 >> $logfile
|
||||
# have to do it manually
|
||||
node_vnum=$(echo $NODE_STABLE_BRANCH | awk -F. '{print $1}')
|
||||
# get the highest release number in the stable branch line for this processor architecture
|
||||
node_ver=$(curl -sL https://unofficial-builds.nodejs.org/download/release/index.tab | grep $ARM | grep -m 1 v$node_vnum | awk '{print $1}')
|
||||
echo latest release in the $NODE_STABLE_BRANCH family for $ARM is $node_ver >> $logfile
|
||||
curl -sL https://unofficial-builds.nodejs.org/download/release/$node_ver/node-$node_ver-linux-$ARM.tar.gz >node_release-$node_ver.tar.gz
|
||||
cd /usr/local
|
||||
echo using release tar file = node_release-$node_ver.tar.gz >> $logfile
|
||||
sudo tar --strip-components 1 -xzf $HOME/node_release-$node_ver.tar.gz
|
||||
cd - >/dev/null
|
||||
rm ./node_release-$node_ver.tar.gz
|
||||
fi
|
||||
# get the new node version number
|
||||
new_ver=$(node -v 2>&1)
|
||||
# if there is a failure to get it due to a missing library
|
||||
if [ $(echo $new_ver | grep "not found" | wc -l) -ne 0 ]; then
|
||||
#
|
||||
sudo apt-get install -y --only-upgrade libstdc++6 >> $logfile
|
||||
fi
|
||||
echo node version is $(node -v 2>&1 >>$logfile)
|
||||
fi
|
||||
echo -e "\e[92mNode.js installation Done! version=$(node -v)\e[0m" | tee -a $logfile
|
||||
fi
|
||||
# Check if we need to install or upgrade npm.
|
||||
echo -e "\e[96mCheck current NPM installation ...\e[0m" | tee -a $logfile
|
||||
NPM_INSTALL=false
|
||||
if command_exists npm; then
|
||||
echo -e "\e[0mNPM currently installed. Checking version number." | tee -a $logfile
|
||||
NPM_CURRENT='V'$(npm -v)
|
||||
echo -e "\e[0mMinimum npm version: \e[1m$NPM_TESTED\e[0m" | tee -a $logfile
|
||||
echo -e "\e[0mInstalled npm version: \e[1m$NPM_CURRENT\e[0m" | tee -a $logfile
|
||||
if verlte $NPM_CURRENT $NPM_TESTED; then
|
||||
echo -e "\e[96mnpm should be upgraded.\e[0m" | tee -a $logfile
|
||||
NPM_INSTALL=true
|
||||
|
||||
# Check if a node process is currently running.
|
||||
# If so abort installation.
|
||||
if pgrep "npm" > /dev/null; then
|
||||
echo -e "\e[91mA npm process is currently running. Can't upgrade." | tee -a $logfile
|
||||
echo "Please quit all npm processes and restart the installer." | tee -a $logfile
|
||||
exit;
|
||||
fi
|
||||
|
||||
else
|
||||
echo -e "\e[92mNo npm upgrade necessary.\e[0m" | tee -a $logfile
|
||||
fi
|
||||
|
||||
else
|
||||
echo -e "\e[93mnpm is not installed.\e[0m" | tee -a $logfile
|
||||
NPM_INSTALL=true
|
||||
fi
|
||||
|
||||
#Install magic mirror
|
||||
# Install or upgrade node if necessary.
|
||||
if $NPM_INSTALL; then
|
||||
|
||||
echo -e "\e[96mInstalling npm ...\e[90m" | tee -a $logfile
|
||||
|
||||
# Fetch the latest version of npm from the selected branch
|
||||
# The NODE_STABLE_BRANCH variable will need to be manually adjusted when a new branch is released. (e.g. 7.x)
|
||||
# Only tested (stable) versions are recommended as newer versions could break MagicMirror.
|
||||
|
||||
#NODE_STABLE_BRANCH="9.x"
|
||||
#curl -sL https://deb.nodesource.com/setup_$NODE_STABLE_BRANCH | sudo -E bash -
|
||||
#
|
||||
# if this is a mac, npm was installed with node
|
||||
if [ $mac != 'Darwin' ]; then
|
||||
sudo apt-get install -y npm >>$logfile
|
||||
fi
|
||||
# update to the latest.
|
||||
echo upgrading npm to latest >> $logfile
|
||||
sudo npm i -g npm >>$logfile
|
||||
echo -e "\e[92mnpm installation Done! version=V$(npm -v)\e[0m" | tee -a $logfile
|
||||
fi
|
||||
|
||||
# Install MagicMirror
|
||||
cd ~
|
||||
if [ -d "$HOME/MagicMirror" ] ; then
|
||||
echo -e "\e[93mIt seems like MagicMirror is already installed."
|
||||
echo -e "To prevent overwriting, the installer will be aborted."
|
||||
echo -e "Please rename the \e[1m~/MagicMirror\e[0m\e[93m folder and try again.\e[0m"
|
||||
echo ""
|
||||
echo -e "If you want to upgrade your installation run \e[1m\e[97mgit pull\e[0m from the ~/MagicMirror directory."
|
||||
echo ""
|
||||
exit;
|
||||
fi
|
||||
if [ $doInstall == 1 ]; then
|
||||
if [ -d "$HOME/MagicMirror" ] ; then
|
||||
echo -e "\e[93mIt seems like MagicMirror is already installed." | tee -a $logfile
|
||||
echo -e "To prevent overwriting, the installer will be aborted." | tee -a $logfile
|
||||
echo -e "Please rename the \e[1m~/MagicMirror\e[0m\e[93m folder and try again.\e[0m" | tee -a $logfile
|
||||
echo ""
|
||||
echo -e "If you want to upgrade your installation run \e[1m\e[97mupgrade-script\e[0m from the ~/MagicMirror/installers directory." | tee -a $logfile
|
||||
echo ""
|
||||
exit;
|
||||
fi
|
||||
|
||||
echo -e "\e[96mCloning MagicMirror ...\e[90m"
|
||||
if git clone https://github.com/MichMich/MagicMirror.git; then
|
||||
echo -e "\e[92mCloning MagicMirror Done!\e[0m"
|
||||
echo -e "\e[96mCloning MagicMirror ...\e[90m" | tee -a $logfile
|
||||
if git clone --depth=1 https://github.com/MichMich/MagicMirror.git; then
|
||||
echo -e "\e[92mCloning MagicMirror Done!\e[0m" | tee -a $logfile
|
||||
else
|
||||
echo -e "\e[91mUnable to clone MagicMirror." | tee -a $logfile
|
||||
exit;
|
||||
fi
|
||||
|
||||
cd ~/MagicMirror || exit
|
||||
if [ $(grep version package.json | awk -F: '{print $2}') == '"2.9.0",' -a $ARM == 'armv6l' ]; then
|
||||
git fetch https://github.com/MichMich/MagicMirror.git develop >/dev/null 2>&1
|
||||
git branch develop FETCH_HEAD > /dev/null 2>&1
|
||||
git checkout develop > /dev/null 2>&1
|
||||
fi
|
||||
echo -e "\e[96mInstalling dependencies ...\e[90m" | tee -a $logfile
|
||||
if npm install $force_arch; then
|
||||
echo -e "\e[92mDependencies installation Done!\e[0m" | tee -a $logfile
|
||||
else
|
||||
echo -e "\e[91mUnable to install dependencies!" | tee -a $logfile
|
||||
exit;
|
||||
fi
|
||||
|
||||
# Use sample config for start MagicMirror
|
||||
echo setting up initial config.js | tee -a $logfile
|
||||
cp config/config.js.sample config/config.js
|
||||
fi
|
||||
# Check if plymouth is installed (default with PIXEL desktop environment), then install custom splashscreen.
|
||||
echo -e "\e[96mCheck plymouth installation ...\e[0m" | tee -a $logfile
|
||||
if command_exists plymouth; then
|
||||
THEME_DIR="/usr/share/plymouth/themes"
|
||||
echo -e "\e[90mSplashscreen: Checking themes directory.\e[0m" | tee -a $logfile
|
||||
if [ -d $THEME_DIR ]; then
|
||||
echo -e "\e[90mSplashscreen: Create theme directory if not exists.\e[0m" | tee -a $logfile
|
||||
if [ ! -d $THEME_DIR/MagicMirror ]; then
|
||||
sudo mkdir $THEME_DIR/MagicMirror
|
||||
fi
|
||||
|
||||
if sudo cp ~/MagicMirror/splashscreen/splash.png $THEME_DIR/MagicMirror/splash.png && sudo cp ~/MagicMirror/splashscreen/MagicMirror.plymouth $THEME_DIR/MagicMirror/MagicMirror.plymouth && sudo cp ~/MagicMirror/splashscreen/MagicMirror.script $THEME_DIR/MagicMirror/MagicMirror.script; then
|
||||
echo
|
||||
if [ "$(which plymouth-set-default-theme)." != "." ]; then
|
||||
if sudo plymouth-set-default-theme -R MagicMirror; then
|
||||
echo -e "\e[92mSplashscreen: Changed theme to MagicMirror successfully.\e[0m" | tee -a $logfile
|
||||
else
|
||||
echo -e "\e[91mSplashscreen: Couldn't change theme to MagicMirror!\e[0m" | tee -a $logfile
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo -e "\e[91mSplashscreen: Copying theme failed!\e[0m" | tee -a $logfile
|
||||
fi
|
||||
else
|
||||
echo -e "\e[91mSplashscreen: Themes folder doesn't exist!\e[0m" | tee -a $logfile
|
||||
fi
|
||||
else
|
||||
echo -e "\e[91mUnable to clone MagicMirror."
|
||||
exit;
|
||||
echo -e "\e[93mplymouth is not installed.\e[0m" | tee -a $logfile
|
||||
fi
|
||||
|
||||
cd ~/MagicMirror || exit
|
||||
echo -e "\e[96mInstalling dependencies ...\e[90m"
|
||||
if npm install; then
|
||||
echo -e "\e[92mDependencies installation Done!\e[0m"
|
||||
# Use pm2 control like a service MagicMirror
|
||||
read -p "Do you want use pm2 for auto starting of your MagicMirror (y/N)?" choice
|
||||
if [[ $choice =~ ^[Yy]$ ]]; then
|
||||
echo install and setup pm2 | tee -a $logfile
|
||||
# assume pm2 will be found on the path
|
||||
pm2cmd=pm2
|
||||
# check to see if already installed
|
||||
pm2_installed=$(which $pm2cmd)
|
||||
up=""
|
||||
if [ $mac == 'Darwin' ]; then
|
||||
up="--unsafe-perm"
|
||||
launchctl=launchctl
|
||||
launchctl_path=$(which $launchctl)
|
||||
`export PATH=$PATH:${launchctl_path%/$launchctl}`
|
||||
fi
|
||||
# check to see if already installed
|
||||
pm2_installed=$(which $pm2cmd)
|
||||
if [ "$pm2_installed." != "." ]; then
|
||||
# does it work?
|
||||
pm2_fails=$(pm2 list | grep -i -m 1 "App Name" | wc -l )
|
||||
if [ $pm2_fails != 1 ]; then
|
||||
# uninstall it
|
||||
echo pm2 installed, but does not work, uninstalling >> $logfile
|
||||
sudo npm uninstall $up -g pm2 >> $logfile
|
||||
# force reinstall
|
||||
pm2_installed=
|
||||
fi
|
||||
fi
|
||||
# if not installed
|
||||
if [ "$pm2_installed." == "." ]; then
|
||||
# install it.
|
||||
echo pm2 not installed, installing >>$logfile
|
||||
result=$(sudo npm install $up -g pm2 2>&1)
|
||||
echo pm2 install result $result >>$logfile
|
||||
# if this is a mac
|
||||
if [ $mac == 'Darwin' ]; then
|
||||
echo this is a mac, fixup for path >>$logfile
|
||||
# get the location of pm2 install
|
||||
# parse the npm install output to get the command
|
||||
pm2cmd=`echo $result | awk -F - '{print $1}' | tr -d '[:space:]'`
|
||||
c='/pm2'
|
||||
# get the path only
|
||||
echo ${pm2cmd%$c} >installers/pm2path
|
||||
fi
|
||||
fi
|
||||
echo get the pm2 platform specific startup command >>$logfile
|
||||
# get the platform specific pm2 startup command
|
||||
v=$($pm2cmd startup | tail -n 1)
|
||||
if [ $mac != 'Darwin' ]; then
|
||||
# check to see if we can get the OS package name (Ubuntu)
|
||||
if [ $(which lsb_release| wc -l) >0 ]; then
|
||||
# fix command
|
||||
# if ubuntu 18.04, pm2 startup gets something wrong
|
||||
if [ $(lsb_release -r | grep -m1 18.04 | wc -l) > 0 ]; then
|
||||
v=$(echo $v | sed 's/\/bin/\/bin:\/bin/')
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
echo startup command = $v >>$logfile
|
||||
# execute the command returned
|
||||
$v 2>&1 >>$logfile
|
||||
echo pm2 startup command done >>$logfile
|
||||
# is this is mac
|
||||
# need to fix pm2 startup, only on catalina
|
||||
if [ $mac == 'Darwin' ];then
|
||||
if [ $(sw_vers -productVersion | head -c 6) == '10.15.' ]; then
|
||||
# only do if the faulty tag is present (pm2 may fix this, before the script is fixed)
|
||||
if [ $(grep -m 1 UserName /Users/$USER/Library/LaunchAgents/pm2.$USER.plist | wc -l) -eq 1 ]; then
|
||||
# copy the pm2 startup file config
|
||||
cp /Users/$USER/Library/LaunchAgents/pm2.$USER.plist .
|
||||
# edit out the UserName key/value strings
|
||||
sed -e '/UserName/{N;d;}' pm2.$USER.plist > pm2.$USER.plist.new
|
||||
# copy the file back
|
||||
sudo cp pm2.$USER.plist.new /Users/$USER/Library/LaunchAgents/pm2.$USER.plist
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# if the user is no pi, we have to fixup the pm2 json file
|
||||
echo configure the pm2 config file for MagicMirror >>$logfile
|
||||
if [ "$USER" != "pi" ]; then
|
||||
echo the user is not pi >>$logfile
|
||||
# go to the installers folder`
|
||||
cd installers
|
||||
# edit the startup script for the right user
|
||||
echo change mm.sh >>$logfile
|
||||
if [ ! -e mm_temp.sh ]; then
|
||||
echo save copy of mm.sh >> $logfile
|
||||
cp mm.sh mm_temp.sh
|
||||
fi
|
||||
if [ $(grep pi mm_temp.sh | wc -l) -gt 0 ]; then
|
||||
echo change hard coded pi username >> $logfile
|
||||
sed 's/pi/'$USER'/g' mm_temp.sh >mm.sh
|
||||
else
|
||||
echo change relative home path to hard coded path >> $logfile
|
||||
hf=$(echo $HOME |sed 's/\//\\\//g')
|
||||
sed 's/\~/'$hf'/g' mm_temp.sh >mm.sh
|
||||
fi
|
||||
# edit the pms config file for the right user
|
||||
echo change $PM2_FILE >>$logfile
|
||||
sed 's/pi/'$USER'/g' $PM2_FILE > pm2_MagicMirror_new.json
|
||||
# make sure to use the updated file
|
||||
PM2_FILE=pm2_MagicMirror_new.json
|
||||
# if this is a mac
|
||||
if [ $mac == 'Darwin' ]; then
|
||||
# copy the path file to the system paths list
|
||||
sudo cp ./pm2path /etc/paths.d
|
||||
# change the name of the home path for mac
|
||||
sed 's/home/Users/g' $PM2_FILE > pm2_MagicMirror_new1.json
|
||||
# make sure to use the updated file
|
||||
PM2_FILE=pm2_MagicMirror_new1.json
|
||||
fi
|
||||
echo now using this config file $PM2_FILE >>$logfile
|
||||
# go back one cd level
|
||||
cd - >/dev/null
|
||||
fi
|
||||
echo start MagicMirror via pm2 now >>$logfile
|
||||
# tell pm2 to start the app defined in the config file
|
||||
$pm2cmd start $HOME/MagicMirror/installers/$PM2_FILE
|
||||
# tell pm2 to save that configuration, for start at boot
|
||||
echo save MagicMirror pm2 config now >>$logfile
|
||||
$pm2cmd save
|
||||
pm2setup=$true
|
||||
fi
|
||||
# Disable Screensaver
|
||||
choice=n
|
||||
read -p "Do you want to disable the screen saver? (y/N)?" choice
|
||||
if [[ $choice =~ ^[Yy]$ ]]; then
|
||||
# if this is a mac
|
||||
if [ $mac == 'Darwin' ]; then
|
||||
# get the current setting
|
||||
setting=$(defaults -currentHost read com.apple.screensaver idleTime)
|
||||
# if its on
|
||||
if [ $setting != 0 ] ; then
|
||||
# turn it off
|
||||
echo disable screensaver via mac profile >> $logfile
|
||||
defaults -currentHost write com.apple.screensaver idleTime 0
|
||||
else
|
||||
echo mac profile screen saver already disabled >> $logfile
|
||||
fi
|
||||
else
|
||||
# find out if some screen saver running
|
||||
|
||||
# get just the running processes and args
|
||||
# just want the program name (1st token)
|
||||
# find the 1st with 'saver' in it (should only be one)
|
||||
# parse with path char, get the last field ( the actual pgm name)
|
||||
|
||||
screen_saver_running=$(ps -A -o args | awk '{print $1}' | grep -m1 [s]aver | awk -F\/ '{print $NF}');
|
||||
|
||||
# if we found something
|
||||
if [ "$screen_saver_running." != "." ]; then
|
||||
# some screensaver running
|
||||
case "$screen_saver_running" in
|
||||
mate-screensaver) echo 'mate screen saver' >>$logfile
|
||||
#killall mate-screensaver >/dev/null 2>&1
|
||||
#$ms -d >/dev/null 2>&1
|
||||
gsettings set org.mate.screensaver lock-enabled false 2>/dev/null
|
||||
gsettings set org.mate.screensaver idle-activation-enabled false 2>/dev/null
|
||||
gsettings set org.mate.screensaver lock_delay 0 2>/dev/null
|
||||
echo " $screen_saver_running disabled" >> $logfile
|
||||
DISPLAY=:0 mate-screensaver >/dev/null 2>&1 &
|
||||
;;
|
||||
gnome-screensaver) echo 'gnome screen saver' >>$logfile
|
||||
gnome_screensaver-command -d >/dev/null 2>&1
|
||||
echo " $screen_saver_running disabled" >> $logfile
|
||||
;;
|
||||
xscreensaver) echo 'xscreensaver running' | tee -a $logfile
|
||||
if [ $(grep -m1 'mode:' ~/.xscreensaver | awk '{print $2}') != 'off' ]; then
|
||||
sed -i 's/$xsetting/mode: off/' ~/.xscreensaver
|
||||
echo " xscreensaver set to off" >> $logfile
|
||||
else
|
||||
echo " xscreensaver already disabled" >> $logfile
|
||||
fi
|
||||
;;
|
||||
gsd-screensaver | gsd-screensaver-proxy)
|
||||
setting=$(gsettings get org.gnome.desktop.screensaver lock-enabled)
|
||||
setting1=$(gsettings get org.gnome.desktop.session idle-delay)
|
||||
if [ "$setting $setting1" != 'false uint32 0' ]; then
|
||||
echo disable screensaver via gsettings was $setting and $setting1>> $logfile
|
||||
gsettings set org.gnome.desktop.screensaver lock-enabled false
|
||||
gsettings set org.gnome.desktop.screensaver idle-activation-enabled false
|
||||
gsettings set org.gnome.desktop.session idle-delay 0
|
||||
else
|
||||
echo gsettings screen saver already disabled >> $logfile
|
||||
fi
|
||||
;;
|
||||
*) echo "some other screensaver $screen_saver_running" found | tee -a $logfile
|
||||
echo "please configure it manually" | tee -a $logfile
|
||||
;;
|
||||
esac
|
||||
elif [ -e "/etc/lightdm/lightdm.conf" ]; then
|
||||
# if screen saver NOT already disabled?
|
||||
if [ $(grep 'xserver-command=X -s 0 -dpms' /etc/lightdm/lightdm.conf | wc -l) == 0 ]; then
|
||||
echo install screensaver via lightdm.conf >> $logfile
|
||||
sudo sed -i '/^\[Seat:\*\]/a xserver-command=X -s 0 -dpms' /etc/lightdm/lightdm.conf
|
||||
else
|
||||
echo screensaver via lightdm already disabled >> $logfile
|
||||
fi
|
||||
elif [ $(which gsettings | wc -l) == 1 ]; then
|
||||
setting=$(gsettings get org.gnome.desktop.screensaver lock-enabled)
|
||||
setting1=$(gsettings get org.gnome.desktop.session idle-delay)
|
||||
if [ "$setting $setting1" != 'false uint32 0' ]; then
|
||||
echo disable screensaver via gsettings was $setting and $setting1>> $logfile
|
||||
gsettings set org.gnome.desktop.screensaver lock-enabled false
|
||||
gsettings set org.gnome.desktop.screensaver idle-activation-enabled false
|
||||
gsettings set org.gnome.desktop.session idle-delay 0
|
||||
else
|
||||
echo gsettings screen saver already disabled >> $logfile
|
||||
fi
|
||||
elif [ -d "/etc/xdg/lxsession" ]; then
|
||||
currently_set=$(grep -m1 '\-dpms' /etc/xdg/lxsession/LXDE-pi/autostart)
|
||||
if [ "$currently_set." == "." ]; then
|
||||
echo disable screensaver via lxsession >> $logfile
|
||||
# turn it off for the future
|
||||
sudo su -c "echo -e '@xset s noblank\n@xset s off\n@xset -dpms' >> /etc/xdg/lxsession/LXDE-pi/autostart"
|
||||
# turn it off now
|
||||
export DISPLAY=:0; xset s noblank;xset s off;xset -dpms
|
||||
else
|
||||
echo lxsession screen saver already disabled >> $logfile
|
||||
fi
|
||||
else
|
||||
echo " "
|
||||
echo -e "unable to disable screen saver, /etc/xdg/lxsession does not exist" | tee -a $logfile
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
echo " "
|
||||
if [ $pm2setup -eq $true ]; then
|
||||
rmessage="pm2 start MagicMirror"
|
||||
else
|
||||
echo -e "\e[91mUnable to install dependencies!"
|
||||
exit;
|
||||
rmessage="DISPLAY=:0 npm start"
|
||||
fi
|
||||
echo -e "\e[92mWe're ready! Run \e[1m\e[97m$rmessage\e[0m\e[92m from the ~/MagicMirror directory to start your MagicMirror.\e[0m" | tee -a $logfile
|
||||
|
||||
echo " "
|
||||
echo -e "\e[92mWe're ready! Run \e[1m\e[97mDISPLAY=:0 npm start\e[0m\e[92m from the ~/MagicMirror directory to start your MagicMirror.\e[0m"
|
||||
echo " "
|
||||
echo " "
|
||||
|
||||
date +"install completed - %a %b %e %H:%M:%S %Z %Y" >>$logfile
|
||||
|
101
installers/screensaveroff.sh
Executable file
101
installers/screensaveroff.sh
Executable file
@@ -0,0 +1,101 @@
|
||||
#/bin/bash
|
||||
logfile=~/screensaver.log
|
||||
mac=$(uname -s)
|
||||
|
||||
if [ $mac == 'Darwin' ]; then
|
||||
setting=$(defaults -currentHost read com.apple.screensaver idleTime)
|
||||
if [ $setting != 0 ] ; then
|
||||
echo disable screensaver via mac profile >> $logfile
|
||||
defaults -currentHost write com.apple.screensaver idleTime 0
|
||||
else
|
||||
echo mac profile screen saver already disabled >> $logfile
|
||||
fi
|
||||
else
|
||||
# find out if some screen saver running
|
||||
|
||||
# get just the running processes and args
|
||||
# just want the program name
|
||||
# find the 1st with 'saver' in it (should only be one)
|
||||
# if the process name is a path, parse it and get the last field ( the actual pgm name)
|
||||
|
||||
screen_saver_running=$(ps -A -o args | awk '{print $1}' | grep -m1 [s]aver | awk -F\/ '{print $NF}');
|
||||
|
||||
# if we found something
|
||||
if [ "$screen_saver_running." != "." ]; then
|
||||
# some screensaver running
|
||||
case "$screen_saver_running" in
|
||||
mate-screensaver) echo 'mate screen saver' >>$logfile
|
||||
#killall mate-screensaver >/dev/null 2>&1
|
||||
#ms=$(which mate-screensaver-command)
|
||||
#$ms -d >/dev/null 2>&1
|
||||
gsettings set org.mate.screensaver lock-enabled false 2>/dev/null
|
||||
gsettings set org.mate.screensaver idle-activation-enabled false 2>/dev/null
|
||||
gsettings set org.mate.screensaver lock_delay 0 2>/dev/null
|
||||
echo " $screen_saver_running disabled" >> $logfile
|
||||
DISPLAY=:0 mate-screensaver >/dev/null 2>&1 &
|
||||
;;
|
||||
gnome-screensaver) echo 'gnome screen saver' >>$logfile
|
||||
gnome_screensaver-command -d >/dev/null 2>&1
|
||||
echo " $screen_saver_running disabled" >> $logfile
|
||||
;;
|
||||
xscreensaver) echo 'xscreensaver running' | tee -a $logfile
|
||||
if [ $(grep -m1 'mode:' ~/.xscreensaver | awk '{print $2}') != 'off' ]; then
|
||||
sed -i 's/$xsetting/mode: off/' ~/.xscreensaver
|
||||
echo " xscreensaver set to off" >> $logfile
|
||||
else
|
||||
echo " xscreensaver already disabled" >> $logfile
|
||||
fi
|
||||
;;
|
||||
gsd-screensaver | gsd-screensaver-proxy)
|
||||
setting=$(gsettings get org.gnome.desktop.screensaver lock-enabled)
|
||||
setting1=$(gsettings get org.gnome.desktop.session idle-delay)
|
||||
if [ "$setting $setting1" != 'false uint32 0' ]; then
|
||||
echo disable screensaver via gsettings was $setting and $setting1>> $logfile
|
||||
gsettings set org.gnome.desktop.screensaver lock-enabled false
|
||||
gsettings set org.gnome.desktop.screensaver idle-activation-enabled false
|
||||
gsettings set org.gnome.desktop.session idle-delay 0
|
||||
else
|
||||
echo gsettings screen saver already disabled >> $logfile
|
||||
fi
|
||||
;;
|
||||
*) echo "some other screensaver $screen_saver_running" found | tee -a $logfile
|
||||
echo "please configure it manually" | tee -a $logfile
|
||||
;;
|
||||
esac
|
||||
elif [ -e "/etc/lightdm/lightdm.conf" ]; then
|
||||
# if screen saver NOT already disabled?
|
||||
if [ $(grep 'xserver-command=X -s 0 -dpms' /etc/lightdm/lightdm.conf | wc -l) == 0 ]; then
|
||||
echo install screensaver via lightdm.conf >> $logfile
|
||||
sudo sed -i '/^\[Seat:\*\]/a xserver-command=X -s 0 -dpms' /etc/lightdm/lightdm.conf
|
||||
#sudo cp _myconf /etc/lightdm/lightdm.conf
|
||||
#rm _myconf >/dev/null
|
||||
else
|
||||
echo screensaver via lightdm already disabled >> $logfile
|
||||
fi
|
||||
elif [ $(which gsettings | wc -l) == 1 ]; then
|
||||
setting=$(gsettings get org.gnome.desktop.screensaver lock-enabled)
|
||||
setting1=$(gsettings get org.gnome.desktop.session idle-delay)
|
||||
if [ "$setting $setting1" != 'false uint32 0' ]; then
|
||||
echo disable screensaver via gsettings was $setting and $setting1>> $logfile
|
||||
gsettings set org.gnome.desktop.screensaver lock-enabled false
|
||||
gsettings set org.gnome.desktop.screensaver idle-activation-enabled false
|
||||
gsettings set org.gnome.desktop.session idle-delay 0
|
||||
else
|
||||
echo gsettings screen saver already disabled >> $logfile
|
||||
fi
|
||||
elif [ -d "/etc/xdg/lxsession" ]; then
|
||||
currently_set=$(grep -m1 '\-dpms' /etc/xdg/lxsession/LXDE-pi/autostart)
|
||||
if [ "$currently_set." == "." ]; then
|
||||
echo disable screensaver via lxsession >> $logfile
|
||||
# turn it off for the future
|
||||
sudo su -c "echo -e '@xset s noblank\n@xset s off\n@xset -dpms' >> /etc/xdg/lxsession/LXDE-pi/autostart"
|
||||
# turn it off now
|
||||
export DISPLAY=:0; xset s noblank;xset s off;xset -dpms
|
||||
else
|
||||
echo lxsession screen saver already disabled >> $logfile
|
||||
fi
|
||||
else
|
||||
echo " "
|
||||
echo -e "unable to disable screen saver, /etc/xdg/lxsession does not exist" | tee >>$logfile
|
||||
fi
|
||||
fi
|
361
installers/upgrade-script.sh
Executable file
361
installers/upgrade-script.sh
Executable file
@@ -0,0 +1,361 @@
|
||||
#!/bin/bash
|
||||
# only DO npm installs when flag is set to 1
|
||||
# test when set to 0
|
||||
true=1
|
||||
false=0
|
||||
doinstalls=$false
|
||||
force=$false
|
||||
justActive=$true
|
||||
test_run=$true
|
||||
stashed=$false
|
||||
keyFile=package.json
|
||||
forced_arch=
|
||||
git_active_lock='./.git/index.lock'
|
||||
lf=$'\n'
|
||||
git_user_name=
|
||||
git_user_email=
|
||||
|
||||
trim() {
|
||||
local var="$*"
|
||||
# remove leading whitespace characters
|
||||
var="${var#"${var%%[![:space:]]*}"}"
|
||||
# remove trailing whitespace characters
|
||||
var="${var%"${var##*[![:space:]]}"}"
|
||||
echo -n "$var"
|
||||
}
|
||||
# is this a mac
|
||||
mac=$(uname -s)
|
||||
# get the processor architecture
|
||||
arch=$(uname -m)
|
||||
if [ $mac == 'Darwin' ]; then
|
||||
cmd=greadlink
|
||||
else
|
||||
cmd=readlink
|
||||
fi
|
||||
if [ -d ~/MagicMirror ]; then
|
||||
|
||||
# put the log where the script is located
|
||||
logdir=$(dirname $($cmd -f "$0"))
|
||||
# if the script was execute from the web
|
||||
if [[ $logdir != *"MagicMirror/installers"* ]]; then
|
||||
# use the MagicMirror/installers folder
|
||||
cd ~/MagicMirror/installers >/dev/null
|
||||
logdir=$(pwd)
|
||||
cd - >/dev/null
|
||||
fi
|
||||
logfile=$logdir/upgrade.log
|
||||
echo the log will be $logfile
|
||||
echo >>$logfile
|
||||
date +"Upgrade started - %a %b %e %H:%M:%S %Z %Y" >>$logfile
|
||||
echo system is $(uname -a) >> $logfile
|
||||
echo the os is $(lsb_release -a) >> $logfile
|
||||
|
||||
# because of how its executed from the web, p0 gets overlayed with parm
|
||||
# check to see if a parm was passed .. easy apply without editing
|
||||
p0=$0
|
||||
# if not 'bash', and some parm specified
|
||||
if [ $0 != 'bash' -a "$1." != "." ]; then
|
||||
# then executed locally
|
||||
# get the parm
|
||||
p0=$1
|
||||
fi
|
||||
# lowercase it.. watch out, mac stuff doesn't work with tr, etc
|
||||
p0=$(echo $p0 | cut -c 1-5 | awk '{print tolower($0)}' )
|
||||
if [ $p0 == 'apply' ]; then
|
||||
echo user requested to apply changes >>$logfile
|
||||
doinstalls=$true
|
||||
test_run=$false
|
||||
elif [ $p0 == 'force' ]; then
|
||||
echo user requested to force apply changes >>$logfile
|
||||
doinstalls=$true
|
||||
force=$true
|
||||
test_run=$false
|
||||
fi
|
||||
|
||||
if [ $test_run == $true ]; then
|
||||
echo doing test run = true | tee -a $logfile
|
||||
else
|
||||
echo doing test run = false | tee -a $logfile
|
||||
fi
|
||||
|
||||
# if we want just the modules listed in config.js now
|
||||
if [ $justActive == $true ]; then
|
||||
if [ ! -f ~/MagicMirror/installers/dumpactivemodules.js ]; then
|
||||
echo downloading dumpactivemodules script >> $logfile
|
||||
curl -sL https://www.dropbox.com/s/wwe6bfg2lcjmj43/dumpactivemodules.js?dl=0 > ~/MagicMirror/installers/dumpactivemodules.js
|
||||
fi
|
||||
fi
|
||||
echo update log will be in $logfile
|
||||
# used for parsing the array of module names
|
||||
SAVEIFS=$IFS # Save current IFS
|
||||
IFS=$'\n'
|
||||
|
||||
echo | tee -a $logfile
|
||||
# if the git lock file exists and git is not running
|
||||
if [ -f git_active_lock ]; then
|
||||
# check to see if git is actually running
|
||||
git_running=`ps -ef | grep git | grep -v color | grep -v 'grep git' | wc -l`
|
||||
# if not running
|
||||
if [ git_running == $false ]; then
|
||||
# clean up the dangling lock file
|
||||
echo erasing abandonded git lock file >> $logfile
|
||||
rm git_active_lock >/dev/null 2>&1
|
||||
else
|
||||
# git IS running, we can't proceed
|
||||
echo it appears another instance of git is running | tee -a $logfile
|
||||
# if this is an actual run
|
||||
if [ $doinstalls == $true ]; then
|
||||
# force it back to test run
|
||||
doinstalls = $false
|
||||
test_run=$true
|
||||
echo forcing test run mode | tee -a $logfile
|
||||
echo please resolve git running already and start the update again | tee -a $logfile
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# change to MagicMirror folder
|
||||
cd ~/MagicMirror
|
||||
|
||||
# save custom.css
|
||||
cd css
|
||||
echo "saving custom.css" | tee -a $logfile
|
||||
cp -p custom.css save_custom.css
|
||||
cd - >/dev/null
|
||||
save_alias=$(alias git 2>/dev/null)
|
||||
lang=$(locale | grep LANGUAGE | awk -F= '{print $2}')
|
||||
# make sure git respones are in english, so code works
|
||||
if [ "$lang." != "en_US.UTF-8." ]; then
|
||||
echo not english or locale not set, set git alias >>$logfile
|
||||
if [ "$LC_ALL." == "." ]; then
|
||||
alias git='LANGUAGE=en_US.UTF-8 git' >>$logfile
|
||||
else
|
||||
alias git='LC_ALL=en_US.UTF-8 git' >>$logfile
|
||||
fi
|
||||
#alias >>$logfile
|
||||
fi
|
||||
# get the git remote name
|
||||
remote=$(git remote 2>/dev/null | awk '{print $1}')
|
||||
|
||||
# if remote name set
|
||||
if [ "$remote." != "." ]; then
|
||||
|
||||
echo remote name = $remote >>$logfile
|
||||
|
||||
# get the local and remote package.json versions
|
||||
local_version=$(grep -m1 version package.json | awk -F\" '{print $4}')
|
||||
remote_version=$(curl -s https://raw.githubusercontent.com/MichMich/MagicMirror/master/package.json | grep -m1 version | awk -F\" '{print $4}')
|
||||
|
||||
# only change if they are different
|
||||
if [ "$local_version." != "$remote_version." -o $force == $true -o $test_run == $true ]; then
|
||||
echo upgrading from version $local_version to $remote_version | tee -a $logfile
|
||||
|
||||
# get the latest upgrade
|
||||
echo fetching latest revisions | tee -a $logfile
|
||||
git fetch $remote >/dev/null
|
||||
rc=$?
|
||||
echo git fetch rc=$rc >>$logfile
|
||||
if [ $rc -eq 0 ]; then
|
||||
|
||||
# need to get the current branch
|
||||
current_branch=$(git branch | grep "*" | awk '{print $2}')
|
||||
echo current branch = $current_branch >>$logfile
|
||||
|
||||
git status 2>&1 >>$logfile
|
||||
|
||||
# get the names of the files that are different locally
|
||||
diffs=$(git status 2>&1 | grep modified | awk -F: '{print $2}')
|
||||
|
||||
# split names into an array
|
||||
diffs=($diffs) # split to array $diffs
|
||||
|
||||
# if there are different files (array size greater than zero)
|
||||
if [ ${#diffs[@]} -gt 0 ]; then
|
||||
package_lock=0
|
||||
echo there are "${#diffs[@]}" local files that are different than the master repo | tee -a $logfile
|
||||
echo | tee -a $logfile
|
||||
for file in "${diffs[@]}"
|
||||
do
|
||||
echo "$file" | tee -a $logfile
|
||||
if [ $(echo $file | grep '\-lock.json$' | wc -l) -eq 1 ]; then
|
||||
package_lock=$true
|
||||
fi
|
||||
done
|
||||
echo | tee -a $logfile
|
||||
if [ $package_lock -eq 1 ]; then
|
||||
echo "any *-lock.json files do not need to be saved"
|
||||
fi
|
||||
read -p "do you want to save these files for later (Y/n)?" choice
|
||||
echo save/restore files selection = $choice >> $logfile
|
||||
if [[ $choice =~ ^[Yy]$ ]]; then
|
||||
git_user=$(git config --global --get user.email)
|
||||
if [ "git_user." == "." ]; then
|
||||
git_user_name="-c user.name=upgrade_script"
|
||||
git_user_email="-c user.email=script@upgrade.com"
|
||||
fi
|
||||
git git_user_name git_user_email stash >>$logfile
|
||||
stashed=$true
|
||||
else
|
||||
for file in "${diffs[@]}"
|
||||
do
|
||||
f="$(trim "$file")"
|
||||
echo restoring $f from repo >> $logfile
|
||||
if [ $test_run == $false ]; then
|
||||
git checkout HEAD -- $f | tee -a $logfile
|
||||
else
|
||||
echo skipping restore for $f, doing test run | tee -a $logfile
|
||||
fi
|
||||
done
|
||||
fi
|
||||
else
|
||||
echo no files different from github version >> $logfile
|
||||
fi
|
||||
|
||||
# lets test merge, in memory, no changes to working directory or local repo
|
||||
test_merge_output=$(git merge-tree `git merge-base $current_branch HEAD` HEAD $current_branch | grep "^<<<<<<<\|changed in both")
|
||||
echo "test merge result rc='$test_merge_output' , if empty, no conflicts" >> $logfile
|
||||
|
||||
# if there were no conflicts reported
|
||||
if [ "$test_merge_output." == "." ]; then
|
||||
|
||||
if [ $test_run == $false ]; then
|
||||
# go ahead and merge now
|
||||
echo "executing merge, apply specified" >> $logfile
|
||||
# get the text output of merge
|
||||
merge_output=$(git merge $remote/$current_branch 2>&1)
|
||||
# and its return code
|
||||
merge_result=$?
|
||||
# make any long line readable
|
||||
merge_output=$(echo $merge_output | tr '|' '\n'| sed "s/create/\\${lf}create/g" | sed "s/mode\ change/\\${lf}mode\ change/g")
|
||||
echo -e "merge result rc= $merge_result\n $merge_output">> $logfile
|
||||
else
|
||||
echo "skipping merge, only test run" >> $logfile
|
||||
merge_output=''
|
||||
merge_result=0
|
||||
fi
|
||||
|
||||
# if no merge errors
|
||||
if [ $merge_result == 0 ]; then
|
||||
# some updates applied
|
||||
if [ "$merge_output." != 'Already up to date.' -o $test_run == $true ]; then
|
||||
# update any dependencies for base
|
||||
if [ $doinstalls == $true ]; then
|
||||
# if this is a pi zero
|
||||
echo processor architecture is $arch >> $logfile
|
||||
if [ "$arch" == "armv6l" ]; then
|
||||
# force to look like pi 2
|
||||
echo forcing architecture armv7l >>$logfile
|
||||
forced_arch='--arch=armv7l'
|
||||
fi
|
||||
echo "updating MagicMirror runtime, please wait" | tee -a $logfile
|
||||
npm install $forced_arch 2>&1 | tee -a $logfile
|
||||
done_update=`date +"completed - %a %b %e %H:%M:%S %Z %Y"`
|
||||
echo npm install $done_update on base >> $ logfile
|
||||
fi
|
||||
# process updates for modules after base changed
|
||||
cd modules
|
||||
if [ $justActive == $true ]; then
|
||||
# get the list of ACTIVE modules with package.json files
|
||||
mtype=active
|
||||
modules=$(node ../installers/dumpactivemodules.js)
|
||||
else
|
||||
# get the list of INSTALLED modules with package.json files
|
||||
mtype=installed
|
||||
modules=$(find -maxdepth 2 -name 'package.json' -printf "%h\n" | cut -d'/' -f2 )
|
||||
fi
|
||||
modules=($modules) # split to array $modules
|
||||
|
||||
# if the array has entries in it
|
||||
if [ ${#modules[@]} -gt 0 ]; then
|
||||
echo >> $logfile
|
||||
echo "processing dependency changes for $mtype modules with package.json files" | tee -a $logfile
|
||||
echo
|
||||
for module in "${modules[@]}"
|
||||
do
|
||||
echo "processing for module" $module please wait | tee -a $logfile
|
||||
echo '----------------------------------' | tee -a $logfile
|
||||
# change to that directory
|
||||
cd $module
|
||||
# process its dependencies
|
||||
if [ $doinstalls == $true ]; then
|
||||
npm install $forced_arch 2>&1| tee -a $logfile
|
||||
else
|
||||
echo skipped processing for $module, doing test run | tee -a $logfile
|
||||
fi
|
||||
# return to modules folder
|
||||
cd .. >/dev/null
|
||||
echo "processing complete for module" $module | tee -a $logfile
|
||||
echo
|
||||
done
|
||||
else
|
||||
echo "no modules found needing npm refresh" | tee -a $logfile
|
||||
fi
|
||||
# return to Magic Mirror folder
|
||||
cd .. >/dev/null
|
||||
else
|
||||
echo "no changes detected for modules, skipping " | tee -a $logfile
|
||||
fi
|
||||
else
|
||||
echo there were merge errors | tee -a $logfile
|
||||
echo $merge_output | tee -a %logfile
|
||||
echo you should examine and resolve them | tee -a $logfile
|
||||
echo using the command git log --oneline --decorate | tee -a $logfile
|
||||
git log --oneline --decorate | tee -a $logfile
|
||||
fi
|
||||
else
|
||||
echo "there are merge conflicts to be resolved, no changes have been applied" | tee -a $logfile
|
||||
echo $test_merge_output | tee -a $logfile
|
||||
fi
|
||||
else
|
||||
echo "MagicMirror git fetch failed" | tee -a $logfile
|
||||
fi
|
||||
else
|
||||
echo "local version $local_version already same as master $remote_version" | tee -a $logfile
|
||||
fi
|
||||
else
|
||||
echo "Unable to determine upstream git repository" | tee -a $logfile
|
||||
fi
|
||||
# should be in MagicMirror base
|
||||
cd css
|
||||
# restore custom.css
|
||||
echo "restoring custom.css" | tee -a $logfile
|
||||
cp -p save_custom.css custom.css
|
||||
rm save_custom.css
|
||||
cd - >/dev/null
|
||||
if [ "$lang." != "en_US.UTF-8." ]; then
|
||||
if [ "$save_alias." != "." ]; then
|
||||
echo restoring git alias >>$logfile
|
||||
$save_alias >/dev/null
|
||||
else
|
||||
echo removing git alias >>$logfile
|
||||
unalias git >/dev/null
|
||||
fi
|
||||
fi
|
||||
IFS=$SAVEIFS # Restore IFS
|
||||
|
||||
if [ $stashed == $true ]; then
|
||||
if [ $test_run == $true ]; then
|
||||
echo test run, restoring files stashed | tee -a $logfile
|
||||
git git_user_name git_user_email stash pop >> $logfile
|
||||
else
|
||||
echo we stashed a set of files that appear changed from the latest repo versions. you should review them | tee -a $logfile
|
||||
git stash show --name-only > installers/stashed_files
|
||||
echo see installers/stashed_files for the list
|
||||
echo
|
||||
echo you can use git checkout "stash@{0}" -- filename to extract one file from the stash
|
||||
echo
|
||||
echo or git stash pop to restore them all
|
||||
echo
|
||||
echo WARNING..
|
||||
echo WARNING.. either will overlay the file just installed by the update
|
||||
echo WARNING..
|
||||
fi
|
||||
fi
|
||||
# return to original folder
|
||||
cd - >/dev/null
|
||||
date +"Upgrade ended - %a %b %e %H:%M:%S %Z %Y" >>$logfile
|
||||
else
|
||||
echo It appears MagicMirror has not been installed on this system
|
||||
echo please run the installer, "raspberry.sh" first
|
||||
fi
|
||||
|
193
js/app.js
193
js/app.js
@@ -7,9 +7,33 @@
|
||||
|
||||
var fs = require("fs");
|
||||
var Server = require(__dirname + "/server.js");
|
||||
var Utils = require(__dirname + "/utils.js");
|
||||
var defaultModules = require(__dirname + "/../modules/default/defaultmodules.js");
|
||||
var path = require("path");
|
||||
|
||||
// Alias modules mentioned in package.js under _moduleAliases.
|
||||
require("module-alias/register");
|
||||
|
||||
// add timestamps in front of log messages
|
||||
require("console-stamp")(console, "HH:MM:ss.l");
|
||||
|
||||
// Get version number.
|
||||
global.version = JSON.parse(fs.readFileSync("package.json", "utf8")).version;
|
||||
console.log("Starting MagicMirror: v" + global.version);
|
||||
|
||||
// global absolute root path
|
||||
global.root_path = path.resolve(__dirname + "/../");
|
||||
|
||||
if (process.env.MM_CONFIG_FILE) {
|
||||
global.configuration_file = process.env.MM_CONFIG_FILE;
|
||||
}
|
||||
|
||||
// FIXME: Hotfix Pull Request
|
||||
// https://github.com/MichMich/MagicMirror/pull/673
|
||||
if (process.env.MM_PORT) {
|
||||
global.mmPort = 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) {
|
||||
@@ -30,28 +54,61 @@ var App = function() {
|
||||
*
|
||||
* argument callback function - The callback function.
|
||||
*/
|
||||
|
||||
var loadConfig = function(callback) {
|
||||
console.log("Loading config ...");
|
||||
var defaults = require(__dirname + "/defaults.js");
|
||||
var configFilename = path.resolve(__dirname + "/../config/config.js");
|
||||
|
||||
// For this check proposed to TestSuite
|
||||
// https://forum.magicmirror.builders/topic/1456/test-suite-for-magicmirror/8
|
||||
var configFilename = path.resolve(global.root_path + "/config/config.js");
|
||||
if (typeof(global.configuration_file) !== "undefined") {
|
||||
configFilename = path.resolve(global.configuration_file);
|
||||
}
|
||||
|
||||
try {
|
||||
fs.accessSync(configFilename, fs.F_OK);
|
||||
var c = require(configFilename);
|
||||
checkDeprecatedOptions(c);
|
||||
var config = Object.assign(defaults, c);
|
||||
callback(config);
|
||||
} catch (e) {
|
||||
console.error("WARNING! Could not find config. Please create one.");
|
||||
if (e.code === "ENOENT") {
|
||||
console.error(Utils.colors.error("WARNING! Could not find config file. Please create one. Starting with default configuration."));
|
||||
} else if (e instanceof ReferenceError || e instanceof SyntaxError) {
|
||||
console.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));
|
||||
} else {
|
||||
console.error(Utils.colors.error("WARNING! Could not load config file. Starting with default configuration. Error found: " + e));
|
||||
}
|
||||
callback(defaults);
|
||||
}
|
||||
};
|
||||
|
||||
var checkDeprecatedOptions = function(userConfig) {
|
||||
var deprecated = require(global.root_path + "/js/deprecated.js");
|
||||
var deprecatedOptions = deprecated.configs;
|
||||
|
||||
var usedDeprecated = [];
|
||||
|
||||
deprecatedOptions.forEach(function(option) {
|
||||
if (userConfig.hasOwnProperty(option)) {
|
||||
usedDeprecated.push(option);
|
||||
}
|
||||
});
|
||||
if (usedDeprecated.length > 0) {
|
||||
console.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.")
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/* loadModule(module)
|
||||
* Loads a specific module.
|
||||
*
|
||||
* argument module string - The name of the module (including subpath).
|
||||
*/
|
||||
var loadModule = function(module) {
|
||||
var loadModule = function(module, callback) {
|
||||
|
||||
var elements = module.split("/");
|
||||
var moduleName = elements[elements.length - 1];
|
||||
@@ -74,9 +131,24 @@ var App = function() {
|
||||
if (loadModule) {
|
||||
var Module = require(helperPath);
|
||||
var m = new Module();
|
||||
|
||||
if (m.requiresVersion) {
|
||||
console.log("Check MagicMirror version for node helper '" + moduleName + "' - Minimum version: " + m.requiresVersion + " - Current version: " + global.version);
|
||||
if (cmpVersions(global.version, m.requiresVersion) >= 0) {
|
||||
console.log("Version is ok!");
|
||||
} else {
|
||||
console.log("Version is incorrect. Skip module: '" + moduleName + "'");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m.setName(moduleName);
|
||||
m.setPath(path.resolve(moduleFolder));
|
||||
nodeHelpers.push(m);
|
||||
|
||||
m.loaded(callback);
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -85,20 +157,52 @@ var App = function() {
|
||||
*
|
||||
* argument module string - The name of the module (including subpath).
|
||||
*/
|
||||
var loadModules = function(modules) {
|
||||
var loadModules = function(modules, callback) {
|
||||
console.log("Loading module helpers ...");
|
||||
|
||||
for (var m in modules) {
|
||||
loadModule(modules[m]);
|
||||
}
|
||||
var loadNextModule = function() {
|
||||
if (modules.length > 0) {
|
||||
var nextModule = modules[0];
|
||||
loadModule(nextModule, function() {
|
||||
modules = modules.slice(1);
|
||||
loadNextModule();
|
||||
});
|
||||
} else {
|
||||
// All modules are loaded
|
||||
console.log("All module helpers loaded.");
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
console.log("All module helpers loaded.");
|
||||
loadNextModule();
|
||||
};
|
||||
|
||||
/* cmpVersions(a,b)
|
||||
* Compare two semantic version numbers and return the difference.
|
||||
*
|
||||
* argument a string - Version number a.
|
||||
* argument a string - Version number b.
|
||||
*/
|
||||
function cmpVersions(a, b) {
|
||||
var i, diff;
|
||||
var regExStrip0 = /(\.0+)+$/;
|
||||
var segmentsA = a.replace(regExStrip0, "").split(".");
|
||||
var segmentsB = b.replace(regExStrip0, "").split(".");
|
||||
var l = Math.min(segmentsA.length, segmentsB.length);
|
||||
|
||||
for (i = 0; i < l; i++) {
|
||||
diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10);
|
||||
if (diff) {
|
||||
return diff;
|
||||
}
|
||||
}
|
||||
return segmentsA.length - segmentsB.length;
|
||||
}
|
||||
|
||||
/* start(callback)
|
||||
* This methods starts the core app.
|
||||
* It loads the config, then it loads all modules.
|
||||
* When it"s done it executs the callback with the config as argument.
|
||||
* When it's done it executes the callback with the config as argument.
|
||||
*
|
||||
* argument callback function - The callback function.
|
||||
*/
|
||||
@@ -111,32 +215,67 @@ var App = function() {
|
||||
|
||||
for (var m in config.modules) {
|
||||
var module = config.modules[m];
|
||||
if (modules.indexOf(module.module) === -1) {
|
||||
if (modules.indexOf(module.module) === -1 && !module.disabled) {
|
||||
modules.push(module.module);
|
||||
}
|
||||
}
|
||||
|
||||
loadModules(modules);
|
||||
loadModules(modules, function() {
|
||||
var server = new Server(config, function(app, io) {
|
||||
console.log("Server started ...");
|
||||
|
||||
var server = new Server(config, function(app, io) {
|
||||
console.log("Server started ...");
|
||||
for (var h in nodeHelpers) {
|
||||
var nodeHelper = nodeHelpers[h];
|
||||
nodeHelper.setExpressApp(app);
|
||||
nodeHelper.setSocketIO(io);
|
||||
nodeHelper.start();
|
||||
}
|
||||
|
||||
for (var h in nodeHelpers) {
|
||||
var nodeHelper = nodeHelpers[h];
|
||||
nodeHelper.setExpressApp(app);
|
||||
nodeHelper.setSocketIO(io);
|
||||
nodeHelper.start();
|
||||
}
|
||||
|
||||
console.log("Sockets connected & modules started ...");
|
||||
|
||||
if (typeof callback === "function") {
|
||||
callback(config);
|
||||
}
|
||||
console.log("Sockets connected & modules started ...");
|
||||
|
||||
if (typeof callback === "function") {
|
||||
callback(config);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/* stop()
|
||||
* This methods stops the core app.
|
||||
* This calls each node_helper's STOP() function, if it exists.
|
||||
* Added to fix #1056
|
||||
*/
|
||||
this.stop = function() {
|
||||
for (var h in nodeHelpers) {
|
||||
var nodeHelper = nodeHelpers[h];
|
||||
if (typeof nodeHelper.stop === "function") {
|
||||
nodeHelper.stop();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Listen for SIGINT signal and call stop() function.
|
||||
*
|
||||
* Added to fix #1056
|
||||
* Note: this is only used if running `server-only`. Otherwise
|
||||
* this.stop() is called by app.on("before-quit"... in `electron.js`
|
||||
*/
|
||||
process.on("SIGINT", () => {
|
||||
console.log("[SIGINT] Received. Shutting down server...");
|
||||
setTimeout(() => { process.exit(0); }, 3000); // Force quit after 3 seconds
|
||||
this.stop();
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
/* We also need to listen to SIGTERM signals so we stop everything when we are asked to stop by the OS.
|
||||
*/
|
||||
process.on("SIGTERM", () => {
|
||||
console.log("[SIGTERM] Received. Shutting down server...");
|
||||
setTimeout(() => { process.exit(0); }, 3000); // Force quit after 3 seconds
|
||||
this.stop();
|
||||
process.exit(0);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = new App();
|
||||
module.exports = new App();
|
||||
|
66
js/class.js
66
js/class.js
@@ -4,15 +4,15 @@
|
||||
*/
|
||||
|
||||
// Inspired by base2 and Prototype
|
||||
(function() {
|
||||
(function () {
|
||||
var initializing = false;
|
||||
var fnTest = /xyz/.test(function() {xyz;}) ? /\b_super\b/ : /.*/;
|
||||
var fnTest = /xyz/.test(function () { xyz; }) ? /\b_super\b/ : /.*/;
|
||||
|
||||
// The base Class implementation (does nothing)
|
||||
this.Class = function() {};
|
||||
this.Class = function () { };
|
||||
|
||||
// Create a new Class that inherits from this class
|
||||
Class.extend = function(prop) {
|
||||
Class.extend = function (prop) {
|
||||
var _super = this.prototype;
|
||||
|
||||
// Instantiate a base class (but only create the instance,
|
||||
@@ -21,28 +21,31 @@
|
||||
var prototype = new this();
|
||||
initializing = false;
|
||||
|
||||
// Make a copy of all prototype properties, to prevent reference issues.
|
||||
for (var name in prototype) {
|
||||
prototype[name] = cloneObject(prototype[name]);
|
||||
}
|
||||
|
||||
// Copy the properties over onto the new prototype
|
||||
for (var name in prop) {
|
||||
// Check if we're overwriting an existing function
|
||||
prototype[name] = typeof prop[name] == "function" &&
|
||||
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
|
||||
(function(name, fn) {
|
||||
return function() {
|
||||
var tmp = this._super;
|
||||
prototype[name] = typeof prop[name] === "function" &&
|
||||
typeof _super[name] === "function" && fnTest.test(prop[name]) ? (function (name, fn) {
|
||||
return function () {
|
||||
var tmp = this._super;
|
||||
|
||||
// Add a new ._super() method that is the same method
|
||||
// but on the super-class
|
||||
this._super = _super[name];
|
||||
// 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
|
||||
var ret = fn.apply(this, arguments);
|
||||
this._super = tmp;
|
||||
// The method only need to be bound temporarily, so we
|
||||
// remove it when we're done executing
|
||||
var ret = fn.apply(this, arguments);
|
||||
this._super = tmp;
|
||||
|
||||
return ret;
|
||||
};
|
||||
})(name, prop[name]) :
|
||||
prop[name];
|
||||
return ret;
|
||||
};
|
||||
})(name, prop[name]) : prop[name];
|
||||
}
|
||||
|
||||
// The dummy class constructor
|
||||
@@ -66,5 +69,26 @@
|
||||
};
|
||||
})();
|
||||
|
||||
//Define the clone method for later use.
|
||||
//Helper Method
|
||||
function cloneObject(obj) {
|
||||
if (obj === null || typeof obj !== "object") {
|
||||
return obj;
|
||||
}
|
||||
|
||||
var temp = obj.constructor(); // give temp the original obj's constructor
|
||||
for (var key in obj) {
|
||||
temp[key] = cloneObject(obj[key]);
|
||||
|
||||
if (key === "lockStrings") {
|
||||
Log.log(key);
|
||||
}
|
||||
}
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||
if (typeof module !== "undefined") {module.exports = Class;}
|
||||
if (typeof module !== "undefined") {
|
||||
module.exports = Class;
|
||||
}
|
||||
|
@@ -7,14 +7,29 @@
|
||||
* MIT Licensed.
|
||||
*/
|
||||
|
||||
var port = 8080;
|
||||
var address = "localhost";
|
||||
if (typeof(mmPort) !== "undefined") {
|
||||
port = mmPort;
|
||||
}
|
||||
var defaults = {
|
||||
port: 8080,
|
||||
address: address,
|
||||
port: port,
|
||||
kioskmode: false,
|
||||
electronOptions: {},
|
||||
ipWhitelist: ["127.0.0.1", "::ffff:127.0.0.1", "::1"],
|
||||
|
||||
language: "en",
|
||||
timeFormat: 24,
|
||||
units: "metric",
|
||||
|
||||
zoom: 1,
|
||||
customCss: "css/custom.css",
|
||||
|
||||
modules: [
|
||||
{
|
||||
module: "updatenotification",
|
||||
position: "top_center"
|
||||
},
|
||||
{
|
||||
module: "helloworld",
|
||||
position: "upper_third",
|
||||
|
14
js/deprecated.js
Normal file
14
js/deprecated.js
Normal file
@@ -0,0 +1,14 @@
|
||||
/* Magic Mirror Deprecated Config Options List
|
||||
*
|
||||
* By Michael Teeuw http://michaelteeuw.nl
|
||||
* MIT Licensed.
|
||||
*
|
||||
* Olex S. original idea this deprecated option
|
||||
*/
|
||||
|
||||
var deprecated = {
|
||||
configs: ["kioskmode"],
|
||||
};
|
||||
|
||||
/*************** DO NOT EDIT THE LINE BELOW ***************/
|
||||
if (typeof module !== "undefined") {module.exports = deprecated;}
|
@@ -1,11 +1,12 @@
|
||||
/* jshint esversion: 6 */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Server = require(__dirname + "/server.js");
|
||||
const electron = require("electron");
|
||||
const core = require(__dirname + "/app.js");
|
||||
|
||||
// Config
|
||||
var config = {};
|
||||
var config = process.env.config ? JSON.parse(process.env.config) : {};
|
||||
// Module to control application life.
|
||||
const app = electron.app;
|
||||
// Module to create native browser window.
|
||||
@@ -16,23 +17,64 @@ const BrowserWindow = electron.BrowserWindow;
|
||||
let mainWindow;
|
||||
|
||||
function createWindow() {
|
||||
app.commandLine.appendSwitch("autoplay-policy", "no-user-gesture-required");
|
||||
var electronOptionsDefaults = {
|
||||
width: 800,
|
||||
height: 600,
|
||||
x: 0,
|
||||
y: 0,
|
||||
darkTheme: true,
|
||||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
zoomFactor: config.zoom
|
||||
},
|
||||
backgroundColor: "#000000"
|
||||
};
|
||||
|
||||
// DEPRECATED: "kioskmode" backwards compatibility, to be removed
|
||||
// settings these options directly instead provides cleaner interface
|
||||
if (config.kioskmode) {
|
||||
electronOptionsDefaults.kiosk = true;
|
||||
} else {
|
||||
electronOptionsDefaults.fullscreen = true;
|
||||
electronOptionsDefaults.autoHideMenuBar = true;
|
||||
}
|
||||
|
||||
var electronOptions = Object.assign({}, electronOptionsDefaults, config.electronOptions);
|
||||
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({width: 800, height: 600, fullscreen: true, autoHideMenuBar: true, darkTheme: true, webPreferences: {nodeIntegration: false}});
|
||||
mainWindow = new BrowserWindow(electronOptions);
|
||||
|
||||
// and load the index.html of the app.
|
||||
//mainWindow.loadURL('file://' + __dirname + '../../index.html');
|
||||
mainWindow.loadURL("http://localhost:" + config.port);
|
||||
// If config.address is not defined or is an empty string (listening on all interfaces), connect to localhost
|
||||
var address = (config.address === void 0) | (config.address === "") ? (config.address = "localhost") : config.address;
|
||||
mainWindow.loadURL(`http://${address}:${config.port}`);
|
||||
|
||||
// Open the DevTools.
|
||||
//mainWindow.webContents.openDevTools();
|
||||
// Open the DevTools if run with "npm start dev"
|
||||
if (process.argv.includes("dev")) {
|
||||
mainWindow.webContents.openDevTools();
|
||||
}
|
||||
|
||||
// Emitted when the window is closed.
|
||||
// Set responders for window events.
|
||||
mainWindow.on("closed", function() {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null;
|
||||
});
|
||||
|
||||
if (config.kioskmode) {
|
||||
mainWindow.on("blur", function() {
|
||||
mainWindow.focus();
|
||||
});
|
||||
|
||||
mainWindow.on("leave-full-screen", function() {
|
||||
mainWindow.setFullScreen(true);
|
||||
});
|
||||
|
||||
mainWindow.on("resize", function() {
|
||||
setTimeout(function() {
|
||||
mainWindow.reload();
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
@@ -44,11 +86,7 @@ app.on("ready", function() {
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on("window-all-closed", function() {
|
||||
// On OS X it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== "darwin") {
|
||||
app.quit();
|
||||
}
|
||||
createWindow();
|
||||
});
|
||||
|
||||
app.on("activate", function() {
|
||||
@@ -59,8 +97,24 @@ app.on("activate", function() {
|
||||
}
|
||||
});
|
||||
|
||||
// Start the core application.
|
||||
// This starts all node helpers and starts the webserver.
|
||||
core.start(function(c) {
|
||||
config = c;
|
||||
/* 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
|
||||
* core.stop() is called by process.on("SIGINT"... in `app.js`
|
||||
*/
|
||||
app.on("before-quit", (event) => {
|
||||
console.log("Shutting down server...");
|
||||
event.preventDefault();
|
||||
setTimeout(() => { process.exit(0); }, 3000); // Force-quit after 3 seconds.
|
||||
core.stop();
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
// 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].indexOf(config.address) > -1) {
|
||||
core.start(function(c) {
|
||||
config = c;
|
||||
});
|
||||
}
|
||||
|
37
js/loader.js
37
js/loader.js
@@ -8,7 +8,7 @@
|
||||
|
||||
var Loader = (function() {
|
||||
|
||||
/* Create helper valiables */
|
||||
/* Create helper variables */
|
||||
|
||||
var loadedModuleFiles = [];
|
||||
var loadedFiles = [];
|
||||
@@ -32,10 +32,10 @@ var Loader = (function() {
|
||||
});
|
||||
} else {
|
||||
// All modules loaded. Load custom.css
|
||||
// This is done after all the moduels so we can
|
||||
// overwrite all the defined styls.
|
||||
// This is done after all the modules so we can
|
||||
// overwrite all the defined styles.
|
||||
|
||||
loadFile("css/custom.css", function() {
|
||||
loadFile(config.customCss, function() {
|
||||
// custom.css loaded. Start all modules.
|
||||
startModules();
|
||||
});
|
||||
@@ -55,7 +55,7 @@ var Loader = (function() {
|
||||
module.start();
|
||||
}
|
||||
|
||||
// Notifiy core of loded modules.
|
||||
// Notify core of loaded modules.
|
||||
MM.modulesStarted(moduleObjects);
|
||||
};
|
||||
|
||||
@@ -89,6 +89,10 @@ var Loader = (function() {
|
||||
moduleFolder = config.paths.modules + "/default/" + module;
|
||||
}
|
||||
|
||||
if (moduleData.disabled === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
moduleFiles.push({
|
||||
index: m,
|
||||
identifier: "module_" + m + "_" + module,
|
||||
@@ -100,7 +104,6 @@ var Loader = (function() {
|
||||
config: moduleData.config,
|
||||
classes: (typeof moduleData.classes !== "undefined") ? moduleData.classes + " " + module : module
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return moduleFiles;
|
||||
@@ -117,9 +120,13 @@ var Loader = (function() {
|
||||
|
||||
var afterLoad = function() {
|
||||
var moduleObject = Module.create(module.name);
|
||||
bootstrapModule(module, moduleObject, function() {
|
||||
if (moduleObject) {
|
||||
bootstrapModule(module, moduleObject, function() {
|
||||
callback();
|
||||
});
|
||||
} else {
|
||||
callback();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (loadedModuleFiles.indexOf(url) !== -1) {
|
||||
@@ -130,7 +137,6 @@ var Loader = (function() {
|
||||
afterLoad();
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* bootstrapModule(module, mObj)
|
||||
@@ -156,7 +162,6 @@ var Loader = (function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
/* loadFile(fileName)
|
||||
@@ -178,6 +183,11 @@ var Loader = (function() {
|
||||
script.onload = function() {
|
||||
if (typeof callback === "function") {callback();}
|
||||
};
|
||||
script.onerror = function() {
|
||||
console.error("Error on loading script:", fileName);
|
||||
if (typeof callback === "function") {callback();}
|
||||
};
|
||||
|
||||
document.getElementsByTagName("body")[0].appendChild(script);
|
||||
break;
|
||||
case "css":
|
||||
@@ -189,10 +199,14 @@ var Loader = (function() {
|
||||
stylesheet.onload = function() {
|
||||
if (typeof callback === "function") {callback();}
|
||||
};
|
||||
stylesheet.onerror = function() {
|
||||
console.error("Error on loading stylesheet:", fileName);
|
||||
if (typeof callback === "function") {callback();}
|
||||
};
|
||||
|
||||
document.getElementsByTagName("head")[0].appendChild(stylesheet);
|
||||
break;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/* Public Methods */
|
||||
@@ -243,5 +257,4 @@ var Loader = (function() {
|
||||
loadFile(module.file(fileName), callback);
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
|
40
js/logger.js
40
js/logger.js
@@ -13,35 +13,15 @@
|
||||
|
||||
var Log = (function() {
|
||||
return {
|
||||
info: function(message) {
|
||||
console.info(message);
|
||||
},
|
||||
log: function(message) {
|
||||
console.log(message);
|
||||
},
|
||||
error: function(message) {
|
||||
console.error(message);
|
||||
},
|
||||
warn: function(message) {
|
||||
console.warn(message);
|
||||
},
|
||||
group: function(message) {
|
||||
console.group(message);
|
||||
},
|
||||
groupCollapsed: function(message) {
|
||||
console.groupCollapsed(message);
|
||||
},
|
||||
groupEnd: function() {
|
||||
console.groupEnd();
|
||||
},
|
||||
time: function(message) {
|
||||
console.time(message);
|
||||
},
|
||||
timeEnd: function(message) {
|
||||
console.timeEnd(message);
|
||||
},
|
||||
timeStamp: function(message) {
|
||||
console.timeStamp(message);
|
||||
}
|
||||
info: Function.prototype.bind.call(console.info, console),
|
||||
log: Function.prototype.bind.call(console.log, console),
|
||||
error: Function.prototype.bind.call(console.error, console),
|
||||
warn: Function.prototype.bind.call(console.warn, console),
|
||||
group: Function.prototype.bind.call(console.group, console),
|
||||
groupCollapsed: Function.prototype.bind.call(console.groupCollapsed, console),
|
||||
groupEnd: Function.prototype.bind.call(console.groupEnd, console),
|
||||
time: Function.prototype.bind.call(console.time, console),
|
||||
timeEnd: Function.prototype.bind.call(console.timeEnd, console),
|
||||
timeStamp: Function.prototype.bind.call(console.timeStamp, console)
|
||||
};
|
||||
})();
|
||||
|
345
js/main.js
345
js/main.js
@@ -1,4 +1,5 @@
|
||||
/* global Log, Loader, Module, config, defaults */
|
||||
/* jshint -W020, esversion: 6 */
|
||||
|
||||
/* Magic Mirror
|
||||
* Main System
|
||||
@@ -18,39 +19,51 @@ var MM = (function() {
|
||||
* are configured for a specific position.
|
||||
*/
|
||||
var createDomObjects = function() {
|
||||
for (var m in modules) {
|
||||
var module = modules[m];
|
||||
var domCreationPromises = [];
|
||||
|
||||
if (typeof module.data.position === "string") {
|
||||
|
||||
var wrapper = selectWrapper(module.data.position);
|
||||
|
||||
var dom = document.createElement("div");
|
||||
dom.id = module.identifier;
|
||||
dom.className = module.name;
|
||||
|
||||
if (typeof module.data.classes === "string") {
|
||||
dom.className = "module " + dom.className + " " + module.data.classes;
|
||||
}
|
||||
|
||||
dom.opacity = 0;
|
||||
wrapper.appendChild(dom);
|
||||
|
||||
if (typeof module.data.header !== "undefined" && module.data.header !== "") {
|
||||
var moduleHeader = document.createElement("header");
|
||||
moduleHeader.innerHTML = module.data.header;
|
||||
dom.appendChild(moduleHeader);
|
||||
}
|
||||
|
||||
var moduleContent = document.createElement("div");
|
||||
moduleContent.className = "module-content";
|
||||
dom.appendChild(moduleContent);
|
||||
|
||||
updateDom(module, 0);
|
||||
modules.forEach(function(module) {
|
||||
if (typeof module.data.position !== "string") {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sendNotification("DOM_OBJECTS_CREATED");
|
||||
var wrapper = selectWrapper(module.data.position);
|
||||
|
||||
var dom = document.createElement("div");
|
||||
dom.id = module.identifier;
|
||||
dom.className = module.name;
|
||||
|
||||
if (typeof module.data.classes === "string") {
|
||||
dom.className = "module " + dom.className + " " + module.data.classes;
|
||||
}
|
||||
|
||||
dom.opacity = 0;
|
||||
wrapper.appendChild(dom);
|
||||
|
||||
var moduleHeader = document.createElement("header");
|
||||
moduleHeader.innerHTML = module.getHeader();
|
||||
moduleHeader.className = "module-header";
|
||||
dom.appendChild(moduleHeader);
|
||||
|
||||
if (typeof module.getHeader() === "undefined" || module.getHeader() !== "") {
|
||||
moduleHeader.style = "display: none;";
|
||||
}
|
||||
|
||||
var moduleContent = document.createElement("div");
|
||||
moduleContent.className = "module-content";
|
||||
dom.appendChild(moduleContent);
|
||||
|
||||
var domCreationPromise = updateDom(module, 0);
|
||||
domCreationPromises.push(domCreationPromise);
|
||||
domCreationPromise.then(function() {
|
||||
sendNotification("MODULE_DOM_CREATED", null, null, module);
|
||||
}).catch(Log.error);
|
||||
});
|
||||
|
||||
updateWrapperStates();
|
||||
|
||||
Promise.all(domCreationPromises).then(function() {
|
||||
sendNotification("DOM_OBJECTS_CREATED");
|
||||
});
|
||||
};
|
||||
|
||||
/* selectWrapper(position)
|
||||
@@ -62,7 +75,7 @@ var MM = (function() {
|
||||
var classes = position.replace("_"," ");
|
||||
var parentWrapper = document.getElementsByClassName(classes);
|
||||
if (parentWrapper.length > 0) {
|
||||
var wrapper = parentWrapper[0].getElementsByClassName("container");
|
||||
var wrapper = parentWrapper[0].getElementsByClassName("container");
|
||||
if (wrapper.length > 0) {
|
||||
return wrapper[0];
|
||||
}
|
||||
@@ -72,14 +85,15 @@ var MM = (function() {
|
||||
/* sendNotification(notification, payload, sender)
|
||||
* Send a notification to all modules.
|
||||
*
|
||||
* argument notification string - The identifier of the noitication.
|
||||
* argument notification string - The identifier of the notification.
|
||||
* argument payload mixed - The payload of the notification.
|
||||
* argument sender Module - The module that sent the notification.
|
||||
* argument sendTo Module - The module to send the notification to. (optional)
|
||||
*/
|
||||
var sendNotification = function(notification, payload, sender) {
|
||||
var sendNotification = function(notification, payload, sender, sendTo) {
|
||||
for (var m in modules) {
|
||||
var module = modules[m];
|
||||
if (module !== sender) {
|
||||
if (module !== sender && (!sendTo || module === sendTo)) {
|
||||
module.notificationReceived(notification, payload, sender);
|
||||
}
|
||||
}
|
||||
@@ -90,62 +104,116 @@ var MM = (function() {
|
||||
*
|
||||
* argument module Module - The module that needs an update.
|
||||
* argument speed Number - The number of microseconds for the animation. (optional)
|
||||
*
|
||||
* return Promise - Resolved when the dom is fully updated.
|
||||
*/
|
||||
var updateDom = function(module, speed) {
|
||||
var newContent = module.getDom();
|
||||
return new Promise(function(resolve) {
|
||||
var newContentPromise = module.getDom();
|
||||
var newHeader = module.getHeader();
|
||||
|
||||
if (!module.hidden) {
|
||||
if (!(newContentPromise instanceof Promise)) {
|
||||
// convert to a promise if not already one to avoid if/else's everywhere
|
||||
newContentPromise = Promise.resolve(newContentPromise);
|
||||
}
|
||||
|
||||
if (!moduleNeedsUpdate(module, newContent)) {
|
||||
newContentPromise.then(function(newContent) {
|
||||
var updatePromise = updateDomWithContent(module, speed, newHeader, newContent);
|
||||
|
||||
updatePromise.then(resolve).catch(Log.error);
|
||||
}).catch(Log.error);
|
||||
});
|
||||
};
|
||||
|
||||
/* updateDomWithContent(module, speed, newHeader, newContent)
|
||||
* Update the dom with the specified content
|
||||
*
|
||||
* argument module Module - The module that needs an update.
|
||||
* argument speed Number - The number of microseconds for the animation. (optional)
|
||||
* argument newHeader String - The new header that is generated.
|
||||
* argument newContent Domobject - The new content that is generated.
|
||||
*
|
||||
* return Promise - Resolved when the module dom has been updated.
|
||||
*/
|
||||
var updateDomWithContent = function(module, speed, newHeader, newContent) {
|
||||
return new Promise(function(resolve) {
|
||||
if (module.hidden || !speed) {
|
||||
updateModuleContent(module, newHeader, newContent);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!moduleNeedsUpdate(module, newHeader, newContent)) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!speed) {
|
||||
updateModuleContent(module, newContent);
|
||||
updateModuleContent(module, newHeader, newContent);
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
hideModule(module, speed / 2, function() {
|
||||
updateModuleContent(module, newContent);
|
||||
updateModuleContent(module, newHeader, newContent);
|
||||
if (!module.hidden) {
|
||||
showModule(module, speed / 2);
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
} else {
|
||||
updateModuleContent(module, newContent);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/* moduleNeedsUpdate(module, newContent)
|
||||
* Check if the content has changed.
|
||||
*
|
||||
* argument module Module - The module to check.
|
||||
* argument newHeader String - The new header that is generated.
|
||||
* argument newContent Domobject - The new content that is generated.
|
||||
*
|
||||
* return bool - Does the module need an update?
|
||||
*/
|
||||
var moduleNeedsUpdate = function(module, newContent) {
|
||||
var moduleNeedsUpdate = function(module, newHeader, newContent) {
|
||||
var moduleWrapper = document.getElementById(module.identifier);
|
||||
var contentWrapper = moduleWrapper.getElementsByClassName("module-content")[0];
|
||||
if (moduleWrapper === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var tempWrapper = document.createElement("div");
|
||||
tempWrapper.appendChild(newContent);
|
||||
var contentWrapper = moduleWrapper.getElementsByClassName("module-content");
|
||||
var headerWrapper = moduleWrapper.getElementsByClassName("module-header");
|
||||
|
||||
return tempWrapper.innerHTML !== contentWrapper.innerHTML;
|
||||
var headerNeedsUpdate = false;
|
||||
var contentNeedsUpdate = false;
|
||||
|
||||
if (headerWrapper.length > 0) {
|
||||
headerNeedsUpdate = newHeader !== headerWrapper[0].innerHTML;
|
||||
}
|
||||
|
||||
var tempContentWrapper = document.createElement("div");
|
||||
tempContentWrapper.appendChild(newContent);
|
||||
contentNeedsUpdate = tempContentWrapper.innerHTML !== contentWrapper[0].innerHTML;
|
||||
|
||||
return headerNeedsUpdate || contentNeedsUpdate;
|
||||
};
|
||||
|
||||
/* moduleNeedsUpdate(module, newContent)
|
||||
* Update the content of a module on screen.
|
||||
*
|
||||
* argument module Module - The module to check.
|
||||
* argument newHeader String - The new header that is generated.
|
||||
* argument newContent Domobject - The new content that is generated.
|
||||
*/
|
||||
var updateModuleContent = function(module, content) {
|
||||
var updateModuleContent = function(module, newHeader, newContent) {
|
||||
var moduleWrapper = document.getElementById(module.identifier);
|
||||
var contentWrapper = moduleWrapper.getElementsByClassName("module-content")[0];
|
||||
if (moduleWrapper === null) {return;}
|
||||
var headerWrapper = moduleWrapper.getElementsByClassName("module-header");
|
||||
var contentWrapper = moduleWrapper.getElementsByClassName("module-content");
|
||||
|
||||
contentWrapper.innerHTML = null;
|
||||
contentWrapper.appendChild(content);
|
||||
contentWrapper[0].innerHTML = "";
|
||||
contentWrapper[0].appendChild(newContent);
|
||||
|
||||
headerWrapper[0].innerHTML = newHeader;
|
||||
headerWrapper[0].style = headerWrapper.length > 0 && newHeader ? undefined : "display: none;";
|
||||
};
|
||||
|
||||
/* hideModule(module, speed, callback)
|
||||
@@ -155,7 +223,17 @@ var MM = (function() {
|
||||
* argument speed Number - The speed of the hide animation.
|
||||
* argument callback function - Called when the animation is done.
|
||||
*/
|
||||
var hideModule = function(module, speed, callback) {
|
||||
var hideModule = function(module, speed, callback, options) {
|
||||
options = options || {};
|
||||
|
||||
// set lockString if set in options.
|
||||
if (options.lockString) {
|
||||
// Log.log("Has lockstring: " + options.lockString);
|
||||
if (module.lockStrings.indexOf(options.lockString) === -1) {
|
||||
module.lockStrings.push(options.lockString);
|
||||
}
|
||||
}
|
||||
|
||||
var moduleWrapper = document.getElementById(module.identifier);
|
||||
if (moduleWrapper !== null) {
|
||||
moduleWrapper.style.transition = "opacity " + speed / 1000 + "s";
|
||||
@@ -164,13 +242,18 @@ var MM = (function() {
|
||||
clearTimeout(module.showHideTimer);
|
||||
module.showHideTimer = setTimeout(function() {
|
||||
// To not take up any space, we just make the position absolute.
|
||||
// since it"s fade out anyway, we can see it lay above or
|
||||
// since it's fade out anyway, we can see it lay above or
|
||||
// below other modules. This works way better than adjusting
|
||||
// the .display property.
|
||||
moduleWrapper.style.position = "absolute";
|
||||
moduleWrapper.style.position = "fixed";
|
||||
|
||||
updateWrapperStates();
|
||||
|
||||
if (typeof callback === "function") { callback(); }
|
||||
}, speed);
|
||||
} else {
|
||||
// invoke callback even if no content, issue 1308
|
||||
if (typeof callback === "function") { callback(); }
|
||||
}
|
||||
};
|
||||
|
||||
@@ -181,12 +264,42 @@ var MM = (function() {
|
||||
* argument speed Number - The speed of the show animation.
|
||||
* argument callback function - Called when the animation is done.
|
||||
*/
|
||||
var showModule = function(module, speed, callback) {
|
||||
var showModule = function(module, speed, callback, options) {
|
||||
options = options || {};
|
||||
|
||||
// remove lockString if set in options.
|
||||
if (options.lockString) {
|
||||
var index = module.lockStrings.indexOf(options.lockString);
|
||||
if ( index !== -1) {
|
||||
module.lockStrings.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// 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(","));
|
||||
return;
|
||||
}
|
||||
|
||||
module.hidden = false;
|
||||
|
||||
// If forced show, clean current lockstrings.
|
||||
if (module.lockStrings.length !== 0 && options.force === true) {
|
||||
Log.log("Force show of module: " + module.name);
|
||||
module.lockStrings = [];
|
||||
}
|
||||
|
||||
var moduleWrapper = document.getElementById(module.identifier);
|
||||
if (moduleWrapper !== null) {
|
||||
moduleWrapper.style.transition = "opacity " + speed / 1000 + "s";
|
||||
// Restore the postition. See hideModule() for more info.
|
||||
// Restore the position. See hideModule() for more info.
|
||||
moduleWrapper.style.position = "static";
|
||||
|
||||
updateWrapperStates();
|
||||
|
||||
// Waiting for DOM-changes done in updateWrapperStates before we can start the animation.
|
||||
var dummy = moduleWrapper.parentElement.parentElement.offsetHeight;
|
||||
moduleWrapper.style.opacity = 1;
|
||||
|
||||
clearTimeout(module.showHideTimer);
|
||||
@@ -197,6 +310,35 @@ var MM = (function() {
|
||||
}
|
||||
};
|
||||
|
||||
/* updateWrapperStates()
|
||||
* Checks for all positions if it has visible content.
|
||||
* If not, if will hide the position to prevent unwanted margins.
|
||||
* This method should be called by the show and hide methods.
|
||||
*
|
||||
* Example:
|
||||
* If the top_bar only contains the update notification. And no update is available,
|
||||
* the update notification is hidden. The top bar still occupies space making for
|
||||
* an ugly top margin. By using this function, the top bar will be hidden if the
|
||||
* update notification is not visible.
|
||||
*/
|
||||
var updateWrapperStates = function() {
|
||||
var 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) {
|
||||
var wrapper = selectWrapper(position);
|
||||
var moduleWrappers = wrapper.getElementsByClassName("module");
|
||||
|
||||
var showWrapper = false;
|
||||
Array.prototype.forEach.call(moduleWrappers, function(moduleWrapper) {
|
||||
if (moduleWrapper.style.position === "" || moduleWrapper.style.position === "static") {
|
||||
showWrapper = true;
|
||||
}
|
||||
});
|
||||
|
||||
wrapper.style.display = showWrapper ? "block" : "none";
|
||||
});
|
||||
};
|
||||
|
||||
/* loadConfig()
|
||||
* Loads the core config and combines it with de system defaults.
|
||||
*/
|
||||
@@ -207,7 +349,7 @@ var MM = (function() {
|
||||
return;
|
||||
}
|
||||
|
||||
config = Object.assign(defaults, config);
|
||||
config = Object.assign({}, defaults, config);
|
||||
};
|
||||
|
||||
/* setSelectionMethodsForModules()
|
||||
@@ -218,66 +360,53 @@ var MM = (function() {
|
||||
var setSelectionMethodsForModules = function(modules) {
|
||||
|
||||
/* withClass(className)
|
||||
* filters a collection of modules based on classname(s).
|
||||
* calls modulesByClass to filter modules with the specified classes.
|
||||
*
|
||||
* argument className string/array - one or multiple classnames. (array or space devided)
|
||||
* argument className string/array - one or multiple classnames. (array or space divided)
|
||||
*
|
||||
* return array - Filtered collection of modules.
|
||||
*/
|
||||
var withClass = function(className) {
|
||||
var newModules = [];
|
||||
|
||||
var searchClasses = className;
|
||||
if (typeof className === "string") {
|
||||
searchClasses = className.split(" ");
|
||||
}
|
||||
|
||||
for (var m in modules) {
|
||||
var module = modules[m];
|
||||
var classes = module.data.classes.toLowerCase().split(" ");
|
||||
|
||||
for (var c in searchClasses) {
|
||||
var searchClass = searchClasses[c];
|
||||
if (classes.indexOf(searchClass.toLowerCase()) !== -1) {
|
||||
newModules.push(module);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setSelectionMethodsForModules(newModules);
|
||||
return newModules;
|
||||
return modulesByClass(className, true);
|
||||
};
|
||||
|
||||
/* exceptWithClass(className)
|
||||
* filters a collection of modules based on classname(s). (NOT)
|
||||
* calls modulesByClass to filter modules without the specified classes.
|
||||
*
|
||||
* argument className string/array - one or multiple classnames. (array or space devided)
|
||||
* argument className string/array - one or multiple classnames. (array or space divided)
|
||||
*
|
||||
* return array - Filtered collection of modules.
|
||||
*/
|
||||
var exceptWithClass = function(className) {
|
||||
var newModules = [];
|
||||
return modulesByClass(className, false);
|
||||
};
|
||||
|
||||
/* modulesByClass(className, include)
|
||||
* filters a collection of modules based on classname(s).
|
||||
*
|
||||
* argument className string/array - one or multiple classnames. (array or space divided)
|
||||
* argument include boolean - if the filter should include or exclude the modules with the specific classes.
|
||||
*
|
||||
* return array - Filtered collection of modules.
|
||||
*/
|
||||
var modulesByClass = function(className, include) {
|
||||
var searchClasses = className;
|
||||
if (typeof className === "string") {
|
||||
searchClasses = className.split(" ");
|
||||
}
|
||||
|
||||
for (var m in modules) {
|
||||
var module = modules[m];
|
||||
var newModules = modules.filter(function(module) {
|
||||
var classes = module.data.classes.toLowerCase().split(" ");
|
||||
var foundClass = false;
|
||||
|
||||
for (var c in searchClasses) {
|
||||
var searchClass = searchClasses[c];
|
||||
if (classes.indexOf(searchClass.toLowerCase()) !== -1) {
|
||||
foundClass = true;
|
||||
break;
|
||||
return include;
|
||||
}
|
||||
}
|
||||
if (!foundClass) {
|
||||
newModules.push(module);
|
||||
}
|
||||
}
|
||||
|
||||
return !include;
|
||||
});
|
||||
|
||||
setSelectionMethodsForModules(newModules);
|
||||
return newModules;
|
||||
@@ -291,14 +420,9 @@ var MM = (function() {
|
||||
* return array - Filtered collection of modules.
|
||||
*/
|
||||
var exceptModule = function(module) {
|
||||
var newModules = [];
|
||||
|
||||
for (var m in modules) {
|
||||
var mod = modules[m];
|
||||
if (mod.identifier !== module.identifier) {
|
||||
newModules.push(mod);
|
||||
}
|
||||
}
|
||||
var newModules = modules.filter(function(mod) {
|
||||
return mod.identifier !== module.identifier;
|
||||
});
|
||||
|
||||
setSelectionMethodsForModules(newModules);
|
||||
return newModules;
|
||||
@@ -310,10 +434,9 @@ var MM = (function() {
|
||||
* argument callback function - The function to execute with the module as an argument.
|
||||
*/
|
||||
var enumerate = function(callback) {
|
||||
for (var m in modules) {
|
||||
var module = modules[m];
|
||||
modules.map(function(module) {
|
||||
callback(module);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (typeof modules.withClass === "undefined") { Object.defineProperty(modules, "withClass", {value: withClass, enumerable: false}); }
|
||||
@@ -356,7 +479,7 @@ var MM = (function() {
|
||||
/* sendNotification(notification, payload, sender)
|
||||
* Send a notification to all modules.
|
||||
*
|
||||
* argument notification string - The identifier of the noitication.
|
||||
* argument notification string - The identifier of the notification.
|
||||
* argument payload mixed - The payload of the notification.
|
||||
* argument sender Module - The module that sent the notification.
|
||||
*/
|
||||
@@ -412,10 +535,11 @@ var MM = (function() {
|
||||
* argument module Module - The module hide.
|
||||
* argument speed Number - The speed of the hide animation.
|
||||
* argument callback function - Called when the animation is done.
|
||||
* argument options object - Optional settings for the hide method.
|
||||
*/
|
||||
hideModule: function(module, speed, callback) {
|
||||
hideModule: function(module, speed, callback, options) {
|
||||
module.hidden = true;
|
||||
hideModule(module, speed, callback);
|
||||
hideModule(module, speed, callback, options);
|
||||
},
|
||||
|
||||
/* showModule(module, speed, callback)
|
||||
@@ -424,17 +548,18 @@ var MM = (function() {
|
||||
* argument module Module - The module show.
|
||||
* argument speed Number - The speed of the show animation.
|
||||
* argument callback function - Called when the animation is done.
|
||||
* argument options object - Optional settings for the hide method.
|
||||
*/
|
||||
showModule: function(module, speed, callback) {
|
||||
module.hidden = false;
|
||||
showModule(module, speed, callback);
|
||||
showModule: function(module, speed, callback, options) {
|
||||
// do not change module.hidden yet, only if we really show it later
|
||||
showModule(module, speed, callback, options);
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
||||
|
||||
// Add polyfill for Object.assign.
|
||||
if (typeof Object.assign != "function") {
|
||||
if (typeof Object.assign !== "function") {
|
||||
(function() {
|
||||
Object.assign = function(target) {
|
||||
"use strict";
|
||||
|
320
js/module.js
320
js/module.js
@@ -14,23 +14,35 @@ var Module = Class.extend({
|
||||
* All methods (and properties) below can be subclassed. *
|
||||
*********************************************************/
|
||||
|
||||
// Set the minimum MagicMirror module version for this module.
|
||||
requiresVersion: "2.0.0",
|
||||
|
||||
// Module config defaults.
|
||||
defaults: {},
|
||||
|
||||
// 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.
|
||||
lockStrings: [],
|
||||
|
||||
// Storage of the nunjuck Environment,
|
||||
// This should not be referenced directly.
|
||||
// Use the nunjucksEnvironment() to get it.
|
||||
_nunjucksEnvironment: null,
|
||||
|
||||
/* init()
|
||||
* Is called when the module is instantiated.
|
||||
*/
|
||||
init: function() {
|
||||
init: function () {
|
||||
//Log.log(this.defaults);
|
||||
},
|
||||
|
||||
/* start()
|
||||
* Is called when the module is started.
|
||||
*/
|
||||
start: function() {
|
||||
start: function () {
|
||||
Log.info("Starting module: " + this.name);
|
||||
},
|
||||
|
||||
@@ -39,7 +51,7 @@ var Module = Class.extend({
|
||||
*
|
||||
* return Array<String> - An array with filenames.
|
||||
*/
|
||||
getScripts: function() {
|
||||
getScripts: function () {
|
||||
return [];
|
||||
},
|
||||
|
||||
@@ -48,7 +60,7 @@ var Module = Class.extend({
|
||||
*
|
||||
* return Array<String> - An array with filenames.
|
||||
*/
|
||||
getStyles: function() {
|
||||
getStyles: function () {
|
||||
return [];
|
||||
},
|
||||
|
||||
@@ -57,42 +69,87 @@ var Module = Class.extend({
|
||||
*
|
||||
* return Map<String, String> - A map with langKeys and filenames.
|
||||
*/
|
||||
getTranslations: function() {
|
||||
getTranslations: function () {
|
||||
return false;
|
||||
},
|
||||
|
||||
/* getDom()
|
||||
* This method generates the dom which needs to be displayed. This method is called by the Magic Mirror core.
|
||||
* This method needs to be subclassed if the module wants to display info on the mirror.
|
||||
* This method can to be subclassed if the module wants to display info on the mirror.
|
||||
* Alternatively, the getTemplate method could be subclassed.
|
||||
*
|
||||
* return domobject - The dom to display.
|
||||
* return DomObject | Promise - The dom or a promise with the dom to display.
|
||||
*/
|
||||
getDom: function() {
|
||||
var nameWrapper = document.createElement("div");
|
||||
var name = document.createTextNode(this.name);
|
||||
nameWrapper.appendChild(name);
|
||||
getDom: function () {
|
||||
var self = this;
|
||||
return new Promise(function(resolve) {
|
||||
var div = document.createElement("div");
|
||||
var template = self.getTemplate();
|
||||
var templateData = self.getTemplateData();
|
||||
|
||||
var identifierWrapper = document.createElement("div");
|
||||
var identifier = document.createTextNode(this.identifier);
|
||||
identifierWrapper.appendChild(identifier);
|
||||
identifierWrapper.className = "small dimmed";
|
||||
// Check to see if we need to render a template string or a file.
|
||||
if (/^.*((\.html)|(\.njk))$/.test(template)) {
|
||||
// the template is a filename
|
||||
self.nunjucksEnvironment().render(template, templateData, function (err, res) {
|
||||
if (err) {
|
||||
Log.error(err);
|
||||
}
|
||||
|
||||
var div = document.createElement("div");
|
||||
div.appendChild(nameWrapper);
|
||||
div.appendChild(identifierWrapper);
|
||||
div.innerHTML = res;
|
||||
|
||||
return div;
|
||||
resolve(div);
|
||||
});
|
||||
} else {
|
||||
// the template is a template string.
|
||||
div.innerHTML = self.nunjucksEnvironment().renderString(template, templateData);
|
||||
|
||||
resolve(div);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/* getHeader()
|
||||
* This method generates the header string which needs to be displayed if a user has a header configured for this module.
|
||||
* This method is called by the Magic Mirror core, but only if the user has configured a default header for the module.
|
||||
* This method needs to be subclassed if the module wants to display modified headers on the mirror.
|
||||
*
|
||||
* return string - The header to display above the header.
|
||||
*/
|
||||
getHeader: function () {
|
||||
return this.data.header;
|
||||
},
|
||||
|
||||
/* getTemplate()
|
||||
* This method returns the template for the module which is used by the default getDom implementation.
|
||||
* This method needs to be subclassed if the module wants to use a template.
|
||||
* It can either return a template sting, or a template filename.
|
||||
* If the string ends with '.html' it's considered a file from within the module's folder.
|
||||
*
|
||||
* return string - The template string of filename.
|
||||
*/
|
||||
getTemplate: function () {
|
||||
return "<div class=\"normal\">" + this.name + "</div><div class=\"small dimmed\">" + this.identifier + "</div>";
|
||||
},
|
||||
|
||||
/* getTemplateData()
|
||||
* This method returns the data to be used in the template.
|
||||
* This method needs to be subclassed if the module wants to use a custom data.
|
||||
*
|
||||
* return Object
|
||||
*/
|
||||
getTemplateData: function () {
|
||||
return {};
|
||||
},
|
||||
|
||||
/* notificationReceived(notification, payload, sender)
|
||||
* This method is called when a notification arrives.
|
||||
* This method is called by the Magic Mirror core.
|
||||
*
|
||||
* argument notification string - The identifier of the noitication.
|
||||
* argument notification string - The identifier of the notification.
|
||||
* argument payload mixed - The payload of the notification.
|
||||
* argument sender Module - The module that sent the notification.
|
||||
*/
|
||||
notificationReceived: function(notification, payload, sender) {
|
||||
notificationReceived: function (notification, payload, sender) {
|
||||
if (sender) {
|
||||
Log.log(this.name + " received a module notification: " + notification + " from sender: " + sender.name);
|
||||
} else {
|
||||
@@ -100,27 +157,51 @@ var Module = Class.extend({
|
||||
}
|
||||
},
|
||||
|
||||
/** nunjucksEnvironment()
|
||||
* Returns the nunjucks environment for the current module.
|
||||
* The environment is checked in the _nunjucksEnvironment instance variable.
|
||||
|
||||
* @returns Nunjucks Environment
|
||||
*/
|
||||
nunjucksEnvironment: function() {
|
||||
if (this._nunjucksEnvironment !== null) {
|
||||
return this._nunjucksEnvironment;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
this._nunjucksEnvironment = new nunjucks.Environment(new nunjucks.WebLoader(this.file(""), {async: true}), {
|
||||
trimBlocks: true,
|
||||
lstripBlocks: true
|
||||
});
|
||||
this._nunjucksEnvironment.addFilter("translate", function(str) {
|
||||
return self.translate(str);
|
||||
});
|
||||
|
||||
return this._nunjucksEnvironment;
|
||||
},
|
||||
|
||||
/* socketNotificationReceived(notification, payload)
|
||||
* This method is called when a socket notification arrives.
|
||||
*
|
||||
* argument notification string - The identifier of the noitication.
|
||||
* argument notification string - The identifier of the notification.
|
||||
* argument payload mixed - The payload of the notification.
|
||||
*/
|
||||
socketNotificationReceived: function(notification, payload) {
|
||||
socketNotificationReceived: function (notification, payload) {
|
||||
Log.log(this.name + " received a socket notification: " + notification + " - Payload: " + payload);
|
||||
},
|
||||
|
||||
/* suspend()
|
||||
* This method is called when a module is hidden.
|
||||
*/
|
||||
suspend: function() {
|
||||
Log.log(this.name + " is suspend.");
|
||||
suspend: function () {
|
||||
Log.log(this.name + " is suspended.");
|
||||
},
|
||||
|
||||
/* resume()
|
||||
* This method is called when a module is shown.
|
||||
*/
|
||||
resume: function() {
|
||||
resume: function () {
|
||||
Log.log(this.name + " is resumed.");
|
||||
},
|
||||
|
||||
@@ -131,9 +212,9 @@ var Module = Class.extend({
|
||||
/* setData(data)
|
||||
* Set the module data.
|
||||
*
|
||||
* argument data obejct - Module data.
|
||||
* argument data object - Module data.
|
||||
*/
|
||||
setData: function(data) {
|
||||
setData: function (data) {
|
||||
this.data = data;
|
||||
this.name = data.name;
|
||||
this.identifier = data.identifier;
|
||||
@@ -145,23 +226,23 @@ var Module = Class.extend({
|
||||
/* setConfig(config)
|
||||
* Set the module config and combine it with the module defaults.
|
||||
*
|
||||
* argument config obejct - Module config.
|
||||
* argument config object - Module config.
|
||||
*/
|
||||
setConfig: function(config) {
|
||||
this.config = Object.assign(this.defaults, config);
|
||||
setConfig: function (config) {
|
||||
this.config = Object.assign({}, this.defaults, config);
|
||||
},
|
||||
|
||||
/* socket()
|
||||
* Returns a socket object. If it doesn"t exist, it"s created.
|
||||
* Returns a socket object. If it doesn't exist, it"s created.
|
||||
* It also registers the notification callback.
|
||||
*/
|
||||
socket: function() {
|
||||
socket: function () {
|
||||
if (typeof this._socket === "undefined") {
|
||||
this._socket = this._socket = new MMSocket(this.name);
|
||||
}
|
||||
|
||||
var self = this;
|
||||
this._socket.setNotificationCallback(function(notification, payload) {
|
||||
this._socket.setNotificationCallback(function (notification, payload) {
|
||||
self.socketNotificationReceived(notification, payload);
|
||||
});
|
||||
|
||||
@@ -175,8 +256,8 @@ var Module = Class.extend({
|
||||
*
|
||||
* return string - File path.
|
||||
*/
|
||||
file: function(file) {
|
||||
return this.data.path + "/" + file;
|
||||
file: function (file) {
|
||||
return (this.data.path + "/" + file).replace("//", "/");
|
||||
},
|
||||
|
||||
/* loadStyles()
|
||||
@@ -184,23 +265,8 @@ var Module = Class.extend({
|
||||
*
|
||||
* argument callback function - Function called when done.
|
||||
*/
|
||||
loadStyles: function(callback) {
|
||||
var self = this;
|
||||
var styles = this.getStyles();
|
||||
|
||||
var loadNextStyle = function() {
|
||||
if (styles.length > 0) {
|
||||
var nextStyle = styles[0];
|
||||
Loader.loadFile(nextStyle, self, function() {
|
||||
styles = styles.slice(1);
|
||||
loadNextStyle();
|
||||
});
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
loadNextStyle();
|
||||
loadStyles: function (callback) {
|
||||
this.loadDependencies("getStyles", callback);
|
||||
},
|
||||
|
||||
/* loadScripts()
|
||||
@@ -208,23 +274,33 @@ var Module = Class.extend({
|
||||
*
|
||||
* argument callback function - Function called when done.
|
||||
*/
|
||||
loadScripts: function(callback) {
|
||||
var self = this;
|
||||
var scripts = this.getScripts();
|
||||
loadScripts: function (callback) {
|
||||
this.loadDependencies("getScripts", callback);
|
||||
},
|
||||
|
||||
var loadNextScript = function() {
|
||||
if (scripts.length > 0) {
|
||||
var nextScript = scripts[0];
|
||||
Loader.loadFile(nextScript, self, function() {
|
||||
scripts = scripts.slice(1);
|
||||
loadNextScript();
|
||||
/* loadDependencies(funcName, callback)
|
||||
* Helper method to load all dependencies.
|
||||
*
|
||||
* argument funcName string - Function name to call to get scripts or styles.
|
||||
* argument callback function - Function called when done.
|
||||
*/
|
||||
loadDependencies: function (funcName, callback) {
|
||||
var self = this;
|
||||
var dependencies = this[funcName]();
|
||||
|
||||
var loadNextDependency = function () {
|
||||
if (dependencies.length > 0) {
|
||||
var nextDependency = dependencies[0];
|
||||
Loader.loadFile(nextDependency, self, function () {
|
||||
dependencies = dependencies.slice(1);
|
||||
loadNextDependency();
|
||||
});
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
loadNextScript();
|
||||
loadNextDependency();
|
||||
},
|
||||
|
||||
/* loadScripts()
|
||||
@@ -232,14 +308,14 @@ var Module = Class.extend({
|
||||
*
|
||||
* argument callback function - Function called when done.
|
||||
*/
|
||||
loadTranslations: function(callback) {
|
||||
loadTranslations: function (callback) {
|
||||
var self = this;
|
||||
var translations = this.getTranslations();
|
||||
var lang = config.language.toLowerCase();
|
||||
|
||||
// The variable `first` will contain the first
|
||||
// defined translation after the following line.
|
||||
for (var first in translations) {break;}
|
||||
for (var first in translations) { break; }
|
||||
|
||||
if (translations) {
|
||||
var translationFile = translations[lang] || undefined;
|
||||
@@ -247,8 +323,8 @@ var Module = Class.extend({
|
||||
|
||||
// If a translation file is set, load it and then also load the fallback translation file.
|
||||
// Otherwise only load the fallback translation file.
|
||||
if (translationFile !== undefined) {
|
||||
Translator.load(self, translationFile, false, function() {
|
||||
if (translationFile !== undefined && translationFile !== translationsFallbackFile) {
|
||||
Translator.load(self, translationFile, false, function () {
|
||||
Translator.load(self, translationsFallbackFile, true, callback);
|
||||
});
|
||||
} else {
|
||||
@@ -259,14 +335,18 @@ var Module = Class.extend({
|
||||
}
|
||||
},
|
||||
|
||||
/* translate(key, defaultValue)
|
||||
* Request the translation for a given key.
|
||||
*
|
||||
* argument key string - The key of the string to translage
|
||||
* argument defaultValue string - The default value if no translation was found. (Optional)
|
||||
*/
|
||||
translate: function(key, defaultValue) {
|
||||
return Translator.translate(this, key) || defaultValue || "";
|
||||
/* translate(key, defaultValueOrVariables, defaultValue)
|
||||
* Request the translation for a given key with optional variables and default value.
|
||||
*
|
||||
* argument key string - The key of the string to translate
|
||||
* argument defaultValueOrVariables string/object - The default value or variables for translating. (Optional)
|
||||
* argument defaultValue string - The default value with variables. (Optional)
|
||||
*/
|
||||
translate: function (key, defaultValueOrVariables, defaultValue) {
|
||||
if(typeof defaultValueOrVariables === "object") {
|
||||
return Translator.translate(this, key, defaultValueOrVariables) || defaultValue || "";
|
||||
}
|
||||
return Translator.translate(this, key) || defaultValueOrVariables || "";
|
||||
},
|
||||
|
||||
/* updateDom(speed)
|
||||
@@ -274,27 +354,27 @@ var Module = Class.extend({
|
||||
*
|
||||
* argument speed Number - The speed of the animation. (Optional)
|
||||
*/
|
||||
updateDom: function(speed) {
|
||||
updateDom: function (speed) {
|
||||
MM.updateDom(this, speed);
|
||||
},
|
||||
|
||||
/* sendNotification(notification, payload)
|
||||
* Send a notification to all modules.
|
||||
*
|
||||
* argument notification string - The identifier of the noitication.
|
||||
* argument notification string - The identifier of the notification.
|
||||
* argument payload mixed - The payload of the notification.
|
||||
*/
|
||||
sendNotification: function(notification, payload) {
|
||||
sendNotification: function (notification, payload) {
|
||||
MM.sendNotification(notification, payload, this);
|
||||
},
|
||||
|
||||
/* sendSocketNotification(notification, payload)
|
||||
* Send a socket notification to the node helper.
|
||||
*
|
||||
* argument notification string - The identifier of the noitication.
|
||||
* argument notification string - The identifier of the notification.
|
||||
* argument payload mixed - The payload of the notification.
|
||||
*/
|
||||
sendSocketNotification: function(notification, payload) {
|
||||
sendSocketNotification: function (notification, payload) {
|
||||
this.socket().sendNotification(notification, payload);
|
||||
},
|
||||
|
||||
@@ -303,15 +383,22 @@ var Module = Class.extend({
|
||||
*
|
||||
* argument speed Number - The speed of the hide animation.
|
||||
* argument callback function - Called when the animation is done.
|
||||
* argument options object - Optional settings for the hide method.
|
||||
*/
|
||||
hide: function(speed, callback) {
|
||||
callback = callback || function() {};
|
||||
hide: function (speed, callback, options) {
|
||||
if (typeof callback === "object") {
|
||||
options = callback;
|
||||
callback = function () { };
|
||||
}
|
||||
|
||||
callback = callback || function () { };
|
||||
options = options || {};
|
||||
|
||||
var self = this;
|
||||
MM.hideModule(self, speed, function() {
|
||||
MM.hideModule(self, speed, function () {
|
||||
self.suspend();
|
||||
callback();
|
||||
});
|
||||
}, options);
|
||||
},
|
||||
|
||||
/* showModule(module, speed, callback)
|
||||
@@ -319,29 +406,29 @@ var Module = Class.extend({
|
||||
*
|
||||
* argument speed Number - The speed of the show animation.
|
||||
* argument callback function - Called when the animation is done.
|
||||
* argument options object - Optional settings for the hide method.
|
||||
*/
|
||||
show: function(speed, callback) {
|
||||
show: function (speed, callback, options) {
|
||||
if (typeof callback === "object") {
|
||||
options = callback;
|
||||
callback = function () { };
|
||||
}
|
||||
|
||||
callback = callback || function () { };
|
||||
options = options || {};
|
||||
|
||||
this.resume();
|
||||
MM.showModule(this, speed, callback);
|
||||
MM.showModule(this, speed, callback, options);
|
||||
}
|
||||
});
|
||||
|
||||
Module.definitions = {};
|
||||
|
||||
Module.create = function(name) {
|
||||
Module.create = function (name) {
|
||||
|
||||
//Define the clone method for later use.
|
||||
function cloneObject(obj) {
|
||||
if (obj === null || typeof obj !== "object") {
|
||||
return obj;
|
||||
}
|
||||
|
||||
var temp = obj.constructor(); // give temp the original obj"s constructor
|
||||
for (var key in obj) {
|
||||
temp[key] = cloneObject(obj[key]);
|
||||
}
|
||||
|
||||
return temp;
|
||||
// Make sure module definition is available.
|
||||
if (!Module.definitions[name]) {
|
||||
return;
|
||||
}
|
||||
|
||||
var moduleDefinition = Module.definitions[name];
|
||||
@@ -351,10 +438,41 @@ Module.create = function(name) {
|
||||
var ModuleClass = Module.extend(clonedDefinition);
|
||||
|
||||
return new ModuleClass();
|
||||
|
||||
};
|
||||
|
||||
Module.register = function(name, moduleDefinition) {
|
||||
/* cmpVersions(a,b)
|
||||
* Compare two semantic version numbers and return the difference.
|
||||
*
|
||||
* argument a string - Version number a.
|
||||
* argument a string - Version number b.
|
||||
*/
|
||||
function cmpVersions(a, b) {
|
||||
var i, diff;
|
||||
var regExStrip0 = /(\.0+)+$/;
|
||||
var segmentsA = a.replace(regExStrip0, "").split(".");
|
||||
var segmentsB = b.replace(regExStrip0, "").split(".");
|
||||
var l = Math.min(segmentsA.length, segmentsB.length);
|
||||
|
||||
for (i = 0; i < l; i++) {
|
||||
diff = parseInt(segmentsA[i], 10) - parseInt(segmentsB[i], 10);
|
||||
if (diff) {
|
||||
return diff;
|
||||
}
|
||||
}
|
||||
return segmentsA.length - segmentsB.length;
|
||||
}
|
||||
|
||||
Module.register = function (name, moduleDefinition) {
|
||||
|
||||
if (moduleDefinition.requiresVersion) {
|
||||
Log.log("Check MagicMirror version for module '" + name + "' - Minimum version: " + moduleDefinition.requiresVersion + " - Current version: " + version);
|
||||
if (cmpVersions(version, moduleDefinition.requiresVersion) >= 0) {
|
||||
Log.log("Version is ok!");
|
||||
} else {
|
||||
Log.log("Version is incorrect. Skip module: '" + name + "'");
|
||||
return;
|
||||
}
|
||||
}
|
||||
Log.log("Module registered: " + name);
|
||||
Module.definitions[name] = moduleDefinition;
|
||||
};
|
||||
|
@@ -5,7 +5,7 @@
|
||||
* MIT Licensed.
|
||||
*/
|
||||
|
||||
var Class = require("../../../js/class.js");
|
||||
var Class = require("./class.js");
|
||||
var express = require("express");
|
||||
var path = require("path");
|
||||
|
||||
@@ -14,14 +14,29 @@ NodeHelper = Class.extend({
|
||||
console.log("Initializing new module helper ...");
|
||||
},
|
||||
|
||||
loaded: function(callback) {
|
||||
console.log("Module helper loaded: " + this.name);
|
||||
callback();
|
||||
},
|
||||
|
||||
start: function() {
|
||||
console.log("Staring module helper: " + this.name);
|
||||
console.log("Starting module helper: " + this.name);
|
||||
},
|
||||
|
||||
/* stop()
|
||||
* Called when the MagicMirror server receives a `SIGINT`
|
||||
* Close any open connections, stop any sub-processes and
|
||||
* gracefully exit the module.
|
||||
*
|
||||
*/
|
||||
stop: function() {
|
||||
console.log("Stopping module helper: " + this.name);
|
||||
},
|
||||
|
||||
/* socketNotificationReceived(notification, payload)
|
||||
* This method is called when a socket notification arrives.
|
||||
*
|
||||
* argument notification string - The identifier of the noitication.
|
||||
* argument notification string - The identifier of the notification.
|
||||
* argument payload mixed - The payload of the notification.
|
||||
*/
|
||||
socketNotificationReceived: function(notification, payload) {
|
||||
@@ -40,7 +55,7 @@ NodeHelper = Class.extend({
|
||||
/* setPath(path)
|
||||
* Set the module path.
|
||||
*
|
||||
* argument name string - Module name.
|
||||
* argument path string - Module path.
|
||||
*/
|
||||
setPath: function(path) {
|
||||
this.path = path;
|
||||
@@ -49,7 +64,7 @@ NodeHelper = Class.extend({
|
||||
/* sendSocketNotification(notification, payload)
|
||||
* Send a socket notification to the node helper.
|
||||
*
|
||||
* argument notification string - The identifier of the noitication.
|
||||
* argument notification string - The identifier of the notification.
|
||||
* argument payload mixed - The payload of the notification.
|
||||
*/
|
||||
sendSocketNotification: function(notification, payload) {
|
||||
@@ -93,9 +108,10 @@ NodeHelper = Class.extend({
|
||||
|
||||
// register catch all.
|
||||
socket.on("*", function(notification, payload) {
|
||||
if (notification !== "*")
|
||||
//console.log('received message in namespace: ' + namespace);
|
||||
self.socketNotificationReceived(notification, payload);
|
||||
if (notification !== "*") {
|
||||
//console.log('received message in namespace: ' + namespace);
|
||||
self.socketNotificationReceived(notification, payload);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
61
js/server.js
61
js/server.js
@@ -10,21 +10,64 @@ var app = require("express")();
|
||||
var server = require("http").Server(app);
|
||||
var io = require("socket.io")(server);
|
||||
var path = require("path");
|
||||
var ipfilter = require("express-ipfilter").IpFilter;
|
||||
var fs = require("fs");
|
||||
var helmet = require("helmet");
|
||||
var Utils = require(__dirname + "/utils.js");
|
||||
|
||||
var Server = function(config, callback) {
|
||||
console.log("Starting server op port " + config.port + " ... ");
|
||||
|
||||
server.listen(config.port);
|
||||
var port = config.port;
|
||||
if (process.env.MM_PORT) {
|
||||
port = process.env.MM_PORT;
|
||||
}
|
||||
|
||||
console.log("Starting server on port " + port + " ... ");
|
||||
|
||||
server.listen(port, config.address ? config.address : "localhost");
|
||||
|
||||
if (config.ipWhitelist instanceof Array && config.ipWhitelist.length === 0) {
|
||||
console.info(Utils.colors.warn("You're using a full whitelist configuration to allow for all IPs"));
|
||||
}
|
||||
|
||||
app.use(function(req, res, next) {
|
||||
var result = ipfilter(config.ipWhitelist, {mode: config.ipWhitelist.length === 0 ? "deny" : "allow", log: false})(req, res, function(err) {
|
||||
if (err === undefined) {
|
||||
return next();
|
||||
}
|
||||
console.log(err.message);
|
||||
res.status(403).send("This device is not allowed to access your mirror. <br> Please check your config.js or config.js.sample to change this.");
|
||||
});
|
||||
});
|
||||
app.use(helmet());
|
||||
|
||||
app.use("/js", express.static(__dirname));
|
||||
app.use("/config", express.static(path.resolve(__dirname + "/../config")));
|
||||
app.use("/css", express.static(path.resolve(__dirname + "/../css")));
|
||||
app.use("/fonts", express.static(path.resolve(__dirname + "/../fonts")));
|
||||
app.use("/modules", express.static(path.resolve(__dirname + "/../modules")));
|
||||
app.use("/vendor", express.static(path.resolve(__dirname + "/../vendor")));
|
||||
app.use("/translations", express.static(path.resolve(__dirname + "/../translations")));
|
||||
var directories = ["/config", "/css", "/fonts", "/modules", "/vendor", "/translations", "/tests/configs"];
|
||||
var directory;
|
||||
for (var i in directories) {
|
||||
directory = directories[i];
|
||||
app.use(directory, express.static(path.resolve(global.root_path + directory)));
|
||||
}
|
||||
|
||||
app.get("/version", function(req,res) {
|
||||
res.send(global.version);
|
||||
});
|
||||
|
||||
app.get("/config", function(req,res) {
|
||||
res.send(config);
|
||||
});
|
||||
|
||||
app.get("/", function(req, res) {
|
||||
res.sendFile(path.resolve(__dirname + "/../index.html"));
|
||||
var html = fs.readFileSync(path.resolve(global.root_path + "/index.html"), {encoding: "utf8"});
|
||||
html = html.replace("#VERSION#", global.version);
|
||||
|
||||
configFile = "config/config.js";
|
||||
if (typeof(global.configuration_file) !== "undefined") {
|
||||
configFile = global.configuration_file;
|
||||
}
|
||||
html = html.replace("#CONFIG_FILE#", configFile);
|
||||
|
||||
res.send(html);
|
||||
});
|
||||
|
||||
if (typeof callback === "function") {
|
||||
|
@@ -22,7 +22,6 @@ var MMSocket = function(moduleName) {
|
||||
// register catch all.
|
||||
self.socket.on("*", function(notification, payload) {
|
||||
if (notification !== "*") {
|
||||
//console.log('Received notification: ' + notification +', payload: ' + payload);
|
||||
notificationCallback(notification, payload);
|
||||
}
|
||||
});
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user