Dynamic per-backend configuration options

This commit is contained in:
Philipp Wolfer 2023-12-05 23:25:15 +01:00
parent ae5f1c5f26
commit c9fa21be73
No known key found for this signature in database
GPG key ID: 8FDF744D4919943B
14 changed files with 262 additions and 17 deletions

View file

@ -63,7 +63,7 @@ func (l BackendList) Swap(i, j int) {
type Capability = string
func ResolveBackend[T interface{}](config *viper.Viper) (T, error) {
backendName, backend, err := resolveBackend(config)
backendName, backend, err := backendWithConfig(config)
var result T
if err != nil {
return result, err
@ -78,6 +78,14 @@ func ResolveBackend[T interface{}](config *viper.Viper) (T, error) {
return result, err
}
func BackendByName(backendName string) (models.Backend, error) {
backendType := knownBackends[backendName]
if backendType == nil {
return nil, fmt.Errorf("unknown backend %s", backendName)
}
return backendType(), nil
}
func GetBackends() BackendList {
backends := make(BackendList, 0)
for name, backendFunc := range knownBackends {
@ -107,13 +115,13 @@ var knownBackends = map[string]func() models.Backend{
"subsonic": func() models.Backend { return &subsonic.SubsonicApiBackend{} },
}
func resolveBackend(config *viper.Viper) (string, models.Backend, error) {
func backendWithConfig(config *viper.Viper) (string, models.Backend, error) {
backendName := config.GetString("backend")
backendType := knownBackends[backendName]
if backendType == nil {
return backendName, nil, fmt.Errorf("unknown backend %s", backendName)
backend, err := BackendByName(backendName)
if err != nil {
return backendName, nil, err
}
return backendName, backendType().FromConfig(config), nil
return backendName, backend.FromConfig(config), nil
}
func ImplementsInterface[T interface{}](backend *models.Backend) (bool, string) {

View file

@ -36,6 +36,18 @@ type DeezerApiBackend struct {
func (b *DeezerApiBackend) Name() string { return "deezer" }
func (b *DeezerApiBackend) Options() *[]models.BackendOption {
return &[]models.BackendOption{{
Name: "client-id",
Label: "Client ID",
Type: models.String,
}, {
Name: "client-secret",
Label: "Client secret",
Type: models.Secret,
}}
}
func (b *DeezerApiBackend) FromConfig(config *viper.Viper) models.Backend {
b.clientId = config.GetString("client-id")
b.clientSecret = config.GetString("client-secret")

View file

@ -25,6 +25,8 @@ type DumpBackend struct{}
func (b *DumpBackend) Name() string { return "dump" }
func (b *DumpBackend) Options() *[]models.BackendOption { return nil }
func (b *DumpBackend) FromConfig(config *viper.Viper) models.Backend {
return b
}

View file

@ -33,6 +33,22 @@ type FunkwhaleApiBackend struct {
func (b *FunkwhaleApiBackend) Name() string { return "funkwhale" }
func (b *FunkwhaleApiBackend) Options() *[]models.BackendOption {
return &[]models.BackendOption{{
Name: "server-url",
Label: "Server URL",
Type: models.String,
}, {
Name: "username",
Label: "User name",
Type: models.String,
}, {
Name: "token",
Label: "Access token",
Type: models.Secret,
}}
}
func (b *FunkwhaleApiBackend) FromConfig(config *viper.Viper) models.Backend {
b.client = NewClient(
config.GetString("server-url"),

View file

@ -36,6 +36,26 @@ type JSPFBackend struct {
func (b *JSPFBackend) Name() string { return "jspf" }
func (b *JSPFBackend) Options() *[]models.BackendOption {
return &[]models.BackendOption{{
Name: "file-path",
Label: "File path",
Type: models.String,
}, {
Name: "title",
Label: "Playlist title",
Type: models.String,
}, {
Name: "username",
Label: "User name",
Type: models.String,
}, {
Name: "identifier",
Label: "Unique playlist identifier",
Type: models.String,
}}
}
func (b *JSPFBackend) FromConfig(config *viper.Viper) models.Backend {
b.filePath = config.GetString("file-path")
b.title = config.GetString("title")

View file

@ -43,6 +43,22 @@ type LastfmApiBackend struct {
func (b *LastfmApiBackend) Name() string { return "lastfm" }
func (b *LastfmApiBackend) Options() *[]models.BackendOption {
return &[]models.BackendOption{{
Name: "username",
Label: "User name",
Type: models.String,
}, {
Name: "client-id",
Label: "Client ID",
Type: models.String,
}, {
Name: "client-secret",
Label: "Client secret",
Type: models.Secret,
}}
}
func (b *LastfmApiBackend) FromConfig(config *viper.Viper) models.Backend {
clientId := config.GetString("client-id")
clientSecret := config.GetString("client-secret")

View file

@ -34,6 +34,18 @@ type ListenBrainzApiBackend struct {
func (b *ListenBrainzApiBackend) Name() string { return "listenbrainz" }
func (b *ListenBrainzApiBackend) Options() *[]models.BackendOption {
return &[]models.BackendOption{{
Name: "username",
Label: "User name",
Type: models.String,
}, {
Name: "token",
Label: "Access token",
Type: models.Secret,
}}
}
func (b *ListenBrainzApiBackend) FromConfig(config *viper.Viper) models.Backend {
b.client = NewClient(config.GetString("token"))
b.client.MaxResults = MaxItemsPerGet

View file

@ -33,6 +33,22 @@ type MalojaApiBackend struct {
func (b *MalojaApiBackend) Name() string { return "maloja" }
func (b *MalojaApiBackend) Options() *[]models.BackendOption {
return &[]models.BackendOption{{
Name: "server-url",
Label: "Server URL",
Type: models.String,
}, {
Name: "token",
Label: "Access token",
Type: models.Secret,
}, {
Name: "nofix",
Label: "Disable auto correction of submitted listens",
Type: models.Bool,
}}
}
func (b *MalojaApiBackend) FromConfig(config *viper.Viper) models.Backend {
b.client = NewClient(
config.GetString("server-url"),

View file

@ -36,6 +36,22 @@ type ScrobblerLogBackend struct {
func (b *ScrobblerLogBackend) Name() string { return "scrobbler-log" }
func (b *ScrobblerLogBackend) Options() *[]models.BackendOption {
return &[]models.BackendOption{{
Name: "file-path",
Label: "File path",
Type: models.String,
}, {
Name: "include-skipped",
Label: "Include skipped listens",
Type: models.Bool,
}, {
Name: "append",
Label: "Append to file",
Type: models.Bool,
}}
}
func (b *ScrobblerLogBackend) FromConfig(config *viper.Viper) models.Backend {
b.filePath = config.GetString("file-path")
b.includeSkipped = config.GetBool("include-skipped")

View file

@ -39,6 +39,18 @@ type SpotifyApiBackend struct {
func (b *SpotifyApiBackend) Name() string { return "spotify" }
func (b *SpotifyApiBackend) Options() *[]models.BackendOption {
return &[]models.BackendOption{{
Name: "client-id",
Label: "Client ID",
Type: models.String,
}, {
Name: "client-secret",
Label: "Client secret",
Type: models.Secret,
}}
}
func (b *SpotifyApiBackend) FromConfig(config *viper.Viper) models.Backend {
b.clientId = config.GetString("client-id")
b.clientSecret = config.GetString("client-secret")

View file

@ -34,6 +34,22 @@ type SubsonicApiBackend struct {
func (b *SubsonicApiBackend) Name() string { return "subsonic" }
func (b *SubsonicApiBackend) Options() *[]models.BackendOption {
return &[]models.BackendOption{{
Name: "server-url",
Label: "Server URL",
Type: models.String,
}, {
Name: "username",
Label: "User name",
Type: models.String,
}, {
Name: "token",
Label: "Access token",
Type: models.Secret,
}}
}
func (b *SubsonicApiBackend) FromConfig(config *viper.Viper) models.Backend {
b.client = subsonic.Client{
Client: &http.Client{},

View file

@ -33,6 +33,9 @@ type Backend interface {
// Initialize the backend from a config.
FromConfig(config *viper.Viper) Backend
// Return configuration options
Options() *[]BackendOption
}
type ImportBackend interface {

View file

@ -0,0 +1,32 @@
/*
Copyright © 2023 Philipp Wolfer <phw@uploadedlobster.com>
Scotty is free software: you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later version.
Scotty is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
Scotty. If not, see <https://www.gnu.org/licenses/>.
*/
package models
type OptionType string
const (
Bool OptionType = "bool"
Secret OptionType = "secret"
String OptionType = "string"
)
type BackendOption struct {
Name string
Label string
Type OptionType
Default string
Validate func(string) error
}