Introduce settings.json to store custom sources

This commit is contained in:
nemunaire 2024-10-01 19:10:45 +02:00
parent 85ecd89104
commit ded6ef6095
6 changed files with 143 additions and 23 deletions

42
app.go
View File

@ -2,6 +2,7 @@ package main
import (
"context"
"fmt"
"log"
"net/http"
"time"
@ -10,6 +11,7 @@ import (
"git.nemunai.re/nemunaire/hathoris/api"
"git.nemunai.re/nemunaire/hathoris/config"
"git.nemunai.re/nemunaire/hathoris/settings"
"git.nemunai.re/nemunaire/hathoris/sources"
"git.nemunai.re/nemunaire/hathoris/ui"
)
@ -17,6 +19,7 @@ import (
type App struct {
cfg *config.Config
router *gin.Engine
settings *settings.Settings
srv *http.Server
}
@ -35,6 +38,13 @@ func NewApp(cfg *config.Config) *App {
app := &App{
cfg: cfg,
router: router,
settings: loadUserSettings(cfg),
}
// Load user settings
err := app.loadCustomSources()
if err != nil {
log.Fatal(err.Error())
}
// Register routes
@ -48,6 +58,33 @@ func NewApp(cfg *config.Config) *App {
return app
}
func loadUserSettings(cfg *config.Config) (s *settings.Settings) {
var err error
s, err = settings.Load(cfg)
if err != nil {
log.Fatal("Unable to load settings: ", err.Error())
}
return
}
func (app *App) loadCustomSources() error {
for id, csrc := range app.settings.CustomSources {
if newss, ok := sources.LoadableSources[csrc.Source]; !ok {
return fmt.Errorf("Unable to load source #%d: %q: no such source registered", id, csrc.Source)
} else {
src, err := newss(csrc.KV)
if err != nil {
return fmt.Errorf("Unable to load source #%d (%s): %w", id, csrc.Source, err)
}
sources.SoundSources[fmt.Sprintf("%s-%d", csrc.Source, id)] = src
}
}
return nil
}
func (app *App) Start() {
app.srv = &http.Server{
Addr: app.cfg.Bind,
@ -82,6 +119,11 @@ func (app *App) Stop() {
time.Sleep(2000 * time.Millisecond)
}
err := app.settings.Save(app.cfg.SettingsPath)
if err != nil {
log.Println("Unable to save settings: ", err.Error())
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := app.srv.Shutdown(ctx); err != nil {

View File

@ -9,6 +9,7 @@ func (c *Config) declareFlags() {
flag.StringVar(&c.BaseURL, "baseurl", c.BaseURL, "URL prepended to each URL")
flag.StringVar(&c.Bind, "bind", c.Bind, "Bind port/socket")
flag.StringVar(&c.DevProxy, "dev", c.DevProxy, "Use ui directory instead of embedded assets")
flag.StringVar(&c.SettingsPath, "settings-file", c.SettingsPath, "Path to settings.json file")
// Others flags are declared in some other files when they need specials configurations
}
@ -17,6 +18,7 @@ func Consolidated() (cfg *Config, err error) {
// Define defaults options
cfg = &Config{
Bind: "127.0.0.1:8080",
SettingsPath: "settings.json",
}
cfg.declareFlags()

View File

@ -9,6 +9,7 @@ type Config struct {
DevProxy string
Bind string
BaseURL string
SettingsPath string
}
// parseLine treats a config line and place the read value in the variable

66
settings/settings.go Normal file
View File

@ -0,0 +1,66 @@
package settings
import (
"encoding/json"
"fmt"
"os"
"git.nemunai.re/nemunaire/hathoris/config"
)
type CustomSource struct {
Source string `json:"src"`
KV map[string]string `json:"kv"`
}
type Settings struct {
CustomSources []CustomSource `json:"custom_sources"`
}
func Load(cfg *config.Config) (*Settings, error) {
if cfg.SettingsPath == "" {
return &Settings{}, nil
}
if st, err := os.Stat(cfg.SettingsPath); os.IsNotExist(err) || (err == nil && st.Size() == 0) {
fd, err := os.Create(cfg.SettingsPath)
if err != nil {
return nil, fmt.Errorf("unable to create settings file: %w", err)
}
_, err = fd.Write([]byte("{}"))
fd.Close()
if err != nil {
return nil, fmt.Errorf("unable to write to settings file: %w", err)
}
}
fd, err := os.Open(cfg.SettingsPath)
if err != nil {
return nil, fmt.Errorf("unable to open settings: %w", err)
}
defer fd.Close()
var settings Settings
err = json.NewDecoder(fd).Decode(&settings)
if err != nil {
return nil, fmt.Errorf("unable to read settings: %w", err)
}
return &settings, nil
}
func (settings *Settings) Save(path string) error {
fd, err := os.Create(path)
if err != nil {
return fmt.Errorf("unable to create settings file: %w", err)
}
defer fd.Close()
err = json.NewEncoder(fd).Encode(settings)
if err != nil {
return fmt.Errorf("unable to read settings: %w", err)
}
return nil
}

View File

@ -2,7 +2,10 @@ package sources
import ()
var SoundSources = map[string]SoundSource{}
var (
LoadableSources = map[string]LoadaleSource{}
SoundSources = map[string]SoundSource{}
)
type SoundSource interface {
GetName() string
@ -15,3 +18,5 @@ type SoundSource interface {
type PlayingSource interface {
CurrentlyPlaying() string
}
type LoadaleSource func(map[string]string) (SoundSource, error)

View File

@ -6,6 +6,7 @@ import (
"os"
"os/exec"
"path"
"strings"
"time"
"github.com/DexterLB/mpvipc"
@ -22,22 +23,25 @@ type MPVSource struct {
}
func init() {
sources.SoundSources["mpv-nig"] = &MPVSource{
Name: "Radio NIG",
File: "http://stream.syntheticfm.com:8030/stream",
sources.LoadableSources["mpv"] = NewMPVSource
}
func NewMPVSource(kv map[string]string) (sources.SoundSource, error) {
var s MPVSource
if name, ok := kv["name"]; ok {
s.Name = name
}
sources.SoundSources["mpv-synthfm"] = &MPVSource{
Name: "Radio Synthetic FM",
File: "http://stream.syntheticfm.com:8040/stream",
if opts, ok := kv["opts"]; ok {
s.Options = strings.Split(opts, " ")
}
sources.SoundSources["mpv-nrw"] = &MPVSource{
Name: "NewRetroWave",
File: "https://youtube.com/channel/UCD-4g5w1h8xQpLaNS_ghU4g/videos",
}
sources.SoundSources["mpv-abgt"] = &MPVSource{
Name: "ABGT",
File: "https://youtube.com/playlist?list=PL6RLee9oArCArCAjnOtZ17dlVZQxaHG8G",
if file, ok := kv["file"]; ok {
s.File = file
}
return &s, nil
}
func (s *MPVSource) GetName() string {