navidrome/conf/configuration.go

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

318 lines
9.5 KiB
Go
Raw Normal View History

2016-03-30 06:05:57 +02:00
package conf
import (
"fmt"
2016-03-30 06:05:57 +02:00
"os"
"path/filepath"
"strings"
2020-07-02 22:41:54 +02:00
"time"
2016-03-30 06:05:57 +02:00
2020-10-25 03:55:19 +01:00
"github.com/kr/pretty"
2020-01-24 01:44:08 +01:00
"github.com/navidrome/navidrome/consts"
"github.com/navidrome/navidrome/log"
"github.com/robfig/cron/v3"
2020-07-02 22:34:21 +02:00
"github.com/spf13/viper"
2016-03-30 06:05:57 +02:00
)
2020-07-02 23:21:25 +02:00
type configOptions struct {
2020-07-02 22:34:21 +02:00
ConfigFile string
Address string
2020-07-02 22:34:21 +02:00
Port int
MusicFolder string
DataFolder string
DbPath string
LogLevel string
2020-07-02 22:41:54 +02:00
ScanInterval time.Duration
ScanSchedule string
2020-07-02 22:41:54 +02:00
SessionTimeout time.Duration
2020-07-02 22:34:21 +02:00
BaseURL string
UILoginBackgroundURL string
EnableTranscodingConfig bool
EnableDownloads bool
EnableExternalServices bool
2020-07-02 22:34:21 +02:00
TranscodingCacheSize string
ImageCacheSize string
2020-08-03 05:17:13 +02:00
AutoImportPlaylists bool
PlaylistsPath string
AutoTranscodeDownload bool
SearchFullString bool
RecentlyAddedByModTime bool
IgnoredArticles string
IndexGroups string
ProbeCommand string
CoverArtPriority string
CoverJpegQuality int
UIWelcomeMessage string
EnableGravatar bool
EnableFavourites bool
EnableStarRating bool
EnableUserEditing bool
2021-04-18 19:51:00 +02:00
DefaultTheme string
DefaultLanguage string
DefaultUIVolume int
EnableCoverAnimation bool
GATrackingID string
EnableLogRedacting bool
AuthRequestLimit int
AuthWindowLength time.Duration
PasswordEncryptionKey string
ReverseProxyUserHeader string
ReverseProxyWhitelist string
Prometheus prometheusOptions
Scanner scannerOptions
2021-02-07 22:46:15 +01:00
Agents string
LastFM lastfmOptions
Spotify spotifyOptions
ListenBrainz listenBrainzOptions
//test downsampling
DefaultDownsamplingFormat string
// DevFlags. These are used to enable/disable debugging and incomplete features
2020-07-02 22:34:21 +02:00
DevLogSourceLine bool
DevLogLevels map[string]string
2020-07-02 22:34:21 +02:00
DevAutoCreateAdminPassword string
DevAutoLoginUsername string
DevFastAccessCoverArt bool
DevActivityPanel bool
DevEnableShare bool
DevSidebarPlaylists bool
DevEnableBufferedScrobble bool
DevShowArtistPage bool
2016-03-30 06:05:57 +02:00
}
type scannerOptions struct {
Extractor string
GenreSeparators string
}
type lastfmOptions struct {
Enabled bool
ApiKey string
Secret string
Language string
}
type spotifyOptions struct {
ID string
Secret string
}
type listenBrainzOptions struct {
Enabled bool
BaseURL string
}
type prometheusOptions struct {
Enabled bool
MetricsPath string
}
2021-02-07 22:46:15 +01:00
var (
Server = &configOptions{}
hooks []func()
)
2020-01-08 16:25:23 +01:00
2020-07-02 22:34:21 +02:00
func LoadFromFile(confFile string) {
viper.SetConfigFile(confFile)
Load()
}
2020-07-02 22:34:21 +02:00
func Load() {
err := viper.Unmarshal(&Server)
if err != nil {
_, _ = fmt.Fprintln(os.Stderr, "FATAL: Error parsing config:", err)
2020-07-02 22:34:21 +02:00
os.Exit(1)
}
err = os.MkdirAll(Server.DataFolder, os.ModePerm)
if err != nil {
_, _ = fmt.Fprintln(os.Stderr, "FATAL: Error creating data path:", "path", Server.DataFolder, err)
os.Exit(1)
}
2020-07-02 22:34:21 +02:00
Server.ConfigFile = viper.GetViper().ConfigFileUsed()
if Server.DbPath == "" {
Server.DbPath = filepath.Join(Server.DataFolder, consts.DefaultDbPath)
}
2020-07-02 22:34:21 +02:00
log.SetLevelString(Server.LogLevel)
log.SetLogLevels(Server.DevLogLevels)
log.SetLogSourceLine(Server.DevLogSourceLine)
log.SetRedacting(Server.EnableLogRedacting)
if err := validateScanSchedule(); err != nil {
os.Exit(1)
}
// Print current configuration if log level is Debug
if log.CurrentLevel() >= log.LevelDebug {
prettyConf := pretty.Sprintf("Loaded configuration from '%s': %# v", Server.ConfigFile, Server)
if Server.EnableLogRedacting {
prettyConf = log.Redact(prettyConf)
}
_, _ = fmt.Fprintln(os.Stderr, prettyConf)
}
2021-02-07 22:46:15 +01:00
if !Server.EnableExternalServices {
disableExternalServices()
}
2021-02-07 22:46:15 +01:00
// Call init hooks
for _, hook := range hooks {
hook()
}
}
func disableExternalServices() {
log.Info("All external integrations are DISABLED!")
Server.LastFM.Enabled = false
Server.Spotify.ID = ""
Server.ListenBrainz.Enabled = false
Server.Agents = ""
if Server.UILoginBackgroundURL == consts.DefaultUILoginBackgroundURL {
Server.UILoginBackgroundURL = consts.DefaultUILoginBackgroundURLOffline
}
}
func validateScanSchedule() error {
if Server.ScanInterval != -1 {
log.Warn("ScanInterval is DEPRECATED. Please use ScanSchedule. See docs at https://navidrome.org/docs/usage/configuration-options/")
if Server.ScanSchedule != "@every 1m" {
log.Error("You cannot specify both ScanInterval and ScanSchedule, ignoring ScanInterval")
} else {
if Server.ScanInterval == 0 {
Server.ScanSchedule = ""
} else {
Server.ScanSchedule = fmt.Sprintf("@every %s", Server.ScanInterval)
}
log.Warn("Setting ScanSchedule", "schedule", Server.ScanSchedule)
}
}
if Server.ScanSchedule == "0" || Server.ScanSchedule == "" {
Server.ScanSchedule = ""
2021-05-07 02:49:26 +02:00
return nil
}
if _, err := time.ParseDuration(Server.ScanSchedule); err == nil {
Server.ScanSchedule = "@every " + Server.ScanSchedule
}
c := cron.New()
_, err := c.AddFunc(Server.ScanSchedule, func() {})
if err != nil {
log.Error("Invalid ScanSchedule. Please read format spec at https://pkg.go.dev/github.com/robfig/cron#hdr-CRON_Expression_Format", "schedule", Server.ScanSchedule, err)
}
2021-05-07 02:49:26 +02:00
return err
}
2021-02-07 22:46:15 +01:00
// AddHook is used to register initialization code that should run as soon as the config is loaded
func AddHook(hook func()) {
hooks = append(hooks, hook)
2016-03-30 06:05:57 +02:00
}
2020-07-02 23:21:25 +02:00
func init() {
2020-07-28 14:49:07 +02:00
viper.SetDefault("musicfolder", filepath.Join(".", "music"))
viper.SetDefault("datafolder", ".")
2020-07-02 22:34:21 +02:00
viper.SetDefault("loglevel", "info")
viper.SetDefault("address", "0.0.0.0")
2020-07-02 22:34:21 +02:00
viper.SetDefault("port", 4533)
2020-07-02 22:41:54 +02:00
viper.SetDefault("sessiontimeout", consts.DefaultSessionTimeout)
viper.SetDefault("scaninterval", -1)
viper.SetDefault("scanschedule", "@every 1m")
2020-07-02 22:34:21 +02:00
viper.SetDefault("baseurl", "")
2021-03-24 15:21:31 +01:00
viper.SetDefault("uiloginbackgroundurl", consts.DefaultUILoginBackgroundURL)
2020-07-02 22:34:21 +02:00
viper.SetDefault("enabletranscodingconfig", false)
viper.SetDefault("transcodingcachesize", "100MB")
viper.SetDefault("imagecachesize", "100MB")
2020-08-03 05:17:13 +02:00
viper.SetDefault("autoimportplaylists", true)
viper.SetDefault("playlistspath", consts.DefaultPlaylistsPath)
viper.SetDefault("enabledownloads", true)
viper.SetDefault("enableexternalservices", true)
viper.SetDefault("autotranscodedownload", false)
2020-07-02 22:34:21 +02:00
// Config options only valid for file/env configuration
viper.SetDefault("searchfullstring", false)
viper.SetDefault("recentlyaddedbymodtime", false)
2020-07-02 22:34:21 +02:00
viper.SetDefault("ignoredarticles", "The El La Los Las Le Les Os As O A")
viper.SetDefault("indexgroups", "A B C D E F G H I J K L M N O P Q R S T U V W X-Z(XYZ) [Unknown]([)")
viper.SetDefault("probecommand", "ffmpeg %s -f ffmetadata")
viper.SetDefault("coverartpriority", "embedded, cover.*, folder.*, front.*")
viper.SetDefault("coverjpegquality", 75)
viper.SetDefault("uiwelcomemessage", "")
viper.SetDefault("enablegravatar", false)
viper.SetDefault("enablefavourites", true)
viper.SetDefault("enablestarrating", true)
viper.SetDefault("enableuserediting", true)
2021-04-18 19:51:00 +02:00
viper.SetDefault("defaulttheme", "Dark")
viper.SetDefault("defaultlanguage", "")
viper.SetDefault("defaultuivolume", consts.DefaultUIVolume)
viper.SetDefault("enablecoveranimation", true)
viper.SetDefault("gatrackingid", "")
2021-05-02 22:49:20 +02:00
viper.SetDefault("enablelogredacting", true)
viper.SetDefault("authrequestlimit", 5)
viper.SetDefault("authwindowlength", 20*time.Second)
viper.SetDefault("passwordencryptionkey", "")
2020-07-02 22:34:21 +02:00
viper.SetDefault("reverseproxyuserheader", "Remote-User")
viper.SetDefault("reverseproxywhitelist", "")
viper.SetDefault("prometheus.enabled", false)
viper.SetDefault("prometheus.metricspath", "/metrics")
viper.SetDefault("scanner.extractor", consts.DefaultScannerExtractor)
2021-07-16 17:03:28 +02:00
viper.SetDefault("scanner.genreseparators", ";/,")
2021-02-07 22:46:15 +01:00
viper.SetDefault("agents", "lastfm,spotify")
viper.SetDefault("lastfm.enabled", true)
viper.SetDefault("lastfm.language", "en")
2021-06-21 23:09:34 +02:00
viper.SetDefault("lastfm.apikey", consts.LastFMAPIKey)
viper.SetDefault("lastfm.secret", consts.LastFMAPISecret)
viper.SetDefault("spotify.id", "")
viper.SetDefault("spotify.secret", "")
viper.SetDefault("listenbrainz.enabled", true)
viper.SetDefault("listenbrainz.baseurl", "https://api.listenbrainz.org/1/")
viper.SetDefault("defaultdownsamplingformat", consts.DefaultDownsamplingFormat)
2020-07-02 22:34:21 +02:00
// DevFlags. These are used to enable/disable debugging and incomplete features
viper.SetDefault("devlogsourceline", false)
viper.SetDefault("devautocreateadminpassword", "")
viper.SetDefault("devautologinusername", "")
viper.SetDefault("devfastaccesscoverart", false)
viper.SetDefault("devactivitypanel", true)
viper.SetDefault("devenableshare", false)
2021-07-19 22:10:37 +02:00
viper.SetDefault("devenablebufferedscrobble", true)
viper.SetDefault("devsidebarplaylists", true)
2021-10-17 17:07:59 +02:00
viper.SetDefault("devshowartistpage", true)
2016-03-30 06:05:57 +02:00
}
2020-07-02 23:21:25 +02:00
2020-07-03 15:39:28 +02:00
func InitConfig(cfgFile string) {
cfgFile = getConfigFile(cfgFile)
2020-07-02 23:21:25 +02:00
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Search config in local directory with name "navidrome" (without extension).
viper.AddConfigPath(".")
viper.SetConfigName("navidrome")
}
2020-07-03 00:17:31 +02:00
_ = viper.BindEnv("port")
2020-07-02 23:21:25 +02:00
viper.SetEnvPrefix("ND")
replacer := strings.NewReplacer(".", "_")
viper.SetEnvKeyReplacer(replacer)
2020-07-02 23:21:25 +02:00
viper.AutomaticEnv()
2020-07-03 16:19:44 +02:00
err := viper.ReadInConfig()
if viper.ConfigFileUsed() != "" && err != nil {
_, _ = fmt.Fprintln(os.Stderr, "FATAL: Navidrome could not open config file: ", err)
2020-07-03 16:19:44 +02:00
}
2020-07-02 23:21:25 +02:00
}
func getConfigFile(cfgFile string) string {
if cfgFile != "" {
return cfgFile
}
return os.Getenv("ND_CONFIGFILE")
}