feat(config): add audiobookshelf section
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLoadAudiobookshelfSection(t *testing.T) {
|
||||
t.Setenv("HOME", t.TempDir())
|
||||
|
||||
path := filepath.Join(os.Getenv("HOME"), ".config", "cliamp", "config.toml")
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||||
t.Fatalf("MkdirAll: %v", err)
|
||||
}
|
||||
|
||||
data := []byte(`
|
||||
[audiobookshelf]
|
||||
url = "https://abs.example.com"
|
||||
token = "abc123"
|
||||
user = "listener"
|
||||
password = "1qazxsw2"
|
||||
libraries = ["Audiobooks", "Podcasts"]
|
||||
`)
|
||||
if err := os.WriteFile(path, data, 0o644); err != nil {
|
||||
t.Fatalf("WriteFile: %v", err)
|
||||
}
|
||||
|
||||
cfg, err := Load()
|
||||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
|
||||
abs := cfg.Audiobookshelf
|
||||
if abs.URL != "https://abs.example.com" {
|
||||
t.Fatalf("URL = %q, want https://abs.example.com", abs.URL)
|
||||
}
|
||||
if abs.Token != "abc123" {
|
||||
t.Fatalf("Token = %q, want abc123", abs.Token)
|
||||
}
|
||||
if abs.User != "listener" {
|
||||
t.Fatalf("User = %q, want listener", abs.User)
|
||||
}
|
||||
if abs.Password != "1qazxsw2" {
|
||||
t.Fatalf("Password = %q, want 1qazxsw2", abs.Password)
|
||||
}
|
||||
if len(abs.Libraries) != 2 || abs.Libraries[0] != "Audiobooks" || abs.Libraries[1] != "Podcasts" {
|
||||
t.Fatalf("Libraries = %v, want [Audiobooks Podcasts]", abs.Libraries)
|
||||
}
|
||||
if !abs.IsSet() {
|
||||
t.Fatal("IsSet() = false, want true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAudiobookshelfIsSet(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
cfg AudiobookshelfConfig
|
||||
want bool
|
||||
}{
|
||||
{name: "empty", cfg: AudiobookshelfConfig{}, want: false},
|
||||
{name: "url only", cfg: AudiobookshelfConfig{URL: "https://abs"}, want: false},
|
||||
{name: "token only", cfg: AudiobookshelfConfig{Token: "t"}, want: false},
|
||||
{name: "url and token", cfg: AudiobookshelfConfig{URL: "https://abs", Token: "t"}, want: true},
|
||||
{name: "url and user only", cfg: AudiobookshelfConfig{URL: "https://abs", User: "u"}, want: false},
|
||||
{name: "url and credentials", cfg: AudiobookshelfConfig{URL: "https://abs", User: "u", Password: "p"}, want: true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.cfg.IsSet(); got != tt.want {
|
||||
t.Fatalf("IsSet() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+30
-1
@@ -234,6 +234,21 @@ func (e EmbyConfig) IsSet() bool {
|
||||
return e.URL != "" && (e.Token != "" || (e.User != "" && e.Password != ""))
|
||||
}
|
||||
|
||||
// AudiobookshelfConfig holds credentials for an Audiobookshelf server.
|
||||
// URL is required. Authenticate either with Token, or with User+Password.
|
||||
type AudiobookshelfConfig struct {
|
||||
URL string // e.g. "https://abs.example.com"
|
||||
Token string // API key or login token
|
||||
User string // optional username for password-based login
|
||||
Password string // optional password for password-based login
|
||||
Libraries []string // optional: restrict to these library names
|
||||
}
|
||||
|
||||
// IsSet reports whether the Audiobookshelf provider is configured.
|
||||
func (a AudiobookshelfConfig) IsSet() bool {
|
||||
return a.URL != "" && (a.Token != "" || (a.User != "" && a.Password != ""))
|
||||
}
|
||||
|
||||
// Config holds user preferences loaded from the config file.
|
||||
type Config struct {
|
||||
Volume float64 // dB, clamped at runtime to [VolumeMin, +6]
|
||||
@@ -247,7 +262,7 @@ type Config struct {
|
||||
Speed float64 // playback speed ratio: 0.25–2.0 (default 1.0)
|
||||
AutoPlay bool // start playback automatically on launch (radio streams, CLI tracks)
|
||||
SeekStepLarge int // seconds for Shift+Left/Right seek jumps
|
||||
Provider string // default provider: "radio", "navidrome", "spotify", "qobuz", "plex", "jellyfin", "emby", "soundcloud", "netease", "ytmusic" (default "radio")
|
||||
Provider string // default provider: "radio", "navidrome", "spotify", "qobuz", "plex", "jellyfin", "emby", "audiobookshelf", "soundcloud", "netease", "ytmusic" (default "radio")
|
||||
Theme string // theme name, or "" for ANSI default
|
||||
Visualizer string // visualizer mode name, or "" for default (Bars)
|
||||
SampleRate int // output sample rate: 22050, 44100, 48000, 96000, 192000
|
||||
@@ -267,6 +282,7 @@ type Config struct {
|
||||
Plex PlexConfig // optional Plex Media Server credentials
|
||||
Jellyfin JellyfinConfig // optional Jellyfin server credentials
|
||||
Emby EmbyConfig // optional Emby server credentials
|
||||
Audiobookshelf AudiobookshelfConfig // optional Audiobookshelf server credentials
|
||||
SoundCloud SoundCloudConfig // SoundCloud provider (opt-in via enabled = true)
|
||||
NetEase NetEaseConfig // NetEase Cloud Music provider (opt-in via enabled = true)
|
||||
Plugins map[string]map[string]string // per-plugin config from [plugins.*] sections
|
||||
@@ -464,6 +480,19 @@ func Load() (Config, error) {
|
||||
case "user_id":
|
||||
cfg.Emby.UserID = parseString(val)
|
||||
}
|
||||
case "audiobookshelf":
|
||||
switch key {
|
||||
case "url":
|
||||
cfg.Audiobookshelf.URL = parseString(val)
|
||||
case "token":
|
||||
cfg.Audiobookshelf.Token = parseString(val)
|
||||
case "user":
|
||||
cfg.Audiobookshelf.User = parseString(val)
|
||||
case "password":
|
||||
cfg.Audiobookshelf.Password = parseString(val)
|
||||
case "libraries":
|
||||
cfg.Audiobookshelf.Libraries = parseStringSlice(val)
|
||||
}
|
||||
default:
|
||||
// Handle [plugins] and [plugins.*] sections.
|
||||
if section == "plugins" || strings.HasPrefix(section, "plugins.") {
|
||||
|
||||
Reference in New Issue
Block a user