Compare commits

...

132 Commits

Author SHA1 Message Date
e2b01f6585 chore(deps): lock file maintenance
Some checks failed
continuous-integration/drone/push Build is failing
2024-10-21 23:42:02 +00:00
37b41e2d4b chore(deps): update dependency svelte to v5.0.5
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-21 19:43:34 +00:00
ed8648fcf0 chore(deps): update typescript-eslint monorepo to v8.11.0
Some checks failed
continuous-integration/drone/push Build is failing
2024-10-21 17:39:56 +00:00
114430ed6d chore(deps): update dependency svelte to v5.0.4
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-21 11:45:18 +00:00
9a90ef7f30 chore(deps): lock file maintenance
Some checks failed
continuous-integration/drone/push Build is failing
2024-10-21 00:53:14 +00:00
78006a9da8 chore(deps): update dependency svelte to v5.0.3
Some checks failed
continuous-integration/drone/push Build is failing
2024-10-20 13:47:10 +00:00
edffa5ddf6 chore(deps): update dependency @sveltejs/kit to v2.7.2
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-19 23:56:28 +00:00
77c6b1adc6 chore(deps): update dependency svelte to v5.0.2
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-19 21:56:31 +00:00
0ee5b8a90d chore(deps): update dependency svelte to v5
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-19 19:51:39 +00:00
b65344a766 fix(deps): update dependency sass to v1.80.3
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-18 23:55:52 +00:00
8ed5ef9b35 chore(deps): update dependency eslint to v9.13.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-18 21:49:09 +00:00
dc565088ea fix(deps): update dependency sass to v1.80.2
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-17 21:45:46 +00:00
f2587de80f chore(deps): update typescript-eslint monorepo to v8.10.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-17 17:46:23 +00:00
a83d94b562 fix(deps): update dependency sass to v1.80.1
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-17 03:48:21 +00:00
0795fc616e chore(deps): update dependency @sveltejs/kit to v2.7.1
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-14 22:42:33 +00:00
3818e3926a chore(deps): update typescript-eslint monorepo to v8.9.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-14 17:44:57 +00:00
6c28be7f72 fix(deps): update dependency vite to v5.4.9
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-14 11:42:30 +00:00
e716097f9b chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-14 00:48:17 +00:00
79192bd277 chore(deps): update dependency @sveltejs/kit to v2.7.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-11 18:43:23 +00:00
5b8e676e71 chore(deps): update dependency svelte-check to v4.0.5
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-11 16:48:54 +00:00
a3b00fe38d Add pre-alarm action
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2024-10-11 18:00:15 +02:00
86c81396e2 fix(deps): update dependency sass to v1.79.5
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-11 01:36:40 +00:00
e131a6fdce chore(deps): update dependency typescript to v5.6.3
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-09 11:43:31 +00:00
0265f4cb7b chore(deps): update dependency @sveltejs/kit to v2.6.4
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-09 10:37:07 +00:00
7152c7f377 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-07 19:50:08 +00:00
4c1a2c7b01 chore(deps): update dependency @sveltejs/kit to v2.6.3
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-07 18:42:34 +00:00
b6d37527d7 chore(deps): update typescript-eslint monorepo to v8.8.1
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-07 17:33:25 +00:00
c8cff15d28 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-07 00:42:14 +00:00
bef1c4a3b6 chore(deps): update dependency @sveltejs/kit to v2.6.2
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-06 06:37:12 +00:00
8c09ac3fbe chore(deps): update dependency eslint to v9.12.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-04 21:34:34 +00:00
d4efcf2986 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-30 19:55:03 +00:00
3387b78a42 chore(deps): update typescript-eslint monorepo to v8.8.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-30 17:45:54 +00:00
f4e546a3f1 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-30 01:51:04 +00:00
2026afdb8e fix(deps): update dependency sass to v1.79.4
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-28 03:59:56 +00:00
a4faf89474 chore(deps): update dependency svelte-check to v4.0.4
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-27 23:48:41 +00:00
fd8dcca8e8 chore(deps): update dependency @sveltejs/kit to v2.6.1
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-27 21:42:29 +00:00
e52bb4ff5a chore(deps): update dependency @sveltejs/kit to v2.6.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-27 01:43:55 +00:00
98466d797a chore(deps): update dependency svelte-check to v4.0.3
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-26 13:50:04 +00:00
313aa152ed chore(deps): update dependency prettier-plugin-svelte to v3.2.7
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-26 11:42:18 +00:00
4bf61270d6 fix(deps): update dependency vite to v5.4.8
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-25 04:39:29 +00:00
f3399f39c6 chore(deps): update dependency eslint to v9.11.1
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-23 19:48:33 +00:00
7277799e5d chore(deps): update typescript-eslint monorepo to v8.7.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-23 17:41:16 +00:00
85ece4a101 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-23 00:44:07 +00:00
0a954669be fix(deps): update dependency sass to v1.79.3
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-20 21:41:21 +00:00
47e16d4610 chore(deps): update dependency eslint to v9.11.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-20 17:47:36 +00:00
a77422a561 fix(deps): update dependency vite to v5.4.7
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-20 15:48:46 +00:00
e60059ac13 fix(deps): update dependency sass-loader to v16.0.2
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-20 13:49:03 +00:00
c7d5e61ba6 fix(deps): update dependency sass to v1.79.2
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-19 23:43:31 +00:00
c4d5fb3a96 chore(deps): update dependency @sveltejs/kit to v2.5.28
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-18 01:46:39 +00:00
947c2a2403 fix(deps): update dependency sass to v1.79.1
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-18 00:41:59 +00:00
145bbd4bf1 chore(deps): update dependency @sveltejs/adapter-static to v3.0.5
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-17 17:39:54 +00:00
c45c67d59f fix(deps): update dependency vite to v5.4.6
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-16 20:39:55 +00:00
4e2ffd3e60 chore(deps): update typescript-eslint monorepo to v8.6.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-16 17:37:32 +00:00
c31b1d3188 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-16 00:40:57 +00:00
714fd7636c chore(deps): update dependency @sveltejs/kit to v2.5.27
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-13 16:36:33 +00:00
a8f36c833f fix(deps): update dependency vite to v5.4.5
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-13 09:41:53 +00:00
0085d40b4d chore(deps): update dependency svelte-check to v4.0.2
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-12 11:34:57 +00:00
b055cee040 fix(deps): update dependency vite to v5.4.4
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-11 08:35:18 +00:00
7cacf2dfb7 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-09 18:42:05 +00:00
ac8069f184 chore(deps): update typescript-eslint monorepo to v8.5.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-09 17:34:47 +00:00
890d2a3565 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-09 00:38:40 +00:00
054e575257 chore(deps): update dependency eslint to v9.10.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-06 21:29:59 +00:00
cb9e04fc1d chore(deps): update dependency @sveltejs/kit to v2.5.26
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-04 18:40:50 +00:00
7866f2b0b8 chore(deps): update dependency svelte-check to v4.0.1
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-04 12:33:26 +00:00
5eea245c7c fix(deps): update dependency sass to v1.78.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-03 23:33:48 +00:00
980a99c1c4 fix(deps): update dependency vite to v5.4.3
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-03 16:34:26 +00:00
f933c32ace chore(deps): update typescript-eslint monorepo to v8.4.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-02 17:32:31 +00:00
12a48d025e chore(deps): update dependency svelte-check to v4
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-02 12:32:42 +00:00
271fea3e8a chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-02 00:38:33 +00:00
4f615662f3 Sort track in track list
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-01 17:14:30 +02:00
23fb78b037 chore(deps): update dependency @sveltejs/kit to v2.5.25
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-27 21:34:01 +00:00
7343424b18 chore(deps): update typescript-eslint monorepo to v8.3.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-26 17:30:33 +00:00
92a1643598 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-26 00:38:58 +00:00
006e2722c6 chore(deps): update dependency eslint to v9.9.1
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-23 21:37:02 +00:00
67a0277b42 chore(deps): update dependency svelte to v4.2.19
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-23 16:34:34 +00:00
505bfd81e0 chore(deps): update dependency svelte-check to v3.8.6
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-22 16:28:33 +00:00
a910029353 fix(deps): update dependency dayjs to v1.11.13
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-20 15:31:48 +00:00
8bfd5489b3 fix(deps): update dependency vite to v5.4.2
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-20 14:27:07 +00:00
e3cbfd3d07 chore(deps): update typescript-eslint monorepo to v8.2.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-19 21:35:50 +00:00
b94aea0f33 fix(deps): update dependency sass-loader to v16.0.1
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-19 19:36:41 +00:00
b0c9467ab7 chore(deps): update dependency @sveltejs/kit to v2.5.24
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-19 11:29:49 +00:00
5e91f7227f chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-19 00:35:31 +00:00
02a4cb15a2 fix(deps): update dependency vite to v5.4.1
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-15 15:45:36 +00:00
34aa7477a5 chore(deps): update typescript-eslint monorepo to v8.1.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-15 13:42:21 +00:00
6b914029c9 chore(deps): update dependency @sveltejs/adapter-static to v3.0.4
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-15 11:46:25 +00:00
086bacbedd chore(deps): update dependency @sveltejs/kit to v2.5.22
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-15 08:07:53 +00:00
4c5ebe5988 chore(deps): update dependency eslint to v9
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-06 08:26:48 +00:00
c2fd3d679b chore(deps): update typescript-eslint monorepo to v8
Some checks are pending
continuous-integration/drone/push Build is running
2024-08-06 08:24:37 +00:00
ebffb7b168 fix(deps): update dependency sass-loader to v16
Some checks are pending
continuous-integration/drone/push Build is running
2024-08-06 08:22:58 +00:00
3bc3b1c96d chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-05 00:26:04 +00:00
732df88b04 chore(deps): update dependency @sveltejs/kit to v2.5.20
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-02 17:28:37 +00:00
dd375b79b6 chore(deps): update dependency @sveltejs/kit to v2.5.19
All checks were successful
continuous-integration/drone/push Build is passing
2024-08-01 11:29:18 +00:00
a55084dfd8 chore(deps): update dependency svelte-check to v3.8.5
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-30 17:29:22 +00:00
c8c6282216 Refactor federation + can sync track between instances
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2024-07-30 11:00:05 +02:00
e99efdb43f chore(deps): update typescript-eslint monorepo to v7.18.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-29 17:26:17 +00:00
700e3ad178 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-29 13:27:39 +00:00
25e5362d01 Add delay on federation
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-29 11:16:51 +02:00
5f2a515437 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-29 00:35:52 +00:00
8d8fa1f855 fix(deps): update dependency sass-loader to v15
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-26 07:09:36 +00:00
424eeeaa56 chore(deps): update dependency typescript to v5.5.4
Some checks are pending
continuous-integration/drone/push Build is running
2024-07-25 18:31:55 +00:00
9fa5a378e1 Do federation wakeup/stop
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
2024-07-25 19:38:02 +02:00
435d1d8f98 ui: Can enable federation on alarms 2024-07-25 19:03:21 +02:00
3a6187d791 Add federation settings 2024-07-25 18:53:00 +02:00
60acf77acd fix(deps): update dependency vite to v5.3.5
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-25 09:35:43 +00:00
36e12755be chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-22 18:34:48 +00:00
c3fa97493f chore(deps): update typescript-eslint monorepo to v7.17.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-22 17:31:57 +00:00
e38ee7dc54 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-22 00:37:22 +00:00
e35b8f5f56 chore(deps): update dependency prettier-plugin-svelte to v3.2.6
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-17 13:32:15 +00:00
94516cf15f fix(deps): update dependency vite to v5.3.4
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-16 09:34:41 +00:00
68a723e50a chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-15 19:35:39 +00:00
6dcd59e0d4 chore(deps): update typescript-eslint monorepo to v7.16.1
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-15 17:32:02 +00:00
c47c8116c5 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-15 00:37:55 +00:00
72e550f6b8 chore(deps): update dependency prettier to v3.3.3
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-13 13:34:58 +00:00
0082dfddbd fix(deps): update dependency sass to v1.77.8
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-11 20:32:15 +00:00
d7fa0f1540 fix(deps): update dependency sass to v1.77.7
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-09 22:32:43 +00:00
ee46a8e942 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-08 18:52:39 +00:00
e1b3105ce0 chore(deps): update typescript-eslint monorepo to v7.16.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-08 17:33:24 +00:00
d28f9a34b3 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-08 00:37:54 +00:00
a731e17aba fix(deps): update dependency vite to v5.3.3
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-03 05:35:20 +00:00
93d29b1f90 chore(deps): update typescript-eslint monorepo to v7.15.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-01 17:36:06 +00:00
c936945225 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-07-01 00:41:02 +00:00
972fe4fefc chore(deps): update dependency @sveltejs/kit to v2.5.18
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-29 15:33:27 +00:00
b06b3632ed fix(deps): update dependency vite to v5.3.2
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-27 16:30:02 +00:00
4f453460ad chore(deps): update dependency svelte-check to v3.8.4
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-26 16:28:10 +00:00
bc6e43d971 chore(deps): update dependency svelte-check to v3.8.3
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-26 11:27:31 +00:00
e283731a1f chore(deps): update typescript-eslint monorepo to v7.14.1
Some checks failed
continuous-integration/drone/push Build is failing
2024-06-24 18:27:36 +00:00
9e4dd2c973 chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-24 15:26:48 +00:00
60d7f6a088 chore(deps): update dependency svelte-check to v3.8.2
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-24 14:25:05 +00:00
db688d5dbd chore(deps): lock file maintenance
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-24 00:31:52 +00:00
30ae524669 chore(deps): update dependency prettier-plugin-svelte to v3.2.5
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-20 14:24:08 +00:00
c98ae939bf chore(deps): update dependency svelte-preprocess to v6
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-19 11:34:22 +00:00
b82b1fe50d chore(deps): update dependency @sveltejs/kit to v2.5.17
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-19 03:30:14 +00:00
21 changed files with 1546 additions and 950 deletions

