2016-03-29 20:05:57 -08:00
package conf
import (
2020-01-26 12:42:56 -09:00
"fmt"
2016-03-29 20:05:57 -08:00
"os"
2020-01-26 12:42:56 -09:00
"path/filepath"
2020-09-05 16:28:27 -08:00
"strings"
2020-07-02 12:41:54 -08:00
"time"
2016-03-29 20:05:57 -08:00
2020-10-24 18:55:19 -08:00
"github.com/kr/pretty"
2020-01-23 15:44:08 -09:00
"github.com/navidrome/navidrome/consts"
"github.com/navidrome/navidrome/log"
2021-05-06 13:56:10 -08:00
"github.com/robfig/cron/v3"
2020-07-02 12:34:21 -08:00
"github.com/spf13/viper"
2016-03-29 20:05:57 -08:00
)
2020-07-02 13:21:25 -08:00
type configOptions struct {
2020-07-02 12:34:21 -08:00
ConfigFile string
2020-07-08 16:54:56 -08:00
Address string
2020-07-02 12:34:21 -08:00
Port int
MusicFolder string
DataFolder string
DbPath string
LogLevel string
2020-07-02 12:41:54 -08:00
ScanInterval time . Duration
2021-05-06 13:56:10 -08:00
ScanSchedule string
2020-07-02 12:41:54 -08:00
SessionTimeout time . Duration
2020-07-02 12:34:21 -08:00
BaseURL string
UILoginBackgroundURL string
EnableTranscodingConfig bool
2020-11-10 12:14:43 -09:00
EnableDownloads bool
2020-07-02 12:34:21 -08:00
TranscodingCacheSize string
ImageCacheSize string
2020-08-02 19:17:13 -08:00
AutoImportPlaylists bool
2020-07-03 07:51:15 -08:00
2021-03-12 13:49:47 -09:00
SearchFullString bool
RecentlyAddedByModTime bool
IgnoredArticles string
IndexGroups string
ProbeCommand string
CoverArtPriority string
CoverJpegQuality int
UIWelcomeMessage string
EnableGravatar bool
2021-03-28 16:35:49 -08:00
EnableFavourites bool
2021-04-07 12:02:52 -08:00
EnableStarRating bool
2021-05-02 13:10:56 -08:00
EnableUserEditing bool
2021-04-18 09:51:00 -08:00
DefaultTheme string
2021-03-12 13:49:47 -09:00
GATrackingID string
2021-05-02 12:39:25 -08:00
EnableLogRedacting bool
2021-03-12 13:49:47 -09:00
AuthRequestLimit int
AuthWindowLength time . Duration
2021-06-11 19:17:21 -08:00
ReverseProxyUserHeader string
ReverseProxyWhitelist string
2020-06-13 09:55:58 -08:00
2020-09-05 16:28:27 -08:00
Scanner scannerOptions
2021-02-07 12:46:15 -09:00
Agents string
2020-10-17 19:59:09 -08:00
LastFM lastfmOptions
2020-10-18 09:23:02 -08:00
Spotify spotifyOptions
2020-09-05 16:28:27 -08:00
2020-01-22 04:32:31 -09:00
// DevFlags. These are used to enable/disable debugging and incomplete features
2020-07-02 12:34:21 -08:00
DevLogSourceLine bool
DevAutoCreateAdminPassword string
2020-10-25 08:00:21 -08:00
DevPreCacheAlbumArtwork bool
2020-11-16 12:39:31 -09:00
DevFastAccessCoverArt bool
2020-11-04 19:25:38 -09:00
DevOldCacheLayout bool
2020-11-25 11:29:46 -09:00
DevActivityPanel bool
2021-05-30 11:36:10 -08:00
DevEnableShare bool
2016-03-29 20:05:57 -08:00
}
2020-09-05 16:28:27 -08:00
type scannerOptions struct {
Extractor string
}
2020-10-17 19:59:09 -08:00
type lastfmOptions struct {
2021-05-27 12:14:24 -08:00
Enabled bool
2020-10-17 19:59:09 -08:00
ApiKey string
Secret string
Language string
}
2020-10-18 09:23:02 -08:00
type spotifyOptions struct {
ID string
Secret string
}
2021-02-07 12:46:15 -09:00
var (
Server = & configOptions { }
hooks [ ] func ( )
)
2020-01-08 06:25:23 -09:00
2020-07-02 12:34:21 -08:00
func LoadFromFile ( confFile string ) {
viper . SetConfigFile ( confFile )
Load ( )
2020-01-26 13:09:08 -09:00
}
2020-07-02 12:34:21 -08:00
func Load ( ) {
err := viper . Unmarshal ( & Server )
2020-01-26 13:09:08 -09:00
if err != nil {
2020-07-02 12:34:21 -08:00
fmt . Println ( "Error parsing config:" , err )
os . Exit ( 1 )
2020-01-26 13:09:08 -09:00
}
2020-07-10 17:43:09 -08:00
err = os . MkdirAll ( Server . DataFolder , os . ModePerm )
if err != nil {
fmt . Println ( "Error creating data path:" , "path" , Server . DataFolder , err )
os . Exit ( 1 )
}
2020-07-02 12:34:21 -08:00
Server . ConfigFile = viper . GetViper ( ) . ConfigFileUsed ( )
2020-01-26 12:42:56 -09:00
if Server . DbPath == "" {
2020-02-28 10:35:32 -09:00
Server . DbPath = filepath . Join ( Server . DataFolder , consts . DefaultDbPath )
2020-01-26 12:42:56 -09:00
}
2020-07-02 12:34:21 -08:00
2020-01-31 04:35:33 -09:00
log . SetLevelString ( Server . LogLevel )
log . SetLogSourceLine ( Server . DevLogSourceLine )
2021-05-02 12:39:25 -08:00
log . SetRedacting ( Server . EnableLogRedacting )
2021-05-06 13:56:10 -08:00
if err := validateScanSchedule ( ) ; err != nil {
os . Exit ( 1 )
}
2021-05-30 12:01:36 -08:00
// Print current configuration if log level is Debug
2021-05-12 10:43:09 -08:00
if log . CurrentLevel ( ) >= log . LevelDebug {
2021-05-30 12:01:36 -08:00
prettyConf := pretty . Sprintf ( "Loaded configuration from '%s': %# v" , Server . ConfigFile , Server )
if Server . EnableLogRedacting {
prettyConf = log . Redact ( prettyConf )
}
fmt . Println ( prettyConf )
2021-05-12 10:43:09 -08:00
}
2021-02-07 12:46:15 -09:00
// Call init hooks
for _ , hook := range hooks {
hook ( )
}
}
2021-05-06 13:56:10 -08:00
func validateScanSchedule ( ) error {
2021-05-12 10:08:38 -08:00
if Server . ScanInterval != - 1 {
2021-05-06 13:56:10 -08:00
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 {
2021-05-12 10:08:38 -08:00
if Server . ScanInterval == 0 {
Server . ScanSchedule = ""
} else {
Server . ScanSchedule = fmt . Sprintf ( "@every %s" , Server . ScanInterval )
}
2021-05-06 13:56:10 -08:00
log . Warn ( "Setting ScanSchedule" , "schedule" , Server . ScanSchedule )
}
}
2021-05-06 16:49:26 -08:00
if Server . ScanSchedule == "" {
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-06 13:56:10 -08:00
}
2021-05-06 16:49:26 -08:00
return err
2021-05-06 13:56:10 -08:00
}
2021-02-07 12:46:15 -09: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-29 20:05:57 -08:00
}
2020-07-02 13:21:25 -08:00
func init ( ) {
2020-07-28 04:49:07 -08:00
viper . SetDefault ( "musicfolder" , filepath . Join ( "." , "music" ) )
viper . SetDefault ( "datafolder" , "." )
2020-07-02 12:34:21 -08:00
viper . SetDefault ( "loglevel" , "info" )
2020-07-08 16:54:56 -08:00
viper . SetDefault ( "address" , "0.0.0.0" )
2020-07-02 12:34:21 -08:00
viper . SetDefault ( "port" , 4533 )
2020-07-02 12:41:54 -08:00
viper . SetDefault ( "sessiontimeout" , consts . DefaultSessionTimeout )
2021-05-12 10:08:38 -08:00
viper . SetDefault ( "scaninterval" , - 1 )
2021-05-06 13:56:10 -08:00
viper . SetDefault ( "scanschedule" , "@every 1m" )
2020-07-02 12:34:21 -08:00
viper . SetDefault ( "baseurl" , "" )
2021-03-24 06:21:31 -08:00
viper . SetDefault ( "uiloginbackgroundurl" , consts . DefaultUILoginBackgroundURL )
2020-07-02 12:34:21 -08:00
viper . SetDefault ( "enabletranscodingconfig" , false )
viper . SetDefault ( "transcodingcachesize" , "100MB" )
2021-01-31 20:31:02 -09:00
viper . SetDefault ( "imagecachesize" , "100MB" )
2020-08-02 19:17:13 -08:00
viper . SetDefault ( "autoimportplaylists" , true )
2020-11-10 12:14:43 -09:00
viper . SetDefault ( "enabledownloads" , true )
2020-07-02 12:34:21 -08:00
2020-07-19 10:45:05 -08:00
// Config options only valid for file/env configuration
2020-08-30 09:08:10 -08:00
viper . SetDefault ( "searchfullstring" , false )
2021-03-12 13:49:47 -09:00
viper . SetDefault ( "recentlyaddedbymodtime" , false )
2020-07-02 12:34:21 -08: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 )
2020-07-03 07:51:15 -08:00
viper . SetDefault ( "uiwelcomemessage" , "" )
2020-11-12 20:40:01 -09:00
viper . SetDefault ( "enablegravatar" , false )
2021-03-28 16:35:49 -08:00
viper . SetDefault ( "enablefavourites" , true )
2021-04-07 12:02:52 -08:00
viper . SetDefault ( "enablestarrating" , true )
2021-05-02 13:10:56 -08:00
viper . SetDefault ( "enableuserediting" , true )
2021-04-18 09:51:00 -08:00
viper . SetDefault ( "defaulttheme" , "Dark" )
2020-07-03 08:53:35 -08:00
viper . SetDefault ( "gatrackingid" , "" )
2021-05-02 12:49:20 -08:00
viper . SetDefault ( "enablelogredacting" , true )
2020-07-19 10:45:05 -08:00
viper . SetDefault ( "authrequestlimit" , 5 )
viper . SetDefault ( "authwindowlength" , 20 * time . Second )
2020-07-02 12:34:21 -08:00
2021-06-11 19:17:21 -08:00
viper . SetDefault ( "reverseproxyuserheader" , "Remote-User" )
2021-06-13 08:46:36 -08:00
viper . SetDefault ( "reverseproxywhitelist" , "" )
2021-06-11 19:17:21 -08:00
2020-10-05 17:01:03 -08:00
viper . SetDefault ( "scanner.extractor" , "taglib" )
2021-02-07 12:46:15 -09:00
viper . SetDefault ( "agents" , "lastfm,spotify" )
2021-05-27 12:14:24 -08:00
viper . SetDefault ( "lastfm.enabled" , true )
2020-10-17 19:59:09 -08:00
viper . SetDefault ( "lastfm.language" , "en" )
2020-10-22 04:31:47 -08:00
viper . SetDefault ( "lastfm.apikey" , "" )
viper . SetDefault ( "lastfm.secret" , "" )
viper . SetDefault ( "spotify.id" , "" )
viper . SetDefault ( "spotify.secret" , "" )
2020-09-05 16:28:27 -08:00
2020-07-02 12:34:21 -08:00
// DevFlags. These are used to enable/disable debugging and incomplete features
viper . SetDefault ( "devlogsourceline" , false )
viper . SetDefault ( "devautocreateadminpassword" , "" )
2020-10-25 08:00:21 -08:00
viper . SetDefault ( "devprecachealbumartwork" , false )
2020-11-04 19:25:38 -09:00
viper . SetDefault ( "devoldcachelayout" , false )
2020-11-16 12:39:31 -09:00
viper . SetDefault ( "devFastAccessCoverArt" , false )
2021-01-31 20:31:02 -09:00
viper . SetDefault ( "devactivitypanel" , true )
2021-05-30 11:36:10 -08:00
viper . SetDefault ( "devenableshare" , false )
2016-03-29 20:05:57 -08:00
}
2020-07-02 13:21:25 -08:00
2020-07-03 05:39:28 -08:00
func InitConfig ( cfgFile string ) {
2020-07-20 14:36:12 -08:00
cfgFile = getConfigFile ( cfgFile )
2020-07-02 13:21:25 -08: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-02 14:17:31 -08:00
_ = viper . BindEnv ( "port" )
2020-07-02 13:21:25 -08:00
viper . SetEnvPrefix ( "ND" )
2020-09-05 16:28:27 -08:00
replacer := strings . NewReplacer ( "." , "_" )
viper . SetEnvKeyReplacer ( replacer )
2020-07-02 13:21:25 -08:00
viper . AutomaticEnv ( )
2020-07-03 06:19:44 -08:00
err := viper . ReadInConfig ( )
if cfgFile != "" && err != nil {
fmt . Println ( "Navidrome could not open config file: " , err )
os . Exit ( 1 )
}
2020-07-02 13:21:25 -08:00
}
2020-07-20 14:36:12 -08:00
func getConfigFile ( cfgFile string ) string {
if cfgFile != "" {
return cfgFile
}
return os . Getenv ( "ND_CONFIGFILE" )
}