Introduce settings.json to store custom sources
This commit is contained in:
parent
85ecd89104
commit
ded6ef6095
52
app.go
52
app.go
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
@ -10,14 +11,16 @@ 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"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
cfg *config.Config
|
||||
router *gin.Engine
|
||||
srv *http.Server
|
||||
cfg *config.Config
|
||||
router *gin.Engine
|
||||
settings *settings.Settings
|
||||
srv *http.Server
|
||||
}
|
||||
|
||||
func NewApp(cfg *config.Config) *App {
|
||||
@ -33,8 +36,15 @@ func NewApp(cfg *config.Config) *App {
|
||||
|
||||
// Prepare struct
|
||||
app := &App{
|
||||
cfg: cfg,
|
||||
router: router,
|
||||
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 {
|
||||
|
@ -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
|
||||
}
|
||||
@ -16,7 +17,8 @@ func (c *Config) declareFlags() {
|
||||
func Consolidated() (cfg *Config, err error) {
|
||||
// Define defaults options
|
||||
cfg = &Config{
|
||||
Bind: "127.0.0.1:8080",
|
||||
Bind: "127.0.0.1:8080",
|
||||
SettingsPath: "settings.json",
|
||||
}
|
||||
|
||||
cfg.declareFlags()
|
||||
|
@ -6,9 +6,10 @@ import (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
DevProxy string
|
||||
Bind string
|
||||
BaseURL string
|
||||
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
66
settings/settings.go
Normal 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
|
||||
}
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user