View File

@ -1,11 +1,14 @@
package api package api
import ( import (
"fmt"
"log"
"net/http" "net/http"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"git.nemunai.re/nemunaire/reveil/config" "git.nemunai.re/nemunaire/reveil/config"
"git.nemunai.re/nemunaire/reveil/model"
"git.nemunai.re/nemunaire/reveil/player" "git.nemunai.re/nemunaire/reveil/player"
) )
@ -20,7 +23,7 @@ func declareAlarmRoutes(cfg *config.Config, router *gin.RouterGroup) {
router.POST("/alarm/run", func(c *gin.Context) { router.POST("/alarm/run", func(c *gin.Context) {
if player.CommonPlayer == nil { if player.CommonPlayer == nil {
err := player.WakeUp(cfg, nil) err := player.WakeUp(cfg, nil, true)
if err != nil { if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()}) c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return return
@ -51,6 +54,21 @@ func declareAlarmRoutes(cfg *config.Config, router *gin.RouterGroup) {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()}) c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return return
} }
settings, err := reveil.ReadSettings(cfg.SettingsFile)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Errorf("Unable to read settings: %s", err.Error())})
return
}
for k, srv := range settings.Federation {
err = srv.WakeStop()
if err != nil {
log.Printf("Unable to do federated wakeup on %s: %s", k, err.Error())
} else {
log.Printf("Federated wakeup on %s: launched!", k)
}
}
} }
c.JSON(http.StatusOK, true) c.JSON(http.StatusOK, true)

