Compare commits

..

No commits in common. "master" and "v0.5.1" have entirely different histories.

40 changed files with 1697 additions and 1833 deletions

View file

@ -13,7 +13,7 @@ workspace:
steps: steps:
- name: build front - name: build front
image: node:22 image: node:21
commands: commands:
- mkdir deploy - mkdir deploy
- cd ui - cd ui

View file

@ -1,4 +1,4 @@
FROM node:22-alpine as nodebuild FROM node:21-alpine as nodebuild
WORKDIR /ui WORKDIR /ui
@ -18,7 +18,7 @@ WORKDIR /go/src/git.nemunai.re/nemunaire/reveil
RUN go get -v && go generate -v && go build -tags pulse -ldflags="-s -w" RUN go get -v && go generate -v && go build -tags pulse -ldflags="-s -w"
FROM alpine:3.22 FROM alpine:3.20
VOLUME /data VOLUME /data
WORKDIR /data WORKDIR /data

View file

@ -1,4 +1,4 @@
FROM alpine:3.22 FROM alpine:3.20
VOLUME /data VOLUME /data
WORKDIR /data WORKDIR /data

70
app.go
View file

@ -16,13 +16,11 @@ import (
) )
type App struct { type App struct {
cfg *config.Config cfg *config.Config
db *reveil.LevelDBStorage db *reveil.LevelDBStorage
router *gin.Engine router *gin.Engine
srv *http.Server srv *http.Server
nextAlarm *time.Timer nextAlarm *time.Timer
nextPreAlarm *time.Timer
ticker *time.Ticker
} }
func NewApp(cfg *config.Config) *App { func NewApp(cfg *config.Config) *App {
@ -62,10 +60,6 @@ func NewApp(cfg *config.Config) *App {
} }
func (app *App) Start() { func (app *App) Start() {
if app.ticker != nil {
app.ticker.Stop()
}
app.srv = &http.Server{ app.srv = &http.Server{
Addr: app.cfg.Bind, Addr: app.cfg.Bind,
Handler: app.router, Handler: app.router,
@ -73,70 +67,20 @@ func (app *App) Start() {
app.ResetTimer() app.ResetTimer()
go app.CheckTime()
log.Printf("Ready, listening on %s\n", app.cfg.Bind) log.Printf("Ready, listening on %s\n", app.cfg.Bind)
if err := app.srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { if err := app.srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("listen: %s\n", err) log.Fatalf("listen: %s\n", err)
} }
} }
func (app *App) CheckTime() {
app.ticker = time.NewTicker(time.Minute)
startTime := time.Now()
for range app.ticker.C {
if time.Since(startTime).Round(time.Second).Seconds() != time.Since(startTime.Round(0)).Round(time.Second).Seconds() {
app.ResetTimer()
startTime = time.Now()
}
}
}
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
} }
settings, _ := reveil.ReadSettings(app.cfg.SettingsFile)
if na, routines, federated, err := reveil.GetNextAlarm(app.cfg, app.db); err == nil && na != nil { 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)
@ -158,10 +102,6 @@ func (app *App) Stop() {
app.nextAlarm.Stop() app.nextAlarm.Stop()
} }
if app.ticker != nil {
app.ticker.Stop()
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel() defer cancel()
if err := app.srv.Shutdown(ctx); err != nil { if err := app.srv.Shutdown(ctx); err != nil {

25
go.mod
View file

@ -1,17 +1,17 @@
module git.nemunai.re/nemunaire/reveil module git.nemunai.re/nemunaire/reveil
go 1.23.0 go 1.18
toolchain go1.24.4
require ( require (
github.com/gin-gonic/gin v1.10.1 github.com/faiface/beep v1.1.0
github.com/gin-gonic/gin v1.10.0
github.com/syndtr/goleveldb v1.0.0 github.com/syndtr/goleveldb v1.0.0
) )
require ( require (
github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect github.com/cloudwego/iasm v0.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect
@ -21,20 +21,29 @@ require (
github.com/go-playground/validator/v10 v10.20.0 // indirect github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/snappy v0.0.1 // indirect github.com/golang/snappy v0.0.1 // indirect
github.com/hajimehoshi/go-mp3 v0.3.0 // indirect
github.com/hajimehoshi/oto v0.7.1 // indirect
github.com/icza/bitio v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mewkiz/flac v1.0.7 // indirect
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.8.0 // indirect golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.36.0 // indirect golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.38.0 // indirect golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8 // indirect
golang.org/x/sys v0.31.0 // indirect golang.org/x/image v0.0.0-20190227222117-0694c2d4d067 // indirect
golang.org/x/text v0.23.0 // indirect golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect google.golang.org/protobuf v1.34.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect

166
go.sum
View file

@ -1,50 +1,119 @@
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/faiface/beep v1.1.0 h1:A2gWP6xf5Rh7RG/p9/VAW2jRSDEGQm5sbOb38sf5d4c=
github.com/faiface/beep v1.1.0/go.mod h1:6I8p6kK2q4opL/eWb+kAkk38ehnTunWeToJB+s51sT4=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg=
github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ= github.com/gin-gonic/gin v1.8.1 h1:4+fr/el88TOO3ewCmQr8cx/CtZ/umlIRIs5M4NTNjf8=
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-audio/audio v1.0.0/go.mod h1:6uAu0+H2lHkwdGsAY+j2wHPNPpPoeg5AaEFh9FlA+Zs=
github.com/go-audio/riff v1.0.0/go.mod h1:l3cQwc85y79NQFCRB7TiPoNiaijp6q8Z0Uv38rVG498=
github.com/go-audio/wav v1.0.0/go.mod h1:3yoReyQOsiARkvPl3ERCi8JFjihzG6WhjYpZCf5zAWE=
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.0 h1:u50s323jtVGugKlcYeyzC0etD1HifMjqmJqb8WugfUU=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/jYrnRPArHwAcmLoJZxyho=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.10.0 h1:I7mrTYv78z8k8VXa/qJlOlEXn/nBh+BF8dHX5nt/dr0=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/hajimehoshi/go-mp3 v0.3.0 h1:fTM5DXjp/DL2G74HHAs/aBGiS9Tg7wnp+jkU38bHy4g=
github.com/hajimehoshi/go-mp3 v0.3.0/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM=
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
github.com/hajimehoshi/oto v0.7.1 h1:I7maFPz5MBCwiutOrz++DLdbr4rTzBsbBuV2VpgU9kk=
github.com/hajimehoshi/oto v0.7.1/go.mod h1:wovJ8WWMfFKvP587mhHgot/MBr4DnNy9m6EepeVGnos=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/icza/bitio v1.0.0 h1:squ/m1SHyFeCA6+6Gyol1AxV9nmPPlJFT8c2vKdj3U8=
github.com/icza/bitio v1.0.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A=
github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6 h1:8UsGZ2rr2ksmEru6lToqnXgA8Mz1DP11X4zSJ159C3k=
github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA=
github.com/jfreymuth/oggvorbis v1.0.1/go.mod h1:NqS+K+UXKje0FUYUPosyQ+XTVvjmVjps1aEZH1sumIk=
github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mewkiz/flac v1.0.7 h1:uIXEjnuXqdRaZttmSFM5v5Ukp4U6orrZsnYGGR3yow8=
github.com/mewkiz/flac v1.0.7/go.mod h1:yU74UH277dBUpqxPouHSQIar3G1X/QIclVbFahSd1pU=
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2 h1:EyTNMdePWaoWsRSGQnXiSoQu0r6RS1eA557AwJhlzHU=
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2/go.mod h1:3E2FUC/qYUfM8+r9zAwpeHJzqRVVMIYnpzD/clwWxyA=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@ -55,51 +124,118 @@ github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8 h1:idBdZTd9UioThJp8KpM/rTSinK/ChZFBE43/WtIy8zg=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067 h1:KYGJGHOQy8oSi1fDlSpcZF0+juKwk/hEMv5SiwHogR0=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6 h1:vyLBGJPIl9ZYbcQFM2USFmJBK6KI+t+z6jL0lbwjrnc=
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e h1:NHvCuwuS43lGnYhten69ZWqi2QOj/CiDNcKbVqwVoew=
golang.org/x/sys v0.0.0-20220712014510-0a85c31ab51e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
@ -108,6 +244,8 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=

View file

@ -8,17 +8,13 @@ import (
// Settings represents the settings panel. // Settings represents the settings panel.
type Settings struct { type Settings struct {
Language string `json:"language"` Language string `json:"language"`
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"` MaxRunTime time.Duration `json:"max_run_time"`
PreAlarmAction string `json:"pre_alarm_action"` MaxVolume uint16 `json:"max_volume"`
MaxRunTime time.Duration `json:"max_run_time"` Federation map[string]FederationServer `json:"federation"`
MaxVolume uint16 `json:"max_volume"`
StartVolume uint16 `json:"start_volume"`
NoRandom bool `json:"no_random"`
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.

View file

@ -22,8 +22,6 @@ type Player struct {
Playlist []string Playlist []string
MaxRunTime time.Duration MaxRunTime time.Duration
MaxVolume uint16 MaxVolume uint16
StartVolume uint16
NoRandom bool
Stopper chan bool Stopper chan bool
currentCmd *exec.Cmd currentCmd *exec.Cmd
currentCmdCh chan bool currentCmdCh chan bool
@ -97,13 +95,11 @@ func NewPlayer(cfg *config.Config, routines []reveil.Identifier) (*Player, error
currentCmdCh: make(chan bool, 1), currentCmdCh: make(chan bool, 1),
MaxRunTime: settings.MaxRunTime * time.Minute, MaxRunTime: settings.MaxRunTime * time.Minute,
MaxVolume: uint16(settings.MaxVolume), MaxVolume: uint16(settings.MaxVolume),
StartVolume: uint16(settings.StartVolume),
NoRandom: settings.NoRandom,
weatherTime: settings.WeatherDelay * time.Minute, weatherTime: settings.WeatherDelay * time.Minute,
weatherAction: wact, weatherAction: wact,
claironTime: settings.GongInterval * time.Minute, claironTime: settings.GongInterval * time.Minute,
claironFile: reveil.CurrentGongPath(cfg), claironFile: reveil.CurrentGongPath(cfg),
reverseOrder: !settings.NoRandom && int(time.Now().Unix()/86400)%2 == 0, reverseOrder: int(time.Now().Unix()/86400)%2 == 0,
} }
// Load routines // Load routines
@ -133,13 +129,11 @@ func NewPlayer(cfg *config.Config, routines []reveil.Identifier) (*Player, error
p.Playlist = append(p.Playlist, track.Path) p.Playlist = append(p.Playlist, track.Path)
} }
if !p.NoRandom { log.Println("Shuffling playlist...")
log.Println("Shuffling playlist...") // Shuffle the playlist
// Shuffle the playlist rand.Shuffle(len(p.Playlist), func(i, j int) {
rand.Shuffle(len(p.Playlist), func(i, j int) { p.Playlist[i], p.Playlist[j] = p.Playlist[j], p.Playlist[i]
p.Playlist[i], p.Playlist[j] = p.Playlist[j], p.Playlist[i] })
})
}
return &p, nil return &p, nil
} }
@ -210,7 +204,7 @@ loop:
} else { } else {
p.dontUpdateVolume = false p.dontUpdateVolume = false
p.volume = uint16(math.Log(1+float64(p.ntick)/8) * 9500) p.volume = uint16(math.Log(1+float64(p.ntick)/8) * 9500)
p.SetVolume(p.StartVolume + p.volume) p.SetVolume(p.volume)
if p.reverseOrder { if p.reverseOrder {
p.playedItem -= 1 p.playedItem -= 1
@ -232,7 +226,7 @@ loop:
p.ntick += 1 p.ntick += 1
if !p.dontUpdateVolume { if !p.dontUpdateVolume {
p.volume = 3500 + uint16(math.Log(1+float64(p.ntick)/8)*9500) p.volume = 3500 + uint16(math.Log(1+float64(p.ntick)/8)*9500)
p.SetVolume(p.StartVolume + p.volume) p.SetVolume(p.volume)
} }
case <-p.Stopper: case <-p.Stopper:
@ -255,12 +249,8 @@ loopcalm:
for i := 0; i < 128 && p.volume >= 768; i += 1 { for i := 0; i < 128 && p.volume >= 768; i += 1 {
timer := time.NewTimer(40 * time.Millisecond) timer := time.NewTimer(40 * time.Millisecond)
if p.volume <= 0 { p.volume -= 768
p.StartVolume -= 768 p.SetVolume(p.volume)
} else {
p.volume -= 768
}
p.SetVolume(p.StartVolume + p.volume)
select { select {
case <-p.Stopper: case <-p.Stopper:

2749
ui/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -14,19 +14,19 @@
"devDependencies": { "devDependencies": {
"@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": "^5.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0",
"@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/eslint-plugin": "^7.0.0",
"@typescript-eslint/parser": "^8.0.0", "@typescript-eslint/parser": "^7.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": "^9.0.0", "eslint": "^8.0.0",
"eslint-config-prettier": "^10.0.0", "eslint-config-prettier": "^9.0.0",
"eslint-plugin-svelte": "^3.0.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": "^5.0.0", "svelte": "^4.0.0",
"svelte-check": "^4.0.0", "svelte-check": "^3.4.3",
"svelte-preprocess": "^6.0.0", "svelte-preprocess": "^6.0.0",
"tslib": "^2.3.1", "tslib": "^2.3.1",
"typescript": "^5.0.0" "typescript": "^5.0.0"
@ -35,8 +35,8 @@
"dependencies": { "dependencies": {
"dayjs": "^1.11.5", "dayjs": "^1.11.5",
"sass": "^1.49.7", "sass": "^1.49.7",
"sass-loader": "^16.0.0", "sass-loader": "^15.0.0",
"@sveltestrap/sveltestrap": "^7.0.0", "@sveltestrap/sveltestrap": "^6.0.0",
"vite": "^6.0.0" "vite": "^5.0.0"
} }
} }

View file

@ -9,9 +9,12 @@
import { actions } from '$lib/stores/actions'; import { actions } from '$lib/stores/actions';
let { flush = false, class: className = '' } = $props(); export let flush = false;
let refreshInProgress = $state(false); export { className as class };
let className = '';
let refreshInProgress = false;
function refresh_actions() { function refresh_actions() {
refreshInProgress = true; refreshInProgress = true;
actions.refresh().then(() => { actions.refresh().then(() => {
@ -26,12 +29,13 @@
</h2> </h2>
<div> <div>
{#if !flush} {#if !flush}
<a <Button
href="routines/actions" href="routines/actions"
class="btn btn-sm btn-outline-info" color="outline-info"
size="sm"
> >
<Icon name="pencil" /> <Icon name="pencil" />
</a> </Button>
{/if} {/if}
<Button <Button
color="outline-dark" color="outline-dark"

View file

@ -10,19 +10,21 @@
import DateRangeFormat from '$lib/components/DateRangeFormat.svelte'; import DateRangeFormat from '$lib/components/DateRangeFormat.svelte';
import { alarmsExceptions } from '$lib/stores/alarmexceptions'; import { alarmsExceptions } from '$lib/stores/alarmexceptions';
let { flush = false } = $props(); export let flush = false;
</script> </script>
<div class="d-flex justify-content-between align-items-center" class:mx-2={flush}> <div class="d-flex justify-content-between align-items-center" class:mx-2={flush}>
<h2> <h2>
Exceptions Exceptions
</h2> </h2>
<a <Button
href="alarms/exceptions/new" href="alarms/exceptions/new"
class="btn btn-sm btn-outline-primary float-end {($page.params.kind === 'single' && $page.url.pathname.endsWith('/new'))?'active':''}" color="outline-primary"
size="sm"
class="float-end {($page.params.kind === 'exceptions' && $page.url.pathname.endsWith('/new'))?'active':''}"
> >
<Icon name="plus-lg" /> <Icon name="plus-lg" />
</a> </Button>
</div> </div>
<div class="text-center"> <div class="text-center">
{#if $alarmsExceptions.list !== null} {#if $alarmsExceptions.list !== null}

View file

@ -10,19 +10,21 @@
import { weekdayStr } from '$lib/alarmrepeated'; import { weekdayStr } from '$lib/alarmrepeated';
import { alarmsRepeated } from '$lib/stores/alarmrepeated'; import { alarmsRepeated } from '$lib/stores/alarmrepeated';
let { flush = false } = $props(); export let flush = false;
</script> </script>
<div class="d-flex justify-content-between align-items-center" class:mx-2={flush}> <div class="d-flex justify-content-between align-items-center" class:mx-2={flush}>
<h2> <h2>
Réveils habituels Réveils habituels
</h2> </h2>
<a <Button
href="alarms/repeated/new" href="alarms/repeated/new"
class="btn btn-sm btn-outline-primary float-end {($page.params.kind === 'single' && $page.url.pathname.endsWith('/new'))?'active':''}" color="outline-primary"
size="sm"
class="float-end {($page.params.kind === 'repeated' && $page.url.pathname.endsWith('/new'))?'active':''}"
> >
<Icon name="plus-lg" /> <Icon name="plus-lg" />
</a> </Button>
</div> </div>
<div class="text-center"> <div class="text-center">
{#if $alarmsRepeated.list !== null} {#if $alarmsRepeated.list !== null}

View file

@ -10,19 +10,21 @@
import DateFormat from '$lib/components/DateFormat.svelte'; import DateFormat from '$lib/components/DateFormat.svelte';
import { alarmsSingle } from '$lib/stores/alarmsingle'; import { alarmsSingle } from '$lib/stores/alarmsingle';
let { flush = false } = $props(); export let flush = false;
</script> </script>
<div class="d-flex justify-content-between align-items-center" class:mx-2={flush}> <div class="d-flex justify-content-between align-items-center" class:mx-2={flush}>
<h2> <h2>
Réveils manuels Réveils manuels
</h2> </h2>
<a <Button
href="alarms/single/new" href="alarms/single/new"
class="btn btn-sm btn-outline-primary float-end {($page.params.kind === 'single' && $page.url.pathname.endsWith('/new'))?'active':''}" color="outline-primary"
size="sm"
class="float-end {($page.params.kind === 'single' && $page.url.pathname.endsWith('/new'))?'active':''}"
> >
<Icon name="plus-lg" /> <Icon name="plus-lg" />
</a> </Button>
</div> </div>
<div class="text-center"> <div class="text-center">
{#if $alarmsSingle.list !== null} {#if $alarmsSingle.list !== null}

View file

@ -15,10 +15,10 @@
import { actions_idx } from '$lib/stores/actions'; import { actions_idx } from '$lib/stores/actions';
let { routine = { export let routine = {
name: "Classique", name: "Classique",
steps: [], steps: [],
} } = $props(); };
</script> </script>
<Card> <Card>

View file

@ -7,12 +7,12 @@
Icon, Icon,
} from '@sveltestrap/sveltestrap'; } from '@sveltestrap/sveltestrap';
let { awakingList = [ export let awakingList = [
{ {
id: 1, id: 1,
date: new Date("2022-10-01T09:15:00.000Z"), date: new Date("2022-10-01T09:15:00.000Z"),
}, },
] } = $props(); ];
</script> </script>
<Card> <Card>

View file

@ -8,13 +8,13 @@
Icon, Icon,
} from '@sveltestrap/sveltestrap'; } from '@sveltestrap/sveltestrap';
let { routinesStats = [ export let routinesStats = [
{ {
id: 1, id: 1,
name: "Classique", name: "Classique",
nb: 10, nb: 10,
}, },
] } = $props(); ];
</script> </script>
<Card> <Card>

View file

@ -1,6 +1,9 @@
<script lang="ts"> <script>
import { createEventDispatcher, onMount, onDestroy } from 'svelte'; import { createEventDispatcher, onMount, onDestroy } from 'svelte';
export let begins = null;
export let ends;
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
let interval; let interval;
@ -21,7 +24,8 @@
} }
}); });
let { begins = $bindable(null), ends, class: className = 'text-muted' } = $props(); export { className as class };
let className = 'text-muted';
</script> </script>
{#if begins && ends} {#if begins && ends}

View file

@ -1,5 +1,7 @@
<script> <script>
let { date, dateStyle, timeStyle } = $props(); export let date;
export let dateStyle;
export let timeStyle;
function formatDate(input, dateStyle, timeStyle) { function formatDate(input, dateStyle, timeStyle) {
if (typeof input === 'string') { if (typeof input === 'string') {

View file

@ -1,10 +1,8 @@
<script> <script>
let { export let startDate;
startDate, export let endDate;
endDate, export let dateStyle;
dateStyle, export let timeStyle;
timeStyle
} = $props();
function formatRange(startDate, endDate, dateStyle, timeStyle) { function formatRange(startDate, endDate, dateStyle, timeStyle) {
if (typeof input === 'string') { if (typeof input === 'string') {

View file

@ -3,17 +3,18 @@
import { import {
Input, Input,
} from '@sveltestrap/sveltestrap'; } from '@sveltestrap/sveltestrap';
let { export let format = 'YYYY-MM-DD HH:mm';
format = 'YYYY-MM-DD HH:mm', export let date = new Date();
date = $bindable(new Date()),
class: className = '',
id = null,
required = false
} = $props();
let internal = $state(); let className = '';
export { className as class };
export let id = null;
export let required = false;
let internal;
const input = (x) => (internal = dayjs(x).format(format)); const input = (x) => (internal = dayjs(x).format(format));
const output = (x) => { const output = (x) => {
@ -23,12 +24,8 @@
} }
}; };
$effect(() => { $: input(date)
input(date) $: output(internal)
});
$effect(() => {
output(internal)
});
</script> </script>
<Input type="datetime-local" class={className} id={id} {required} bind:value={internal} /> <Input type="datetime-local" class={className} id={id} {required} bind:value={internal} />

View file

@ -14,7 +14,8 @@
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
let { id = "", value = $bindable({ }) } = $props(); export let id = "";
export let value = { };
function changeKey(bak, to) { function changeKey(bak, to) {
if (bak === null && to.target.value) { if (bak === null && to.target.value) {
@ -28,7 +29,7 @@
} }
} }
const syncInProgress = $state({ }); const syncInProgress = { };
async function syncMusic(srv) { async function syncMusic(srv) {
syncInProgress[srv] = true; syncInProgress[srv] = true;
@ -63,13 +64,12 @@
bind:value={value[key].url} bind:value={value[key].url}
on:change={() => dispatch("input")} on:change={() => dispatch("input")}
/> />
<a <Button
href={value[key].url} href={value[key].url}
class="btn btn-secondary"
target="_blank" target="_blank"
> >
<Icon name="globe" /> <Icon name="globe" />
</a> </Button>
</InputGroup> </InputGroup>
</Col> </Col>
<Col> <Col>

View file

@ -16,9 +16,13 @@
}); });
} }
let { flush = false, edit = false, class: className = '' } = $props(); export let flush = false;
export let edit = false;
let refreshInProgress = $state(false); export { className as class };
let className = '';
let refreshInProgress = false;
function refresh_gongs() { function refresh_gongs() {
refreshInProgress = true; refreshInProgress = true;
gongs.refresh().then(() => { gongs.refresh().then(() => {
@ -33,24 +37,26 @@
</h2> </h2>
<div> <div>
{#if !edit} {#if !edit}
<a <Button
href="musiks/gongs" href="musiks/gongs"
class="btn btn-sm btn-outline-info" color="outline-info"
size="sm"
> >
<Icon name="pencil" /> <Icon name="pencil" />
</a> </Button>
{/if} {/if}
<a <Button
href="musiks/gongs/new" href="musiks/gongs/new"
class="btn btn-sm btn-outline-primary" color="outline-primary"
size="sm"
> >
<Icon name="plus-lg" /> <Icon name="plus-lg" />
</a> </Button>
<Button <Button
color="outline-dark" color="outline-dark"
size="sm" size="sm"
title="Rafraîchir la liste des gongs" title="Rafraîchir la liste des gongs"
onclick={refresh_gongs} on:click={refresh_gongs}
disabled={refreshInProgress} disabled={refreshInProgress}
> >
{#if !refreshInProgress} {#if !refreshInProgress}
@ -69,7 +75,7 @@
class="list-group-item list-group-item-action" class="list-group-item list-group-item-action"
class:active={(edit && $page.url.pathname.indexOf('/gongs/') !== -1 && $page.params.gid == gong.id) || (!edit && gong.enabled)} class:active={(edit && $page.url.pathname.indexOf('/gongs/') !== -1 && $page.params.gid == gong.id) || (!edit && gong.enabled)}
aria-current="true" aria-current="true"
onclick={() => { on:click={() => {
if (edit) { if (edit) {
goto('musiks/gongs/' + gong.id); goto('musiks/gongs/' + gong.id);
} else { } else {

View file

@ -12,7 +12,15 @@
const version = fetch('api/version', {headers: {'Accept': 'application/json'}}).then((res) => res.json()) const version = fetch('api/version', {headers: {'Accept': 'application/json'}}).then((res) => res.json())
let { class: className = '' } = $props(); export let activemenu = "";
$: {
const path = $page.url.pathname.split("/");
if (path.length > 1) {
activemenu = path[1];
}
}
export { className as class };
let className = '';
</script> </script>
<Navbar container={false} class="{className} px-md-2" color="primary" dark expand="xs" style="overflow-x: auto"> <Navbar container={false} class="{className} px-md-2" color="primary" dark expand="xs" style="overflow-x: auto">
@ -22,7 +30,7 @@
<Nav navbar> <Nav navbar>
<NavItem class="d-block d-md-none"> <NavItem class="d-block d-md-none">
<NavLink <NavLink
active={$page.route.id === '/'} active={activemenu === ''}
class="text-center" class="text-center"
href="." href="."
> >
@ -32,7 +40,7 @@
</NavItem> </NavItem>
<NavItem> <NavItem>
<NavLink <NavLink
active={$page.route.id.startsWith('/alarms')} active={activemenu === 'alarms'}
class="text-center" class="text-center"
href="alarms" href="alarms"
> >
@ -44,7 +52,7 @@
<NavLink <NavLink
href="musiks" href="musiks"
class="text-center" class="text-center"
active={$page.route.id.startsWith('/musiks')} active={activemenu === 'musiks'}
> >
<Icon name="music-note-list" /><br class="d-inline d-md-none"> <Icon name="music-note-list" /><br class="d-inline d-md-none">
Musiques Musiques
@ -54,7 +62,7 @@
<NavLink <NavLink
href="routines" href="routines"
class="text-center" class="text-center"
active={$page.route.id.startsWith('/routines')} active={activemenu === 'routines'}
> >
<Icon name="activity" /><br class="d-inline d-md-none"> <Icon name="activity" /><br class="d-inline d-md-none">
Routines Routines
@ -64,7 +72,7 @@
<NavLink <NavLink
href="history" href="history"
class="text-center" class="text-center"
active={$page.route.id.startsWith('/history')} active={activemenu === 'history'}
> >
<Icon name="clipboard-pulse" /><br class="d-inline d-md-none"> <Icon name="clipboard-pulse" /><br class="d-inline d-md-none">
Historique Historique
@ -74,7 +82,7 @@
<NavLink <NavLink
href="settings" href="settings"
class="text-center" class="text-center"
active={$page.route.id.startsWith('/settings')} active={activemenu === 'settings'}
> >
<Icon name="gear-fill" /><br class="d-inline d-md-none"> <Icon name="gear-fill" /><br class="d-inline d-md-none">
Paramètres Paramètres

View file

@ -10,9 +10,13 @@
import { tracks } from '$lib/stores/tracks'; import { tracks } from '$lib/stores/tracks';
let { flush = false, edit = false, class: className = '' } = $props(); export let flush = false;
export let edit = false;
let refreshInProgress = $state(false); export { className as class };
let className = '';
let refreshInProgress = false;
function refresh_tracks() { function refresh_tracks() {
refreshInProgress = true; refreshInProgress = true;
tracks.refresh().then(() => { tracks.refresh().then(() => {
@ -27,24 +31,26 @@
</h2> </h2>
<div> <div>
{#if !edit} {#if !edit}
<a <Button
href="musiks/tracks" href="musiks/tracks"
class="btn btn-sm btn-outline-info" color="outline-info"
size="sm"
> >
<Icon name="pencil" /> <Icon name="pencil" />
</a> </Button>
{/if} {/if}
<a <Button
href="musiks/tracks/new" href="musiks/tracks/new"
class="btn btn-sm btn-outline-primary" color="outline-primary"
size="sm"
> >
<Icon name="plus-lg" /> <Icon name="plus-lg" />
</a> </Button>
<Button <Button
color="outline-dark" color="outline-dark"
size="sm" size="sm"
title="Rafraîchir la liste des pistes" title="Rafraîchir la liste des pistes"
onclick={refresh_tracks} on:click={refresh_tracks}
disabled={refreshInProgress} disabled={refreshInProgress}
> >
{#if !refreshInProgress} {#if !refreshInProgress}
@ -63,7 +69,7 @@
class="list-group-item list-group-item-action" class="list-group-item list-group-item-action"
class:active={$page.url.pathname.indexOf('/tracks/') !== -1 && $page.params.tid == track.id} class:active={$page.url.pathname.indexOf('/tracks/') !== -1 && $page.params.tid == track.id}
aria-current="true" aria-current="true"
onclick={() => { on:click={() => {
if (edit) { if (edit) {
goto('musiks/tracks/' + track.id); goto('musiks/tracks/' + track.id);
} else { } else {

View file

@ -5,17 +5,13 @@ export class Settings {
} }
} }
update({ language, gong_interval, weather_delay, weather_action, pre_alarm_delay, pre_alarm_action, max_run_time, max_volume, start_volume, no_random, federation }) { update({ language, gong_interval, weather_delay, weather_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.start_volume = start_volume;
this.no_random = no_random;
this.federation = federation; this.federation = federation;
} }

View file

@ -2,18 +2,6 @@ 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});
@ -26,7 +14,6 @@ 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

@ -10,8 +10,6 @@
import Toaster from '$lib/components/Toaster.svelte'; import Toaster from '$lib/components/Toaster.svelte';
import { ToastsStore } from '$lib/stores/toasts'; import { ToastsStore } from '$lib/stores/toasts';
let { children } = $props();
window.onunhandledrejection = (e) => { window.onunhandledrejection = (e) => {
ToastsStore.addErrorToast({ ToastsStore.addErrorToast({
message: e.reason, message: e.reason,
@ -30,7 +28,7 @@
class="d-none d-lg-flex py-2" class="d-none d-lg-flex py-2"
/> />
<div class="flex-fill d-flex flex-column bg-light"> <div class="flex-fill d-flex flex-column bg-light">
{@render children?.()} <slot></slot>
<div class="d-flex d-lg-none mt-3 mb-5"></div> <div class="d-flex d-lg-none mt-3 mb-5"></div>
</div> </div>
<Toaster /> <Toaster />

View file

@ -13,8 +13,8 @@
import { alarmsSingle } from '$lib/stores/alarmsingle'; import { alarmsSingle } from '$lib/stores/alarmsingle';
import { quotes } from '$lib/stores/quotes'; import { quotes } from '$lib/stores/quotes';
let nextAlarmP = $state(getNextAlarm()); let nextAlarmP = getNextAlarm();
let isActiveP = $state(isAlarmActive()); let isActiveP = isAlarmActive();
function reloadNextAlarm() { function reloadNextAlarm() {
nextAlarmP = getNextAlarm(); nextAlarmP = getNextAlarm();
@ -53,7 +53,7 @@
}); });
} }
let extinctionInProgress = $state(false); let extinctionInProgress = false;
</script> </script>
<Container class="flex-fill d-flex flex-column justify-content-center text-center"> <Container class="flex-fill d-flex flex-column justify-content-center text-center">
@ -103,7 +103,7 @@
<button <button
class="btn btn-lg btn-link" class="btn btn-lg btn-link"
title="Supprimer ce prochain réveil" title="Supprimer ce prochain réveil"
onclick={dropNextAlarm} on:click={dropNextAlarm}
> >
<Icon name="x-circle-fill" /> <Icon name="x-circle-fill" />
</button> </button>
@ -123,14 +123,14 @@
</a> </a>
<button <button
class="btn btn-info" class="btn btn-info"
onclick={() => newCyclesAlarm(5)} on:click={() => newCyclesAlarm(5)}
> >
<Icon name="node-plus" /> <Icon name="node-plus" />
5 cycles 5 cycles
</button> </button>
<button <button
class="btn btn-info" class="btn btn-info"
onclick={() => newCyclesAlarm(6)} on:click={() => newCyclesAlarm(6)}
> >
<Icon name="node-plus" /> <Icon name="node-plus" />
6 cycles 6 cycles
@ -138,7 +138,7 @@
<button <button
class="btn btn-outline-warning" class="btn btn-outline-warning"
title="Lancer le réveil" title="Lancer le réveil"
onclick={() => { runAlarm(); setTimeout(reloadIsActiveAlarm, 500); }} on:click={() => { runAlarm(); setTimeout(reloadIsActiveAlarm, 500); }}
> >
<Icon name="play-circle" /> <Icon name="play-circle" />
Lancer <span class="d-none d-lg-inline">le réveil</span> Lancer <span class="d-none d-lg-inline">le réveil</span>
@ -148,14 +148,14 @@
<div class="d-flex gap-3 mt-3 justify-content-center"> <div class="d-flex gap-3 mt-3 justify-content-center">
<button <button
class="btn btn-outline-info" class="btn btn-outline-info"
onclick={alarmNextTrack} on:click={alarmNextTrack}
> >
<Icon name="skip-end-fill" /> <Icon name="skip-end-fill" />
Chanson suivante Chanson suivante
</button> </button>
<button <button
class="btn btn-danger" class="btn btn-danger"
onclick={stopAlarm} on:click={stopAlarm}
> >
{#if extinctionInProgress} {#if extinctionInProgress}
<Spinner size="sm" /> <Spinner size="sm" />

View file

@ -13,8 +13,6 @@
import AlarmRepeatedList from '$lib/components/AlarmRepeatedList.svelte'; import AlarmRepeatedList from '$lib/components/AlarmRepeatedList.svelte';
import AlarmExceptionList from '$lib/components/AlarmExceptionList.svelte'; import AlarmExceptionList from '$lib/components/AlarmExceptionList.svelte';
let { children } = $props();
function slugToComponent(slug) { function slugToComponent(slug) {
switch(slug) { switch(slug) {
case "single": case "single":
@ -39,7 +37,7 @@
<svelte:component this={slugToComponent($page.params["kind"])} flush={true} /> <svelte:component this={slugToComponent($page.params["kind"])} flush={true} />
</Col> </Col>
<Col md={9} class="d-flex py-2"> <Col md={9} class="d-flex py-2">
{@render children?.()} <slot></slot>
</Col> </Col>
</Row> </Row>
</Container> </Container>

View file

@ -1,6 +1,4 @@
<script> <script>
import { run } from 'svelte/legacy';
import { import {
Button, Button,
Col, Col,
@ -36,20 +34,27 @@
} }
} }
function callRightFunction(kind) { let objP;
switch(kind) { let obj;
$: {
switch ($page.params["kind"]) {
case "single": case "single":
return getAlarmSingle; objP = getAlarmSingle($page.params["aid"]);
break;
case "repeated": case "repeated":
return getAlarmRepeated; objP = getAlarmRepeated($page.params["aid"]);
break;
case "exceptions": case "exceptions":
return getAlarmException; objP = getAlarmException($page.params["aid"]);
break;
} }
objP.then((o) => obj = o);
} }
let edit = $state(false); let edit = false;
function deleteThis(obj) { function deleteThis() {
obj.delete().then(() => { obj.delete().then(() => {
switch($page.params["kind"]) { switch($page.params["kind"]) {
case "single": case "single":
@ -69,12 +74,12 @@
</script> </script>
<Container fluid class="flex-fill"> <Container fluid class="flex-fill">
{#await callRightFunction($page.params["kind"])($page.params["aid"])} {#if $page.params["kind"] == "single"}
<div class="d-flex justify-content-center align-items-center gap-2"> {#await objP}
<Spinner color="primary" /> Chargement en cours&hellip; <div class="d-flex justify-content-center align-items-center gap-2">
</div> <Spinner color="primary" /> Chargement en cours&hellip;
{:then alarm} </div>
{#if $page.params["kind"] == "single"} {:then alarm}
<h2 class="mb-0"> <h2 class="mb-0">
{slugToTitle($page.params["kind"])} du <DateFormat date={alarm.time} dateStyle="long" /> {slugToTitle($page.params["kind"])} du <DateFormat date={alarm.time} dateStyle="long" />
</h2> </h2>
@ -92,10 +97,16 @@
</ListGroupItem> </ListGroupItem>
<ListGroupItem class="d-flex"> <ListGroupItem class="d-flex">
<strong>Fédération activée&nbsp;?</strong> <strong>Fédération activée&nbsp;?</strong>
<Input type="switch" class="ms-2" on:change={() => {alarm.enable_federation = !alarm.enable_federation; alarm.save();}} checked={alarm.enable_federation} /> {alarm.enable_federation?"oui":"non"} <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> </ListGroupItem>
</ListGroup> </ListGroup>
{:else if $page.params["kind"] == "repeated"} {/await}
{:else if $page.params["kind"] == "repeated"}
{#await objP}
<div class="d-flex justify-content-center align-items-center gap-2">
<Spinner color="primary" /> Chargement en cours&hellip;
</div>
{:then alarm}
<h2 class="mb-0"> <h2 class="mb-0">
{slugToTitle($page.params["kind"])} des {weekdayStr(alarm.weekday)}s à {alarm.time} {slugToTitle($page.params["kind"])} des {weekdayStr(alarm.weekday)}s à {alarm.time}
</h2> </h2>
@ -113,19 +124,19 @@
</ListGroupItem> </ListGroupItem>
<ListGroupItem class="d-flex"> <ListGroupItem class="d-flex">
<strong>Alarme active&nbsp;?</strong> <strong>Alarme active&nbsp;?</strong>
<Input type="switch" class="ms-2" on:change={() => {alarm.disabled = !alarm.disabled; alarm.save().then(() => {alarm.next_time = null; alarmsRepeated.refresh()});}} checked={!alarm.disabled} /> {!alarm.disabled?"oui":"non"} <Input type="switch" class="ms-2" on:change={() => {obj.disabled = !obj.disabled; obj.save().then(() => {obj.next_time = null; alarmsRepeated.refresh()});}} checked={!obj.disabled} /> {!obj.disabled?"oui":"non"}
</ListGroupItem> </ListGroupItem>
<ListGroupItem class="d-flex"> <ListGroupItem class="d-flex">
<strong>Ignorer les exceptions&nbsp;?</strong> <strong>Ignorer les exceptions&nbsp;?</strong>
<Input type="switch" class="ms-2" on:change={() => {alarm.ignore_exceptions = !alarm.ignore_exceptions; alarm.save();}} checked={alarm.ignore_exceptions} /> {alarm.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"> <ListGroupItem class="d-flex">
<strong>Fédération activée&nbsp;?</strong> <strong>Fédération activée&nbsp;?</strong>
<Input type="switch" class="ms-2" on:change={() => {alarm.enable_federation = !alarm.enable_federation; alarm.save();}} checked={alarm.enable_federation} /> {alarm.enable_federation?"oui":"non"} <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> </ListGroupItem>
{#if alarm.next_time} {#if alarm.next_time}
<ListGroupItem> <ListGroupItem>
<strong>Prochaine occurrence</strong> <DateFormat date={new Date(alarm.next_time)} dateStyle="long" /> <strong>Prochaine occurrence</strong> <DateFormat date={new Date(obj.next_time)} dateStyle="long" />
</ListGroupItem> </ListGroupItem>
{/if} {/if}
</ListGroup> </ListGroup>
@ -139,7 +150,13 @@
{/each} {/each}
</ListGroup> </ListGroup>
{/if} {/if}
{:else if $page.params["kind"] == "exceptions"} {/await}
{:else if $page.params["kind"] == "exceptions"}
{#await objP}
<div class="d-flex justify-content-center align-items-center gap-2">
<Spinner color="primary" /> Chargement en cours&hellip;
</div>
{:then exception}
<h2 class="mb-0"> <h2 class="mb-0">
{slugToTitle($page.params["kind"])} du <DateRangeFormat startDate={exception._start()} endDate={exception._end()} dateStyle="long" /> {slugToTitle($page.params["kind"])} du <DateRangeFormat startDate={exception._start()} endDate={exception._end()} dateStyle="long" />
</h2> </h2>
@ -149,8 +166,11 @@
</p> </p>
{/if} {/if}
Entre le <DateRangeFormat startDate={exception._start()} endDate={exception._end()} dateStyle="long" /> Entre le <DateRangeFormat startDate={exception._start()} endDate={exception._end()} dateStyle="long" />
{/if} {/await}
{#if !edit} {/if}
{#if !edit}
{#await objP then alarm}
<ListGroup class="my-2 text-center"> <ListGroup class="my-2 text-center">
<ListGroupItem <ListGroupItem
action action
@ -165,12 +185,12 @@
action action
tag="button" tag="button"
class="text-danger fw-bold" class="text-danger fw-bold"
on:click={() => deleteThis(alarm)} on:click={deleteThis}
> >
<Icon name="trash" /> <Icon name="trash" />
Supprimer ce {slugToTitle($page.params["kind"]).toLowerCase()} Supprimer ce {slugToTitle($page.params["kind"]).toLowerCase()}
</ListGroupItem> </ListGroupItem>
</ListGroup> </ListGroup>
{/if} {/await}
{/await} {/if}
</Container> </Container>

View file

@ -35,7 +35,7 @@
} }
} }
let obj = $state(); let obj;
const vtime = new Date(Date.now() + 7.6*3600000); const vtime = new Date(Date.now() + 7.6*3600000);
@ -56,8 +56,7 @@
break; break;
} }
function submit(e) { function submit() {
e.preventDefault();
obj.save().then((res) => { obj.save().then((res) => {
switch($page.params["kind"]) { switch($page.params["kind"]) {
case "single": case "single":
@ -77,7 +76,7 @@
</script> </script>
<Container fluid class="flex-fill"> <Container fluid class="flex-fill">
<form onsubmit={submit}> <form on:submit|preventDefault={submit}>
<Button type="submit" color="link" class="d-block d-md-none float-end"> <Button type="submit" color="link" class="d-block d-md-none float-end">
Ajouter Ajouter
</Button> </Button>

View file

@ -8,8 +8,6 @@
} from '@sveltestrap/sveltestrap'; } from '@sveltestrap/sveltestrap';
import GongsList from '$lib/components/GongsList.svelte'; import GongsList from '$lib/components/GongsList.svelte';
let { children } = $props();
</script> </script>
<div class="d-flex flex-fill flex-column"> <div class="d-flex flex-fill flex-column">
@ -24,7 +22,7 @@
<GongsList edit flush /> <GongsList edit flush />
</Col> </Col>
<Col md={9} class="d-flex py-2"> <Col md={9} class="d-flex py-2">
{@render children?.()} <slot></slot>
</Col> </Col>
</Row> </Row>
</Container> </Container>

View file

@ -22,7 +22,7 @@
}) })
} }
let confirmDeletion = $state(false); let confirmDeletion = false;
</script> </script>
{#await getGong($page.params.gid)} {#await getGong($page.params.gid)}

View file

@ -15,9 +15,7 @@
import { gongs } from '$lib/stores/gongs'; import { gongs } from '$lib/stores/gongs';
import { uploadGong } from '$lib/gong'; import { uploadGong } from '$lib/gong';
function submitGong(e) { function submitGong() {
e.preventDefault();
if (files.length == 0) { if (files.length == 0) {
alert("Vous n'avez sélectionné aucun fichier !") alert("Vous n'avez sélectionné aucun fichier !")
return false; return false;
@ -29,7 +27,7 @@
}) })
} }
let { files = $bindable([]) } = $props(); export let files = [];
</script> </script>
<Container> <Container>
@ -37,7 +35,7 @@
Nouveau gong Nouveau gong
</h2> </h2>
<form onsubmit={submitGong}> <form on:submit|preventDefault={submitGong}>
<Input type="file" bind:files /> <Input type="file" bind:files />
<Button type="submit" color="primary" class="mt-2" disabled={files.length == 0}> <Button type="submit" color="primary" class="mt-2" disabled={files.length == 0}>

View file

@ -8,8 +8,6 @@
} from '@sveltestrap/sveltestrap'; } from '@sveltestrap/sveltestrap';
import TrackList from '$lib/components/TrackList.svelte'; import TrackList from '$lib/components/TrackList.svelte';
let { children } = $props();
</script> </script>
<div class="d-flex flex-fill flex-column"> <div class="d-flex flex-fill flex-column">
@ -24,7 +22,7 @@
<TrackList edit flush /> <TrackList edit flush />
</Col> </Col>
<Col md={9} class="d-flex py-2"> <Col md={9} class="d-flex py-2">
{@render children?.()} <slot></slot>
</Col> </Col>
</Row> </Row>
</Container> </Container>

View file

@ -28,7 +28,7 @@
}) })
} }
let confirmDeletion = $state(false); let confirmDeletion = false;
</script> </script>
{#await getTrack($page.params.tid)} {#await getTrack($page.params.tid)}

View file

@ -15,9 +15,7 @@
import { tracks } from '$lib/stores/tracks'; import { tracks } from '$lib/stores/tracks';
import { uploadTrack } from '$lib/track'; import { uploadTrack } from '$lib/track';
function submitTrack(e) { function submitTrack() {
e.preventDefault();
if (files.length == 0) { if (files.length == 0) {
alert("Vous n'avez sélectionné aucun fichier !") alert("Vous n'avez sélectionné aucun fichier !")
return false; return false;
@ -29,7 +27,7 @@
}) })
} }
let { files = $bindable([]) } = $props(); export let files = [];
</script> </script>
<Container> <Container>
@ -37,7 +35,7 @@
Nouvelle musique Nouvelle musique
</h2> </h2>
<form onsubmit={submitTrack}> <form on:submit|preventDefault={submitTrack}>
<Input type="file" bind:files /> <Input type="file" bind:files />
<Button type="submit" color="primary" class="mt-2" disabled={files.length == 0}> <Button type="submit" color="primary" class="mt-2" disabled={files.length == 0}>

View file

@ -8,8 +8,6 @@
} from '@sveltestrap/sveltestrap'; } from '@sveltestrap/sveltestrap';
import ActionList from '$lib/components/ActionList.svelte'; import ActionList from '$lib/components/ActionList.svelte';
let { children } = $props();
</script> </script>
<div class="d-flex flex-fill flex-column"> <div class="d-flex flex-fill flex-column">
@ -24,7 +22,7 @@
<ActionList edit flush /> <ActionList edit flush />
</Col> </Col>
<Col md={9} class="d-flex py-2"> <Col md={9} class="d-flex py-2">
{@render children?.()} <slot></slot>
</Col> </Col>
</Row> </Row>
</Container> </Container>

View file

@ -17,7 +17,13 @@
import { getSettings } from '$lib/settings'; import { getSettings } from '$lib/settings';
import FederationSettings from '$lib/components/FederationSettings.svelte'; import FederationSettings from '$lib/components/FederationSettings.svelte';
async function submitSettings(settings) { let settingsP = getSettings();
$: settingsP.then((s) => settings = s);
let settings;
async function submitSettings() {
await tick(); await tick();
settings.save(); settings.save();
} }
@ -27,12 +33,12 @@
<h2> <h2>
Paramètres Paramètres
</h2> </h2>
{#await getSettings()} <Form on:submit={submitSettings}>
<div class="d-flex justify-content-center align-items-center gap-2"> {#await settingsP}
<Spinner color="primary" /> Chargement en cours&hellip; <div class="d-flex justify-content-center align-items-center gap-2">
</div> <Spinner color="primary" /> Chargement en cours&hellip;
{:then settings} </div>
<Form on:submit={() => submitSettings(settings)}> {:then}
<FormGroup> <FormGroup>
<Label for="gongIntervals">Intervalle entre les gongs</Label> <Label for="gongIntervals">Intervalle entre les gongs</Label>
<InputGroup> <InputGroup>
@ -41,7 +47,7 @@
id="gongIntervals" id="gongIntervals"
placeholder="20" placeholder="20"
bind:value={settings.gong_interval} bind:value={settings.gong_interval}
on:input={() => submitSettings(settings)} on:input={submitSettings}
/> />
<InputGroupText>min</InputGroupText> <InputGroupText>min</InputGroupText>
</InputGroup> </InputGroup>
@ -55,7 +61,7 @@
id="weatherDelay" id="weatherDelay"
placeholder="5" placeholder="5"
bind:value={settings.weather_delay} bind:value={settings.weather_delay}
on:input={() => submitSettings(settings)} on:input={submitSettings}
/> />
<InputGroupText>min</InputGroupText> <InputGroupText>min</InputGroupText>
</InputGroup> </InputGroup>
@ -68,7 +74,7 @@
type="select" type="select"
id="weatherRituel" id="weatherRituel"
bind:value={settings.weather_action} bind:value={settings.weather_action}
on:input={() => submitSettings(settings)} on:input={submitSettings}
> >
{#each $actions.list as action (action.id)} {#each $actions.list as action (action.id)}
<option value="{action.path}">{action.name}</option> <option value="{action.path}">{action.name}</option>
@ -83,47 +89,13 @@
{/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(settings)}
/>
<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(settings)}
>
{#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
type="select" type="select"
id="greetingLanguage" id="greetingLanguage"
bind:value={settings.language} bind:value={settings.language}
on:input={() => submitSettings(settings)} on:input={submitSettings}
> >
<option value="fr_FR">Français</option> <option value="fr_FR">Français</option>
<option value="en_US">Anglais</option> <option value="en_US">Anglais</option>
@ -140,7 +112,7 @@
id="maxRunTime" id="maxRunTime"
placeholder="60" placeholder="60"
bind:value={settings.max_run_time} bind:value={settings.max_run_time}
on:input={() => submitSettings(settings)} on:input={submitSettings}
/> />
<InputGroupText>min</InputGroupText> <InputGroupText>min</InputGroupText>
</InputGroup> </InputGroup>
@ -155,42 +127,19 @@
min="0" min="0"
max="65535" max="65535"
bind:value={settings.max_volume} bind:value={settings.max_volume}
on:input={() => submitSettings(settings)} on:input={submitSettings}
/> />
</InputGroup> </InputGroup>
</FormGroup> </FormGroup>
<FormGroup>
<Label for="startVolume">Volume de départ</Label>
<InputGroup>
<Input
type="range"
id="startVolume"
min="0"
max="65535"
bind:value={settings.start_volume}
on:input={() => submitSettings(settings)}
/>
</InputGroup>
</FormGroup>
<FormGroup>
<Input
type="switch"
label="Ne pas mélanger la liste de lecture"
bind:checked={settings.no_random}
on:input={() => submitSettings(settings)}
/>
</FormGroup>
<FormGroup> <FormGroup>
<Label for="federation">Federation</Label> <Label for="federation">Federation</Label>
<FederationSettings <FederationSettings
id="federation" id="federation"
bind:value={settings.federation} bind:value={settings.federation}
on:input={() => submitSettings(settings)} on:input={submitSettings}
/> />
</FormGroup> </FormGroup>
</Form> {/await}
{/await} </Form>
</Container> </Container>