View File

@ -13,7 +13,7 @@ import (
func declareAlarmsRoutes(cfg *config.Config, db *reveil.LevelDBStorage, resetTimer func(), router *gin.RouterGroup) { func declareAlarmsRoutes(cfg *config.Config, db *reveil.LevelDBStorage, resetTimer func(), router *gin.RouterGroup) {
router.GET("/alarms/next", func(c *gin.Context) { router.GET("/alarms/next", func(c *gin.Context) {
alarm, _, err := reveil.GetNextAlarm(cfg, db) alarm, _, _, err := reveil.GetNextAlarm(cfg, db)
if err != nil { if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()}) c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return return

176
api/federation.go Normal file
View File

@ -0,0 +1,176 @@
package api
import (
"bytes"
"fmt"
"net/http"
"time"
"github.com/gin-gonic/gin"
"git.nemunai.re/nemunaire/reveil/config"
"git.nemunai.re/nemunaire/reveil/model"
"git.nemunai.re/nemunaire/reveil/player"
)
func declareFederationRoutes(cfg *config.Config, router *gin.RouterGroup) {
router.POST("/federation/wakeup", func(c *gin.Context) {
var s map[string]interface{}
c.ShouldBind(s)
if player.CommonPlayer == nil {
var seed int64
if tmp, ok := s["seed"].(int64); ok {
seed = tmp
} else {
seed := time.Now().Unix()
seed -= seed % 172800
}
err := player.WakeUpFromFederation(cfg, seed, nil)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
} else {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Player already running"})
return
}
c.JSON(http.StatusOK, true)
})
router.POST("/federation/wakeok", func(c *gin.Context) {
if player.CommonPlayer != nil {
err := player.CommonPlayer.Stop()
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
}
c.JSON(http.StatusOK, true)
})
router.GET("/federation", func(c *gin.Context) {
settings, err := reveil.ReadSettings(cfg.SettingsFile)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
c.JSON(http.StatusOK, settings.Federation)
})
federationsRoutes := router.Group("/federation/:fid")
federationsRoutes.Use(func(c *gin.Context) {
settings, err := reveil.ReadSettings(cfg.SettingsFile)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
f, ok := settings.Federation[string(c.Param("fid"))]
if !ok {
c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Action not found"})
return
}
c.Set("federation", &f)
c.Next()
})
federationsRoutes.GET("", func(c *gin.Context) {
c.JSON(http.StatusOK, c.MustGet("federation"))
})
federationsRoutes.POST("sync", func(c *gin.Context) {
srv := c.MustGet("federation").(*reveil.FederationServer)
// Retrieve music list on remote
remoteMusics, err := srv.GetMusics()
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("Unable to retrieve remote tracks lists: %s", err.Error())})
return
}
// Retrieve local music list
localMusics, err := reveil.LoadTracks(cfg)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("Unable to retrieve local tracks: %s", err.Error())})
return
}
// Compute diff
var newMusics []reveil.Track
var oldMusics []reveil.Track
var musicsToEnable []reveil.Track
for _, rTrack := range remoteMusics {
found := false
for _, lTrack := range localMusics {
if bytes.Compare(lTrack.Id, rTrack.Id) == 0 || lTrack.Name == rTrack.Name {
if lTrack.Enabled != rTrack.Enabled {
if lTrack.Enabled {
musicsToEnable = append(musicsToEnable, rTrack)
} else {
oldMusics = append(oldMusics, *lTrack)
}
}
found = true
break
}
}
if !found && rTrack.Enabled {
oldMusics = append(oldMusics, rTrack)
}
}
for _, lTrack := range localMusics {
found := false
for _, rTrack := range remoteMusics {
if bytes.Compare(lTrack.Id, rTrack.Id) == 0 || lTrack.Name == rTrack.Name {
found = true
break
}
}
if !found && lTrack.Enabled {
newMusics = append(newMusics, *lTrack)
}
}
// Disable unexistant musics on local
for _, t := range oldMusics {
t.Enabled = false
err = srv.UpdateTrack(&t)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("An error occurs when disabling remote tracks (unexistant on local): %s: %s", t.Id.ToString(), err.Error())})
return
}
}
// Enable existant musics on remote
for _, t := range musicsToEnable {
t.Enabled = true
err = srv.UpdateTrack(&t)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
}
// Send new musics
for _, t := range newMusics {
err = srv.SendTrack(&t)
if err != nil {
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
return
}
}
c.JSON(http.StatusOK, true)
})
}

View File

@ -13,6 +13,7 @@ func DeclareRoutes(router *gin.Engine, cfg *config.Config, db *reveil.LevelDBSto
declareActionsRoutes(cfg, apiRoutes) declareActionsRoutes(cfg, apiRoutes)
declareAlarmRoutes(cfg, apiRoutes) declareAlarmRoutes(cfg, apiRoutes)
declareAlarmsRoutes(cfg, db, resetTimer, apiRoutes) declareAlarmsRoutes(cfg, db, resetTimer, apiRoutes)
declareFederationRoutes(cfg, apiRoutes)
declareGongsRoutes(cfg, apiRoutes) declareGongsRoutes(cfg, apiRoutes)
declareHistoryRoutes(cfg, apiRoutes) declareHistoryRoutes(cfg, apiRoutes)
declareQuotesRoutes(cfg, apiRoutes) declareQuotesRoutes(cfg, apiRoutes)

39
app.go
View File

@ -21,6 +21,7 @@ type App struct {
router *gin.Engine router *gin.Engine
srv *http.Server srv *http.Server
nextAlarm *time.Timer nextAlarm *time.Timer
nextPreAlarm *time.Timer
} }
func NewApp(cfg *config.Config) *App { func NewApp(cfg *config.Config) *App {
@ -76,18 +77,52 @@ func (app *App) Start() {
func (app *App) ResetTimer() { func (app *App) ResetTimer() {
if app.nextAlarm != nil { if app.nextAlarm != nil {
app.nextAlarm.Stop() app.nextAlarm.Stop()
app.nextPreAlarm = nil
app.nextAlarm = nil app.nextAlarm = nil
} }
if na, routines, err := reveil.GetNextAlarm(app.cfg, app.db); err == nil && na != nil { settings, _ := reveil.ReadSettings(app.cfg.SettingsFile)
if na, routines, federated, err := reveil.GetNextAlarm(app.cfg, app.db); err == nil && na != nil {
if settings != nil && settings.PreAlarmAction != "" {
app.nextPreAlarm = time.AfterFunc(time.Until(*na)-settings.PreAlarmActionDelay*time.Minute, func() {
app.nextPreAlarm = nil
settings, err := reveil.ReadSettings(app.cfg.SettingsFile)
if err != nil {
log.Println("Unable to read settings:", err.Error())
return
}
action, err := reveil.LoadAction(app.cfg, settings.PreAlarmAction)
if err != nil {
log.Println("Unable to load pre-alarm action:", err.Error())
}
cmd, err := action.Launch(settings)
if err != nil {
log.Println(err.Error())
return
}
go func() {
err := cmd.Wait()
if err != nil {
log.Printf("%q: %s", action.Name, err.Error())
}
}()
})
log.Println("Next pre-alarm programmed for", time.Time(*na).Add(settings.PreAlarmActionDelay*-1*time.Minute))
}
app.nextAlarm = time.AfterFunc(time.Until(*na), func() { app.nextAlarm = time.AfterFunc(time.Until(*na), func() {
app.nextPreAlarm = nil
app.nextAlarm = nil app.nextAlarm = nil
reveil.RemoveOldAlarmsSingle(app.db) reveil.RemoveOldAlarmsSingle(app.db)
// Rearm timer for the next time // Rearm timer for the next time
app.ResetTimer() app.ResetTimer()
err := player.WakeUp(app.cfg, routines) err := player.WakeUp(app.cfg, routines, federated)
if err != nil { if err != nil {
log.Println(err.Error()) log.Println(err.Error())
return return

View File

@ -40,25 +40,27 @@ func (h *Hour) UnmarshalJSON(src []byte) error {
return nil return nil
} }
func GetNextAlarm(cfg *config.Config, db *LevelDBStorage) (*time.Time, []Identifier, error) { func GetNextAlarm(cfg *config.Config, db *LevelDBStorage) (*time.Time, []Identifier, bool, error) {
alarmsRepeated, err := GetAlarmsRepeated(db) alarmsRepeated, err := GetAlarmsRepeated(db)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, false, err
} }
var closestAlarm *time.Time var closestAlarm *time.Time
var closestAlarmRoutines []Identifier var closestAlarmRoutines []Identifier
var closestAlarmFederated bool
for _, alarm := range alarmsRepeated { for _, alarm := range alarmsRepeated {
next := alarm.GetNextOccurence(cfg, db) next := alarm.GetNextOccurence(cfg, db)
if next != nil && (closestAlarm == nil || closestAlarm.After(*next)) { if next != nil && (closestAlarm == nil || closestAlarm.After(*next)) {
closestAlarm = next closestAlarm = next
closestAlarmRoutines = alarm.FollowingRoutines closestAlarmRoutines = alarm.FollowingRoutines
closestAlarmFederated = alarm.EnableFederation
} }
} }
alarmsSingle, err := GetAlarmsSingle(db) alarmsSingle, err := GetAlarmsSingle(db)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, false, err
} }
now := time.Now() now := time.Now()
@ -66,10 +68,11 @@ func GetNextAlarm(cfg *config.Config, db *LevelDBStorage) (*time.Time, []Identif
if closestAlarm == nil || (closestAlarm.After(alarm.Time) && alarm.Time.After(now)) { if closestAlarm == nil || (closestAlarm.After(alarm.Time) && alarm.Time.After(now)) {
closestAlarm = &alarm.Time closestAlarm = &alarm.Time
closestAlarmRoutines = alarm.FollowingRoutines closestAlarmRoutines = alarm.FollowingRoutines
closestAlarmFederated = alarm.EnableFederation
} }
} }
return closestAlarm, closestAlarmRoutines, nil return closestAlarm, closestAlarmRoutines, closestAlarmFederated, nil
} }
func GetNextException(cfg *config.Config, db *LevelDBStorage) (*time.Time, error) { func GetNextException(cfg *config.Config, db *LevelDBStorage) (*time.Time, error) {
@ -90,7 +93,7 @@ func GetNextException(cfg *config.Config, db *LevelDBStorage) (*time.Time, error
} }
func DropNextAlarm(cfg *config.Config, db *LevelDBStorage) error { func DropNextAlarm(cfg *config.Config, db *LevelDBStorage) error {
timenext, _, err := GetNextAlarm(cfg, db) timenext, _, _, err := GetNextAlarm(cfg, db)
if err != nil { if err != nil {
return err return err
} }
@ -152,6 +155,7 @@ type AlarmRepeated struct {
Disabled bool `json:"disabled,omitempty"` Disabled bool `json:"disabled,omitempty"`
Excepts Exceptions `json:"excepts,omitempty"` Excepts Exceptions `json:"excepts,omitempty"`
NextTime *time.Time `json:"next_time,omitempty"` NextTime *time.Time `json:"next_time,omitempty"`
EnableFederation bool `json:"enable_federation,omitempty"`
} }
func (a *AlarmRepeated) FillExcepts(cfg *config.Config, db *LevelDBStorage) error { func (a *AlarmRepeated) FillExcepts(cfg *config.Config, db *LevelDBStorage) error {
@ -273,6 +277,7 @@ type AlarmSingle struct {
Time time.Time `json:"time"` Time time.Time `json:"time"`
FollowingRoutines []Identifier `json:"routines"` FollowingRoutines []Identifier `json:"routines"`
Comment string `json:"comment,omitempty"` Comment string `json:"comment,omitempty"`
EnableFederation bool `json:"enable_federation,omitempty"`
} }
func GetAlarmSingle(db *LevelDBStorage, id Identifier) (alarm *AlarmSingle, err error) { func GetAlarmSingle(db *LevelDBStorage, id Identifier) (alarm *AlarmSingle, err error) {

137
model/federation.go Normal file
View File

@ -0,0 +1,137 @@
package reveil
import (
"bytes"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
)
type FederationServer struct {
URL string `json:"url"`
Delay uint `json:"delay"`
}
func (srv *FederationServer) WakeUp(seed int64) error {
req := map[string]interface{}{"seed": seed}
req_enc, err := json.Marshal(req)
if err != nil {
return err
}
res, err := http.Post(srv.URL+"/api/federation/wakeup", "application/json", bytes.NewBuffer(req_enc))
if err != nil {
return err
}
res.Body.Close()
return nil
}
func (srv *FederationServer) WakeStop() error {
res, err := http.Post(srv.URL+"/api/federation/wakeok", "application/json", nil)
if err != nil {
return err
}
res.Body.Close()
return nil
}
func (srv *FederationServer) GetMusics() ([]Track, error) {
res, err := http.Get(srv.URL + "/api/tracks")
if err != nil {
return nil, err
}
defer res.Body.Close()
var tracks []Track
err = json.NewDecoder(res.Body).Decode(&tracks)
if err != nil {
return nil, err
}
return tracks, nil
}
func (srv *FederationServer) UpdateTrack(t *Track) error {
req_enc, err := json.Marshal(t)
if err != nil {
return err
}
req, err := http.NewRequest("PUT", srv.URL+"/api/tracks/"+t.Id.ToString(), bytes.NewBuffer(req_enc))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode == http.StatusOK {
var track Track
err = json.NewDecoder(res.Body).Decode(&track)
if err != nil {
return err
}
} else {
var errmsg map[string]string
err = json.NewDecoder(res.Body).Decode(&errmsg)
if err != nil {
return err
} else {
return fmt.Errorf("%s", errmsg["errmsg"])
}
}
return nil
}
func (srv *FederationServer) SendTrack(track *Track) error {
// Retrieve file
fd, err := track.Open()
if err != nil {
return err
}
defer fd.Close()
var b bytes.Buffer
w := multipart.NewWriter(&b)
var fw io.Writer
// Add an image file
if fw, err = w.CreateFormFile("trackfile", fd.Name()); err != nil {
return err
}
if _, err = io.Copy(fw, fd); err != nil {
return err
}
w.Close()
//
req, err := http.NewRequest("POST", srv.URL+"/api/tracks", &b)
if err != nil {
return err
}
req.Header.Set("Content-Type", w.FormDataContentType())
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
if res.StatusCode != http.StatusOK {
return fmt.Errorf("bad status: %s", res.Status)
}
return nil
}

View File

@ -12,8 +12,11 @@ type Settings struct {
GongInterval time.Duration `json:"gong_interval"` GongInterval time.Duration `json:"gong_interval"`
WeatherDelay time.Duration `json:"weather_delay"` WeatherDelay time.Duration `json:"weather_delay"`
WeatherAction string `json:"weather_action"` WeatherAction string `json:"weather_action"`
PreAlarmActionDelay time.Duration `json:"pre_alarm_delay"`
PreAlarmAction string `json:"pre_alarm_action"`
MaxRunTime time.Duration `json:"max_run_time"` MaxRunTime time.Duration `json:"max_run_time"`
MaxVolume uint16 `json:"max_volume"` MaxVolume uint16 `json:"max_volume"`
Federation map[string]FederationServer `json:"federation"`
} }
// ExistsSettings checks if the settings file can by found at the given path. // ExistsSettings checks if the settings file can by found at the given path.

29
player/federation.go Normal file
View File

@ -0,0 +1,29 @@
package player
import (
"log"
"time"
"git.nemunai.re/nemunaire/reveil/model"
)
func FederatedWakeUp(k string, srv reveil.FederationServer, seed int64) {
if srv.Delay == 0 {
err := srv.WakeUp(seed)
if err != nil {
log.Printf("Unable to do federated wakeup on %s: %s", k, err.Error())
} else {
log.Printf("Federated wakeup on %s: launched!", k)
}
} else {
go func() {
time.Sleep(time.Duration(srv.Delay) * time.Millisecond)
err := srv.WakeUp(seed)
if err != nil {
log.Printf("Unable to do federated wakeup on %s: %s", k, err.Error())
} else {
log.Printf("Federated wakeup on %s: launched!", k)
}
}()
}
}

View File

@ -43,13 +43,29 @@ type Player struct {
playedItem int playedItem int
} }
func WakeUp(cfg *config.Config, routine []reveil.Identifier) (err error) { func WakeUp(cfg *config.Config, routine []reveil.Identifier, federated bool) (err error) {
if CommonPlayer != nil { if CommonPlayer != nil {
return fmt.Errorf("Unable to start the player: a player is already running") return fmt.Errorf("Unable to start the player: a player is already running")
} }
seed := time.Now().Unix() seed := time.Now().Unix()
seed -= seed % 172800 seed -= seed % 172800
if federated {
settings, err := reveil.ReadSettings(cfg.SettingsFile)
if err != nil {
return fmt.Errorf("Unable to read settings: %w", err)
}
for k, srv := range settings.Federation {
FederatedWakeUp(k, srv, seed)
}
}
return WakeUpFromFederation(cfg, seed, routine)
}
func WakeUpFromFederation(cfg *config.Config, seed int64, routine []reveil.Identifier) (err error) {
rand.Seed(seed) rand.Seed(seed)
CommonPlayer, err = NewPlayer(cfg, routine) CommonPlayer, err = NewPlayer(cfg, routine)

View File

@ -24,7 +24,7 @@ func DeclareNoJSRoutes(router *gin.Engine, cfg *config.Config, db *reveil.LevelD
router.SetHTMLTemplate(templ) router.SetHTMLTemplate(templ)
router.GET("/nojs.html", func(c *gin.Context) { router.GET("/nojs.html", func(c *gin.Context) {
alarm, _, err := reveil.GetNextAlarm(cfg, db) alarm, _, _, err := reveil.GetNextAlarm(cfg, db)
if err != nil { if err != nil {
c.HTML(http.StatusInternalServerError, "error.tmpl", gin.H{"errmsg": err.Error()}) c.HTML(http.StatusInternalServerError, "error.tmpl", gin.H{"errmsg": err.Error()})
return return
@ -122,7 +122,7 @@ func DeclareNoJSRoutes(router *gin.Engine, cfg *config.Config, db *reveil.LevelD
case "start": case "start":
if player.CommonPlayer == nil { if player.CommonPlayer == nil {
err := player.WakeUp(cfg, nil) err := player.WakeUp(cfg, nil, true)
if err != nil { if err != nil {
c.HTML(http.StatusInternalServerError, "error.tmpl", gin.H{"errmsg": err.Error()}) c.HTML(http.StatusInternalServerError, "error.tmpl", gin.H{"errmsg": err.Error()})
return return

1799
ui/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -15,19 +15,19 @@
"@sveltejs/adapter-static": "^3.0.0", "@sveltejs/adapter-static": "^3.0.0",
"@sveltejs/kit": "^2.0.0", "@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0",
"@typescript-eslint/eslint-plugin": "^7.0.0", "@typescript-eslint/eslint-plugin": "^8.0.0",
"@typescript-eslint/parser": "^7.0.0", "@typescript-eslint/parser": "^8.0.0",
"bootstrap": "^5.1.3", "bootstrap": "^5.1.3",
"bootstrap-icons": "^1.8.0", "bootstrap-icons": "^1.8.0",
"bootswatch": "^5.1.3", "bootswatch": "^5.1.3",
"eslint": "^8.0.0", "eslint": "^9.0.0",
"eslint-config-prettier": "^9.0.0", "eslint-config-prettier": "^9.0.0",
"eslint-plugin-svelte": "^2.33.0", "eslint-plugin-svelte": "^2.33.0",
"prettier": "^3.1.1", "prettier": "^3.1.1",
"prettier-plugin-svelte": "^3.1.2", "prettier-plugin-svelte": "^3.1.2",
"svelte": "^4.0.0", "svelte": "^5.0.0",
"svelte-check": "^3.4.3", "svelte-check": "^4.0.0",
"svelte-preprocess": "^5.0.3", "svelte-preprocess": "^6.0.0",
"tslib": "^2.3.1", "tslib": "^2.3.1",
"typescript": "^5.0.0" "typescript": "^5.0.0"
}, },
@ -35,7 +35,7 @@
"dependencies": { "dependencies": {
"dayjs": "^1.11.5", "dayjs": "^1.11.5",
"sass": "^1.49.7", "sass": "^1.49.7",
"sass-loader": "^14.0.0", "sass-loader": "^16.0.0",
"@sveltestrap/sveltestrap": "^6.0.0", "@sveltestrap/sveltestrap": "^6.0.0",
"vite": "^5.0.0" "vite": "^5.0.0"
} }

View File

@ -5,7 +5,7 @@ export class AlarmRepeated {
} }
} }
update({ id, weekday, time, routines, disabled, ignore_exceptions, comment, excepts, next_time }) { update({ id, weekday, time, routines, disabled, ignore_exceptions, comment, excepts, next_time, enable_federation }) {
this.id = id; this.id = id;
this.weekday = weekday; this.weekday = weekday;
this.time = time; this.time = time;
@ -13,6 +13,7 @@ export class AlarmRepeated {
this.ignore_exceptions = ignore_exceptions; this.ignore_exceptions = ignore_exceptions;
this.comment = comment; this.comment = comment;
this.disabled = disabled == true; this.disabled = disabled == true;
this.enable_federation = enable_federation == true;
if (excepts !== undefined) if (excepts !== undefined)
this.excepts = excepts; this.excepts = excepts;
if (next_time !== undefined) if (next_time !== undefined)

View File

@ -5,11 +5,12 @@ export class AlarmSingle {
} }
} }
update({ id, time, routines, comment }) { update({ id, time, routines, comment, enable_federation }) {
this.id = id; this.id = id;
this.time = new Date(time); this.time = new Date(time);
this.routines = routines == null ? [] : routines; this.routines = routines == null ? [] : routines;
this.comment = comment; this.comment = comment;
this.enable_federation = enable_federation == true;
if (this.routines.length < 1) { if (this.routines.length < 1) {
this.routines.push(""); this.routines.push("");

View File

@ -0,0 +1,134 @@
<script>
import { createEventDispatcher } from 'svelte';
import {
Button,
Col,
Icon,
Input,
InputGroup,
InputGroupText,
Row,
Spinner,
} from '@sveltestrap/sveltestrap';
const dispatch = createEventDispatcher();
export let id = "";
export let value = { };
function changeKey(bak, to) {
if (bak === null && to.target.value) {
if (!value) value = { };
value[to.target.value] = { url:"" };
to.target.value = "";
value = value;
} else {
value[to.target.value] = value[bak];
delete value[bak];
}
}
const syncInProgress = { };
async function syncMusic(srv) {
syncInProgress[srv] = true;
const res = await fetch(`api/federation/${srv}/sync`, {
method: 'POST',
headers: {'Accept': 'application/json'}
});
if (res.status != 200) {
throw new Error((await res.json()).errmsg);
}
syncInProgress[srv] = false;
}
</script>
{#if value}
{#each Object.keys(value) as key}
<Row class="mb-3">
<Col>
<Input
type="string"
value={key}
on:change={() => dispatch("input")}
on:input={(e) => changeKey(key, e)}
/>
</Col>
<Col>
<InputGroup>
<Input
type="string"
placeholder="https://reveil.fr/"
bind:value={value[key].url}
on:change={() => dispatch("input")}
/>
<Button
href={value[key].url}
target="_blank"
>
<Icon name="globe" />
</Button>
</InputGroup>
</Col>
<Col>
<Row>
<Col>
<InputGroup>
<Input
type="number"
placeholder="60"
bind:value={value[key].delay}
on:change={() => dispatch("input")}
/>
<InputGroupText>ms</InputGroupText>
</InputGroup>
</Col>
<Col xs="auto">
<Button
color="info"
disabled={syncInProgress[key]}
title="Synchroniser les musiques"
type="button"
on:click={() => syncMusic(key)}
>
{#if syncInProgress[key]}
<Spinner size="sm" />
{:else}
<Icon name="music-note-list" />
{/if}
</Button>
</Col>
</Row>
</Col>
</Row>
{/each}
{/if}
<Row>
<Col>
<Input
type="string"
{id}
placeholder="name"
value=""
on:input={(e) => changeKey(null, e)}
/>
</Col>
<Col>
<Input
type="string"
placeholder="https://reveil.fr/"
disabled
value=""
/>
</Col>
<Col>
<Input
type="number"
placeholder="60"
disabled
value=""
/>
</Col>
</Row>

View File

@ -5,13 +5,16 @@ export class Settings {
} }
} }
update({ language, gong_interval, weather_delay, weather_action, max_run_time, max_volume }) { update({ language, gong_interval, weather_delay, weather_action, pre_alarm_delay, pre_alarm_action, max_run_time, max_volume, federation }) {
this.language = language; this.language = language;
this.gong_interval = gong_interval; this.gong_interval = gong_interval;
this.weather_delay = weather_delay; this.weather_delay = weather_delay;
this.weather_action = weather_action; this.weather_action = weather_action;
this.pre_alarm_delay = pre_alarm_delay;
this.pre_alarm_action = pre_alarm_action;
this.max_run_time = max_run_time; this.max_run_time = max_run_time;
this.max_volume = max_volume; this.max_volume = max_volume;
this.federation = federation;
} }
async save() { async save() {

View File

@ -2,6 +2,18 @@ import { writable } from 'svelte/store';
import { getTracks } from '$lib/track' import { getTracks } from '$lib/track'
function cmpTracks(a, b) {
if (a.enabled && !b.enabled) return -1;
if (!a.enabled && b.enabled) return 1;
if (a.path.toLowerCase() > b.path.toLowerCase())
return 1;
if (a.path.toLowerCase() < b.path.toLowerCase())
return -1;
return 0;
}
function createTracksStore() { function createTracksStore() {
const { subscribe, set, update } = writable({list: null}); const { subscribe, set, update } = writable({list: null});
@ -14,6 +26,7 @@ function createTracksStore() {
refresh: async () => { refresh: async () => {
const list = await getTracks(); const list = await getTracks();
list.sort(cmpTracks);
update((m) => Object.assign(m, {list})); update((m) => Object.assign(m, {list}));
return list; return list;
}, },

View File

@ -95,6 +95,10 @@
<ListGroupItem> <ListGroupItem>
<strong>Heure du réveil</strong> <DateFormat date={alarm.time} timeStyle="long" /> <strong>Heure du réveil</strong> <DateFormat date={alarm.time} timeStyle="long" />
</ListGroupItem> </ListGroupItem>
<ListGroupItem class="d-flex">
<strong>Fédération activée&nbsp;?</strong>
<Input type="switch" class="ms-2" on:change={() => {obj.enable_federation = !obj.enable_federation; obj.save();}} checked={obj.enable_federation} /> {obj.enable_federation?"oui":"non"}
</ListGroupItem>
</ListGroup> </ListGroup>
{/await} {/await}
{:else if $page.params["kind"] == "repeated"} {:else if $page.params["kind"] == "repeated"}
@ -126,6 +130,10 @@
<strong>Ignorer les exceptions&nbsp;?</strong> <strong>Ignorer les exceptions&nbsp;?</strong>
<Input type="switch" class="ms-2" on:change={() => {obj.ignore_exceptions = !obj.ignore_exceptions; obj.save();}} checked={obj.ignore_exceptions} /> {obj.ignore_exceptions?"oui":"non"} <Input type="switch" class="ms-2" on:change={() => {obj.ignore_exceptions = !obj.ignore_exceptions; obj.save();}} checked={obj.ignore_exceptions} /> {obj.ignore_exceptions?"oui":"non"}
</ListGroupItem> </ListGroupItem>
<ListGroupItem class="d-flex">
<strong>Fédération activée&nbsp;?</strong>
<Input type="switch" class="ms-2" on:change={() => {obj.enable_federation = !obj.enable_federation; obj.save();}} checked={obj.enable_federation} /> {obj.enable_federation?"oui":"non"}
</ListGroupItem>
{#if alarm.next_time} {#if alarm.next_time}
<ListGroupItem> <ListGroupItem>
<strong>Prochaine occurrence</strong> <DateFormat date={new Date(obj.next_time)} dateStyle="long" /> <strong>Prochaine occurrence</strong> <DateFormat date={new Date(obj.next_time)} dateStyle="long" />

View File

@ -154,6 +154,11 @@
<Input id="exceptionEnd" type="date" required bind:value={obj.end} /> <Input id="exceptionEnd" type="date" required bind:value={obj.end} />
</FormGroup> </FormGroup>
{/if} {/if}
{#if $page.params["kind"] != "exceptions"}
<FormGroup>
<Input id="enable_federation" type="checkbox" label="Activer la fédération" bind:checked={obj.enable_federation} />
</FormGroup>
{/if}
<FormGroup> <FormGroup>
<Label for="comment">Commentaire</Label> <Label for="comment">Commentaire</Label>

View File

@ -15,6 +15,7 @@
import { actions } from '$lib/stores/actions'; import { actions } from '$lib/stores/actions';
import { getSettings } from '$lib/settings'; import { getSettings } from '$lib/settings';
import FederationSettings from '$lib/components/FederationSettings.svelte';
let settingsP = getSettings(); let settingsP = getSettings();
@ -88,6 +89,40 @@
{/if} {/if}
</FormGroup> </FormGroup>
<FormGroup>
<Label for="preAlarmDelay">Lancement action pré-alarme</Label>
<InputGroup>
<Input
type="number"
id="preAlarmDelay"
placeholder="5"
bind:value={settings.pre_alarm_delay}
on:input={submitSettings}
/>
<InputGroupText>min</InputGroupText>
</InputGroup>
</FormGroup>
<FormGroup>
<Label for="preAlarmRituel">Action pour l'action pré-alarme</Label>
{#if $actions.list}
<Input
type="select"
id="preAlarmRituel"
bind:value={settings.pre_alarm_action}
on:input={submitSettings}
>
{#each $actions.list as action (action.id)}
<option value="{action.path}">{action.name}</option>
{/each}
</Input>
{:else}
<div class="d-flex justify-content-center align-items-center gap-2">
<Spinner color="primary" /> Chargement en cours&hellip;
</div>
{/if}
</FormGroup>
<FormGroup> <FormGroup>
<Label for="greetingLanguage">Langue de salutation</Label> <Label for="greetingLanguage">Langue de salutation</Label>
<Input <Input
@ -130,6 +165,15 @@
/> />
</InputGroup> </InputGroup>
</FormGroup> </FormGroup>
<FormGroup>
<Label for="federation">Federation</Label>
<FederationSettings
id="federation"
bind:value={settings.federation}
on:input={submitSettings}
/>
</FormGroup>
{/await} {/await}
</Form> </Form>
</Container> </Container>