2020-07-02 22:34:21 +02:00
package cmd
import (
2021-01-31 23:37:54 +01:00
"context"
2022-11-21 18:14:06 +01:00
"errors"
2020-07-02 22:34:21 +02:00
"fmt"
"os"
2022-11-29 20:40:44 +01:00
"strings"
2020-10-25 03:43:59 +01:00
"time"
2020-07-02 22:34:21 +02:00
2023-03-15 15:56:13 +01:00
"github.com/go-chi/chi/v5/middleware"
2020-07-02 22:34:21 +02:00
"github.com/navidrome/navidrome/conf"
"github.com/navidrome/navidrome/consts"
2023-01-25 01:26:07 +01:00
"github.com/navidrome/navidrome/core"
Jukebox mode (#2289)
* Adding cache directory to ignore-list
* Adding jukebox-related config options
* Adding DevEnableJukebox config option pls. dummy server
* Adding types and routers
* Now without panic
* First draft on parsing the action
* Some cleanups
* Adding playback server
* Verify audio device configuration
* Adding debug-build target to have full symbol support
* Adding beep sound library pls some example code. Not working yet
* Play a fixed mp3 on any interface access for testing purposes
* Put action code into separate file, adding stringer, more debug output, prepare structs, validation
* Put action parameter parser code where it belongs
* Have a single Action transporting all information
* User fmt.Errorf for error-generation
* Adding wide playback interface
* Use action map for parsing, stringer instead switch stmt.
* Use but only one switch case and direct dispatch, refactoring
* Add error handling and pushing to client
* send decent errormessage, no internal server error
* Adding playback devices slice and load it from config
* Combine config-verification and structure init
* Return user-specific device
* Separate playback server from device
* Use dataStore to retrieve mediafile by id
* WIP: Playlist and start/stop handling. Doing start/stop the hard way as of now
* WIP: set, start and stop work on one single song. More to come
* Dont need to wait for the end
* Merge jukebox_action.go into jukebox.go
* Remove getParameterAsInt64(). Use existing requiredParamInt() instead
* Dont need to call newFailure() explicitly
* Remove int64, use int instead.
* Add and set action now accept multiple ids
* Kickout copy of childFromMediaFile(). It is not needed here.
* Refactoring devices and playbackServer
* Turn (internal) playback.DeviceStatus into subsonic JukeboxStatus when rendering output. Indexes int64 -> int
* Now we have a position and playing status
* Switching gain to float32, xs:float is defined as 32 bit. Fixing nasty copy/pointer bug
* Now with volume control
* Start working the queue
* Remove user from device interface
* Rename function GetDevice -> GetDeviceForUser to make intention clearer
* Have a nice stringer for the queue
* User Prepared boolean for now to allow pause/unpause
* Skipping works, but without offsets
* Make ChildFromMediaFile public to be used in jukebox get() implementation
* Return position in seconds and implement offset-skip in seconds
* Default offset to 0
* Adding a simple setGain implementation
* Prepare for transcoding AAC
* WIP: transcode to WAV to use beeps wav decoder. Not done yet.
* WIP: out of sheer desparation: convert to MP3 (which works) rather than WAV to troubleshoot issue.
* Use FLAC as intermediate format to play Apple AAC
* A bit of cleanup
* Catching the end-of-stream event for further reactions
* Have a trackSwitching goroutine waiting on channel when track ends
* Move decoder code into own file. Restructure code a bit
* Now with going on to play the next song in the playlist
* Adding shuffle feature
* Implementing remove action
* Cleanup code
* Remove templates for ffmpeg mp3 generation. Not needed anymore.
* Adding some documentation
* Check whether offset into track is in range. Fixing potential remove track bug. Documentation
* Make golangci-lint happy: handling return values
* Adding test suite and example dummy for playback package
* Adding some basic queue tests
* Only use Jukebox.Enabled config option
* Adding stream closing handling
* Pass context.Context to all PlaybackDevice methods
* Remove unneeded function
* Correct spelling
* Reduce visibility of ChildFromMediaFile
* Decomplicate action-parsing
* Adding simple tempfile-based AAC->FLAC transcoding. No parallel reading and writing yet.
* Try to optimize pipe-writing, tempfile-handling and reading. Not done yet.
* Do a synchronous copy of the tempfile. Racecondition detected
* More debugging statements and fixing the play/pause bug. More work needed
* Start the trackSwitcher() with each device once. Return JSON position even if its 0. More debug-output
* Moving all track-handling code into own module
* Fix typo. Do not pass ctx around when not applicable
* WIP: More refactoring, debugging output
* Fix nil pointer
* Repairing MP3 playback by pinning indirect dependencies: hajimehoshi/go-mp3 and hajimehoshi/oto
* Do not forget to cleanup after a skip action
* Make resync with master easy
* Adding missing mocks
* Adding missing error-handling found by linter
* Updating github.com/hajimehoshi/oto
* Removing duplicate function
* Move BEEP-related code into own package
* Juggle beep-related code around as preparation for interface access
* More refactoring for interface separation
* Gather CloseDevice() behind Track interface.
* Adding skeleton, draft audio-interface using mpv.io
* Adding majority of interface commands using messages to mpv socket.
* Adding end-of-stream handling
* MPV: start/stop are working
* postition is given in float in mpv
* Unify Close() and CloseDevice(). Using temp filename for controlling socket
* Wait until control-socket shows up. Cleanup socket in Close()
* Use canceable command. Rename to Executor
* Skipping tracks works now
* Now with actually setting the position
* Fix regain
* Add missing error-handling found by linter
* Adding retry mode on time-pos property getter
* Remove unneeded code on queue
* Putting build-tag beep onto beep files
* Remove deprecated call to rand.Seed()
"As of Go 1.20 there is no reason to call Seed with a random value. Programs that call Seed with a known value to get a specific sequence of results should use New(NewSource(seed)) to obtain a local random generator."
* Using int32 to conform to Subsonic API spec
* Fix merge error
* Minor style changes
* Get username from context
---------
Co-authored-by: Deluan <deluan@navidrome.org>
2023-09-10 17:25:22 +02:00
"github.com/navidrome/navidrome/core/playback"
2020-07-02 23:21:25 +02:00
"github.com/navidrome/navidrome/db"
2020-10-25 03:43:59 +01:00
"github.com/navidrome/navidrome/log"
2021-10-28 16:25:25 +02:00
"github.com/navidrome/navidrome/resources"
2021-06-22 00:41:11 +02:00
"github.com/navidrome/navidrome/scheduler"
2022-11-28 03:37:19 +01:00
"github.com/navidrome/navidrome/server/backgrounds"
2022-10-03 01:59:53 +02:00
"github.com/prometheus/client_golang/prometheus/promhttp"
2022-11-21 18:14:06 +01:00
"golang.org/x/sync/errgroup"
2022-10-03 01:59:53 +02:00
2020-07-02 22:34:21 +02:00
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
2022-11-21 18:14:06 +01:00
var interrupted = errors . New ( "service was interrupted" )
2020-07-02 22:34:21 +02:00
var (
2020-07-03 02:08:41 +02:00
cfgFile string
noBanner bool
2020-07-02 22:34:21 +02:00
rootCmd = & cobra . Command {
Use : "navidrome" ,
Short : "Navidrome is a self-hosted music server and streamer" ,
Long : ` Navidrome is a self - hosted music server and streamer .
Complete documentation is available at https : //www.navidrome.org/docs`,
2020-07-03 02:08:41 +02:00
PersistentPreRun : func ( cmd * cobra . Command , args [ ] string ) {
preRun ( )
} ,
2020-07-02 22:34:21 +02:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
2020-10-25 03:43:59 +01:00
runNavidrome ( )
2020-07-02 22:34:21 +02:00
} ,
2022-09-15 03:09:39 +02:00
Version : consts . Version ,
2020-07-02 22:34:21 +02:00
}
)
func Execute ( ) {
rootCmd . SetVersionTemplate ( ` {{ println .Version }} ` )
if err := rootCmd . Execute ( ) ; err != nil {
fmt . Println ( err )
os . Exit ( 1 )
}
}
2020-07-03 02:08:41 +02:00
func preRun ( ) {
if ! noBanner {
2021-10-28 16:25:25 +02:00
println ( resources . Banner ( ) )
2020-07-03 02:08:41 +02:00
}
2020-07-02 23:21:25 +02:00
conf . Load ( )
2020-07-03 02:08:41 +02:00
}
2020-10-25 03:43:59 +01:00
func runNavidrome ( ) {
2023-04-04 16:30:28 +02:00
db . Init ( )
2022-11-21 18:14:06 +01:00
defer func ( ) {
if err := db . Close ( ) ; err != nil {
log . Error ( "Error closing DB" , err )
}
2022-11-26 19:13:05 +01:00
log . Info ( "Navidrome stopped, bye." )
2022-11-21 18:14:06 +01:00
} ( )
2020-07-02 23:21:25 +02:00
2022-11-21 18:14:06 +01:00
g , ctx := errgroup . WithContext ( context . Background ( ) )
g . Go ( startServer ( ctx ) )
g . Go ( startSignaler ( ctx ) )
g . Go ( startScheduler ( ctx ) )
g . Go ( schedulePeriodicScan ( ctx ) )
2020-10-25 23:17:23 +01:00
Jukebox mode (#2289)
* Adding cache directory to ignore-list
* Adding jukebox-related config options
* Adding DevEnableJukebox config option pls. dummy server
* Adding types and routers
* Now without panic
* First draft on parsing the action
* Some cleanups
* Adding playback server
* Verify audio device configuration
* Adding debug-build target to have full symbol support
* Adding beep sound library pls some example code. Not working yet
* Play a fixed mp3 on any interface access for testing purposes
* Put action code into separate file, adding stringer, more debug output, prepare structs, validation
* Put action parameter parser code where it belongs
* Have a single Action transporting all information
* User fmt.Errorf for error-generation
* Adding wide playback interface
* Use action map for parsing, stringer instead switch stmt.
* Use but only one switch case and direct dispatch, refactoring
* Add error handling and pushing to client
* send decent errormessage, no internal server error
* Adding playback devices slice and load it from config
* Combine config-verification and structure init
* Return user-specific device
* Separate playback server from device
* Use dataStore to retrieve mediafile by id
* WIP: Playlist and start/stop handling. Doing start/stop the hard way as of now
* WIP: set, start and stop work on one single song. More to come
* Dont need to wait for the end
* Merge jukebox_action.go into jukebox.go
* Remove getParameterAsInt64(). Use existing requiredParamInt() instead
* Dont need to call newFailure() explicitly
* Remove int64, use int instead.
* Add and set action now accept multiple ids
* Kickout copy of childFromMediaFile(). It is not needed here.
* Refactoring devices and playbackServer
* Turn (internal) playback.DeviceStatus into subsonic JukeboxStatus when rendering output. Indexes int64 -> int
* Now we have a position and playing status
* Switching gain to float32, xs:float is defined as 32 bit. Fixing nasty copy/pointer bug
* Now with volume control
* Start working the queue
* Remove user from device interface
* Rename function GetDevice -> GetDeviceForUser to make intention clearer
* Have a nice stringer for the queue
* User Prepared boolean for now to allow pause/unpause
* Skipping works, but without offsets
* Make ChildFromMediaFile public to be used in jukebox get() implementation
* Return position in seconds and implement offset-skip in seconds
* Default offset to 0
* Adding a simple setGain implementation
* Prepare for transcoding AAC
* WIP: transcode to WAV to use beeps wav decoder. Not done yet.
* WIP: out of sheer desparation: convert to MP3 (which works) rather than WAV to troubleshoot issue.
* Use FLAC as intermediate format to play Apple AAC
* A bit of cleanup
* Catching the end-of-stream event for further reactions
* Have a trackSwitching goroutine waiting on channel when track ends
* Move decoder code into own file. Restructure code a bit
* Now with going on to play the next song in the playlist
* Adding shuffle feature
* Implementing remove action
* Cleanup code
* Remove templates for ffmpeg mp3 generation. Not needed anymore.
* Adding some documentation
* Check whether offset into track is in range. Fixing potential remove track bug. Documentation
* Make golangci-lint happy: handling return values
* Adding test suite and example dummy for playback package
* Adding some basic queue tests
* Only use Jukebox.Enabled config option
* Adding stream closing handling
* Pass context.Context to all PlaybackDevice methods
* Remove unneeded function
* Correct spelling
* Reduce visibility of ChildFromMediaFile
* Decomplicate action-parsing
* Adding simple tempfile-based AAC->FLAC transcoding. No parallel reading and writing yet.
* Try to optimize pipe-writing, tempfile-handling and reading. Not done yet.
* Do a synchronous copy of the tempfile. Racecondition detected
* More debugging statements and fixing the play/pause bug. More work needed
* Start the trackSwitcher() with each device once. Return JSON position even if its 0. More debug-output
* Moving all track-handling code into own module
* Fix typo. Do not pass ctx around when not applicable
* WIP: More refactoring, debugging output
* Fix nil pointer
* Repairing MP3 playback by pinning indirect dependencies: hajimehoshi/go-mp3 and hajimehoshi/oto
* Do not forget to cleanup after a skip action
* Make resync with master easy
* Adding missing mocks
* Adding missing error-handling found by linter
* Updating github.com/hajimehoshi/oto
* Removing duplicate function
* Move BEEP-related code into own package
* Juggle beep-related code around as preparation for interface access
* More refactoring for interface separation
* Gather CloseDevice() behind Track interface.
* Adding skeleton, draft audio-interface using mpv.io
* Adding majority of interface commands using messages to mpv socket.
* Adding end-of-stream handling
* MPV: start/stop are working
* postition is given in float in mpv
* Unify Close() and CloseDevice(). Using temp filename for controlling socket
* Wait until control-socket shows up. Cleanup socket in Close()
* Use canceable command. Rename to Executor
* Skipping tracks works now
* Now with actually setting the position
* Fix regain
* Add missing error-handling found by linter
* Adding retry mode on time-pos property getter
* Remove unneeded code on queue
* Putting build-tag beep onto beep files
* Remove deprecated call to rand.Seed()
"As of Go 1.20 there is no reason to call Seed with a random value. Programs that call Seed with a known value to get a specific sequence of results should use New(NewSource(seed)) to obtain a local random generator."
* Using int32 to conform to Subsonic API spec
* Fix merge error
* Minor style changes
* Get username from context
---------
Co-authored-by: Deluan <deluan@navidrome.org>
2023-09-10 17:25:22 +02:00
if conf . Server . Jukebox . Enabled {
g . Go ( startPlaybackServer ( ctx ) )
}
2022-11-21 18:14:06 +01:00
if err := g . Wait ( ) ; err != nil && ! errors . Is ( err , interrupted ) {
2020-10-25 03:43:59 +01:00
log . Error ( "Fatal error in Navidrome. Aborting" , err )
}
}
2022-11-21 18:14:06 +01:00
func startServer ( ctx context . Context ) func ( ) error {
2020-10-25 03:43:59 +01:00
return func ( ) error {
2022-11-21 18:14:06 +01:00
a := CreateServer ( conf . Server . MusicFolder )
a . MountRouter ( "Native API" , consts . URLPathNativeAPI , CreateNativeAPIRouter ( ) )
a . MountRouter ( "Subsonic API" , consts . URLPathSubsonicAPI , CreateSubsonicAPIRouter ( ) )
2023-01-20 22:01:16 +01:00
a . MountRouter ( "Public Endpoints" , consts . URLPathPublic , CreatePublicRouter ( ) )
2022-11-21 18:14:06 +01:00
if conf . Server . LastFM . Enabled {
a . MountRouter ( "LastFM Auth" , consts . URLPathNativeAPI + "/lastfm" , CreateLastFMRouter ( ) )
2020-10-25 03:43:59 +01:00
}
2022-11-21 18:14:06 +01:00
if conf . Server . ListenBrainz . Enabled {
a . MountRouter ( "ListenBrainz Auth" , consts . URLPathNativeAPI + "/listenbrainz" , CreateListenBrainzRouter ( ) )
}
if conf . Server . Prometheus . Enabled {
2023-01-25 01:26:07 +01:00
// blocking call because takes <1ms but useful if fails
core . WriteInitialMetrics ( )
2022-11-21 18:14:06 +01:00
a . MountRouter ( "Prometheus metrics" , conf . Server . Prometheus . MetricsPath , promhttp . Handler ( ) )
}
2023-03-15 15:56:13 +01:00
if conf . Server . DevEnableProfiler {
a . MountRouter ( "Profiling" , "/debug" , middleware . Profiler ( ) )
}
2022-11-29 20:40:44 +01:00
if strings . HasPrefix ( conf . Server . UILoginBackgroundURL , "/" ) {
2022-11-28 03:37:19 +01:00
a . MountRouter ( "Background images" , consts . DefaultUILoginBackgroundURL , backgrounds . NewHandler ( ) )
}
2023-03-29 22:05:31 +02:00
return a . Run ( ctx , conf . Server . Address , conf . Server . Port , conf . Server . TLSCert , conf . Server . TLSKey )
2022-11-21 18:14:06 +01:00
}
2020-10-25 03:43:59 +01:00
}
2022-11-21 18:14:06 +01:00
func schedulePeriodicScan ( ctx context . Context ) func ( ) error {
2020-10-25 03:43:59 +01:00
return func ( ) error {
2022-11-21 18:14:06 +01:00
schedule := conf . Server . ScanSchedule
if schedule == "" {
log . Warn ( "Periodic scan is DISABLED" )
return nil
2021-04-29 19:10:10 +02:00
}
2022-11-21 18:14:06 +01:00
scanner := GetScanner ( )
schedulerInstance := scheduler . GetInstance ( )
2021-05-06 23:56:10 +02:00
2022-11-21 18:14:06 +01:00
log . Info ( "Scheduling periodic scan" , "schedule" , schedule )
err := schedulerInstance . Add ( schedule , func ( ) {
_ = scanner . RescanAll ( ctx , false )
} )
if err != nil {
log . Error ( "Error scheduling periodic scan" , err )
}
2021-05-09 01:19:31 +02:00
2022-11-21 18:14:06 +01:00
time . Sleep ( 2 * time . Second ) // Wait 2 seconds before the initial scan
log . Debug ( "Executing initial scan" )
if err := scanner . RescanAll ( ctx , false ) ; err != nil {
log . Error ( "Error executing initial scan" , err )
}
log . Debug ( "Finished initial scan" )
return nil
2021-05-09 01:19:31 +02:00
}
2021-05-06 23:56:10 +02:00
}
2022-11-21 18:14:06 +01:00
func startScheduler ( ctx context . Context ) func ( ) error {
log . Info ( ctx , "Starting scheduler" )
2021-06-22 00:41:11 +02:00
schedulerInstance := scheduler . GetInstance ( )
2021-04-29 19:10:10 +02:00
return func ( ) error {
2022-11-21 18:14:06 +01:00
schedulerInstance . Run ( ctx )
return nil
}
2020-07-02 23:21:25 +02:00
}
Jukebox mode (#2289)
* Adding cache directory to ignore-list
* Adding jukebox-related config options
* Adding DevEnableJukebox config option pls. dummy server
* Adding types and routers
* Now without panic
* First draft on parsing the action
* Some cleanups
* Adding playback server
* Verify audio device configuration
* Adding debug-build target to have full symbol support
* Adding beep sound library pls some example code. Not working yet
* Play a fixed mp3 on any interface access for testing purposes
* Put action code into separate file, adding stringer, more debug output, prepare structs, validation
* Put action parameter parser code where it belongs
* Have a single Action transporting all information
* User fmt.Errorf for error-generation
* Adding wide playback interface
* Use action map for parsing, stringer instead switch stmt.
* Use but only one switch case and direct dispatch, refactoring
* Add error handling and pushing to client
* send decent errormessage, no internal server error
* Adding playback devices slice and load it from config
* Combine config-verification and structure init
* Return user-specific device
* Separate playback server from device
* Use dataStore to retrieve mediafile by id
* WIP: Playlist and start/stop handling. Doing start/stop the hard way as of now
* WIP: set, start and stop work on one single song. More to come
* Dont need to wait for the end
* Merge jukebox_action.go into jukebox.go
* Remove getParameterAsInt64(). Use existing requiredParamInt() instead
* Dont need to call newFailure() explicitly
* Remove int64, use int instead.
* Add and set action now accept multiple ids
* Kickout copy of childFromMediaFile(). It is not needed here.
* Refactoring devices and playbackServer
* Turn (internal) playback.DeviceStatus into subsonic JukeboxStatus when rendering output. Indexes int64 -> int
* Now we have a position and playing status
* Switching gain to float32, xs:float is defined as 32 bit. Fixing nasty copy/pointer bug
* Now with volume control
* Start working the queue
* Remove user from device interface
* Rename function GetDevice -> GetDeviceForUser to make intention clearer
* Have a nice stringer for the queue
* User Prepared boolean for now to allow pause/unpause
* Skipping works, but without offsets
* Make ChildFromMediaFile public to be used in jukebox get() implementation
* Return position in seconds and implement offset-skip in seconds
* Default offset to 0
* Adding a simple setGain implementation
* Prepare for transcoding AAC
* WIP: transcode to WAV to use beeps wav decoder. Not done yet.
* WIP: out of sheer desparation: convert to MP3 (which works) rather than WAV to troubleshoot issue.
* Use FLAC as intermediate format to play Apple AAC
* A bit of cleanup
* Catching the end-of-stream event for further reactions
* Have a trackSwitching goroutine waiting on channel when track ends
* Move decoder code into own file. Restructure code a bit
* Now with going on to play the next song in the playlist
* Adding shuffle feature
* Implementing remove action
* Cleanup code
* Remove templates for ffmpeg mp3 generation. Not needed anymore.
* Adding some documentation
* Check whether offset into track is in range. Fixing potential remove track bug. Documentation
* Make golangci-lint happy: handling return values
* Adding test suite and example dummy for playback package
* Adding some basic queue tests
* Only use Jukebox.Enabled config option
* Adding stream closing handling
* Pass context.Context to all PlaybackDevice methods
* Remove unneeded function
* Correct spelling
* Reduce visibility of ChildFromMediaFile
* Decomplicate action-parsing
* Adding simple tempfile-based AAC->FLAC transcoding. No parallel reading and writing yet.
* Try to optimize pipe-writing, tempfile-handling and reading. Not done yet.
* Do a synchronous copy of the tempfile. Racecondition detected
* More debugging statements and fixing the play/pause bug. More work needed
* Start the trackSwitcher() with each device once. Return JSON position even if its 0. More debug-output
* Moving all track-handling code into own module
* Fix typo. Do not pass ctx around when not applicable
* WIP: More refactoring, debugging output
* Fix nil pointer
* Repairing MP3 playback by pinning indirect dependencies: hajimehoshi/go-mp3 and hajimehoshi/oto
* Do not forget to cleanup after a skip action
* Make resync with master easy
* Adding missing mocks
* Adding missing error-handling found by linter
* Updating github.com/hajimehoshi/oto
* Removing duplicate function
* Move BEEP-related code into own package
* Juggle beep-related code around as preparation for interface access
* More refactoring for interface separation
* Gather CloseDevice() behind Track interface.
* Adding skeleton, draft audio-interface using mpv.io
* Adding majority of interface commands using messages to mpv socket.
* Adding end-of-stream handling
* MPV: start/stop are working
* postition is given in float in mpv
* Unify Close() and CloseDevice(). Using temp filename for controlling socket
* Wait until control-socket shows up. Cleanup socket in Close()
* Use canceable command. Rename to Executor
* Skipping tracks works now
* Now with actually setting the position
* Fix regain
* Add missing error-handling found by linter
* Adding retry mode on time-pos property getter
* Remove unneeded code on queue
* Putting build-tag beep onto beep files
* Remove deprecated call to rand.Seed()
"As of Go 1.20 there is no reason to call Seed with a random value. Programs that call Seed with a known value to get a specific sequence of results should use New(NewSource(seed)) to obtain a local random generator."
* Using int32 to conform to Subsonic API spec
* Fix merge error
* Minor style changes
* Get username from context
---------
Co-authored-by: Deluan <deluan@navidrome.org>
2023-09-10 17:25:22 +02:00
func startPlaybackServer ( ctx context . Context ) func ( ) error {
log . Info ( ctx , "Starting playback server" )
playbackInstance := playback . GetInstance ( )
return func ( ) error {
return playbackInstance . Run ( ctx )
}
}
2020-10-25 03:43:59 +01:00
// TODO: Implement some struct tags to map flags to viper
2020-07-02 22:34:21 +02:00
func init ( ) {
2020-07-03 15:39:28 +02:00
cobra . OnInitialize ( func ( ) {
conf . InitConfig ( cfgFile )
} )
2020-07-02 22:34:21 +02:00
rootCmd . PersistentFlags ( ) . StringVarP ( & cfgFile , "configfile" , "c" , "" , ` config file (default "./navidrome.toml") ` )
2020-07-03 02:08:41 +02:00
rootCmd . PersistentFlags ( ) . BoolVarP ( & noBanner , "nobanner" , "n" , false , ` don't show banner ` )
2020-07-02 22:34:21 +02:00
rootCmd . PersistentFlags ( ) . String ( "musicfolder" , viper . GetString ( "musicfolder" ) , "folder where your music is stored" )
2023-06-02 23:14:11 +02:00
rootCmd . PersistentFlags ( ) . String ( "datafolder" , viper . GetString ( "datafolder" ) , "folder to store application data (DB), needs write access" )
rootCmd . PersistentFlags ( ) . String ( "cachefolder" , viper . GetString ( "cachefolder" ) , "folder to store cache data (transcoding, images...), needs write access" )
2020-07-02 22:34:21 +02:00
rootCmd . PersistentFlags ( ) . StringP ( "loglevel" , "l" , viper . GetString ( "loglevel" ) , "log level, possible values: error, info, debug, trace" )
2020-07-03 00:17:31 +02:00
_ = viper . BindPFlag ( "musicfolder" , rootCmd . PersistentFlags ( ) . Lookup ( "musicfolder" ) )
_ = viper . BindPFlag ( "datafolder" , rootCmd . PersistentFlags ( ) . Lookup ( "datafolder" ) )
2023-06-02 23:14:11 +02:00
_ = viper . BindPFlag ( "cachefolder" , rootCmd . PersistentFlags ( ) . Lookup ( "cachefolder" ) )
2020-07-03 00:17:31 +02:00
_ = viper . BindPFlag ( "loglevel" , rootCmd . PersistentFlags ( ) . Lookup ( "loglevel" ) )
2020-07-02 22:34:21 +02:00
2023-03-17 21:07:01 +01:00
rootCmd . Flags ( ) . StringP ( "address" , "a" , viper . GetString ( "address" ) , "IP address to bind to" )
rootCmd . Flags ( ) . IntP ( "port" , "p" , viper . GetInt ( "port" ) , "HTTP port Navidrome will listen to" )
rootCmd . Flags ( ) . String ( "baseurl" , viper . GetString ( "baseurl" ) , "base URL to configure Navidrome behind a proxy (ex: /music or http://my.server.com)" )
rootCmd . Flags ( ) . String ( "tlscert" , viper . GetString ( "tlscert" ) , "optional path to a TLS cert file (enables HTTPS listening)" )
2024-01-20 20:50:30 +01:00
rootCmd . Flags ( ) . String ( "unixsocketperm" , viper . GetString ( "unixsocketperm" ) , "optional file permission for the unix socket" )
2023-03-17 21:07:01 +01:00
rootCmd . Flags ( ) . String ( "tlskey" , viper . GetString ( "tlskey" ) , "optional path to a TLS key file (enables HTTPS listening)" )
2020-07-02 23:21:25 +02:00
rootCmd . Flags ( ) . Duration ( "sessiontimeout" , viper . GetDuration ( "sessiontimeout" ) , "how long Navidrome will wait before closing web ui idle sessions" )
rootCmd . Flags ( ) . Duration ( "scaninterval" , viper . GetDuration ( "scaninterval" ) , "how frequently to scan for changes in your music library" )
2020-07-02 22:34:21 +02:00
rootCmd . Flags ( ) . String ( "uiloginbackgroundurl" , viper . GetString ( "uiloginbackgroundurl" ) , "URL to a backaground image used in the Login page" )
rootCmd . Flags ( ) . Bool ( "enabletranscodingconfig" , viper . GetBool ( "enabletranscodingconfig" ) , "enables transcoding configuration in the UI" )
rootCmd . Flags ( ) . String ( "transcodingcachesize" , viper . GetString ( "transcodingcachesize" ) , "size of transcoding cache" )
rootCmd . Flags ( ) . String ( "imagecachesize" , viper . GetString ( "imagecachesize" ) , "size of image (art work) cache. set to 0 to disable cache" )
2024-04-27 20:09:27 +02:00
rootCmd . Flags ( ) . String ( "albumplaycountmode" , viper . GetString ( "albumplaycountmode" ) , "how to compute playcount for albums. absolute (default) or normalized" )
2020-08-03 05:17:13 +02:00
rootCmd . Flags ( ) . Bool ( "autoimportplaylists" , viper . GetBool ( "autoimportplaylists" ) , "enable/disable .m3u playlist auto-import`" )
2020-07-02 22:34:21 +02:00
2022-10-03 01:59:53 +02:00
rootCmd . Flags ( ) . Bool ( "prometheus.enabled" , viper . GetBool ( "prometheus.enabled" ) , "enable/disable prometheus metrics endpoint`" )
rootCmd . Flags ( ) . String ( "prometheus.metricspath" , viper . GetString ( "prometheus.metricspath" ) , "http endpoint for prometheus metrics" )
2020-07-09 02:54:56 +02:00
_ = viper . BindPFlag ( "address" , rootCmd . Flags ( ) . Lookup ( "address" ) )
2020-07-03 00:17:31 +02:00
_ = viper . BindPFlag ( "port" , rootCmd . Flags ( ) . Lookup ( "port" ) )
2023-03-17 21:07:01 +01:00
_ = viper . BindPFlag ( "tlscert" , rootCmd . Flags ( ) . Lookup ( "tlscert" ) )
2024-01-20 20:50:30 +01:00
_ = viper . BindPFlag ( "unixsocketperm" , rootCmd . Flags ( ) . Lookup ( "unixsocketperm" ) )
2023-03-17 21:07:01 +01:00
_ = viper . BindPFlag ( "tlskey" , rootCmd . Flags ( ) . Lookup ( "tlskey" ) )
_ = viper . BindPFlag ( "baseurl" , rootCmd . Flags ( ) . Lookup ( "baseurl" ) )
2020-07-03 00:17:31 +02:00
_ = viper . BindPFlag ( "sessiontimeout" , rootCmd . Flags ( ) . Lookup ( "sessiontimeout" ) )
_ = viper . BindPFlag ( "scaninterval" , rootCmd . Flags ( ) . Lookup ( "scaninterval" ) )
_ = viper . BindPFlag ( "uiloginbackgroundurl" , rootCmd . Flags ( ) . Lookup ( "uiloginbackgroundurl" ) )
2022-10-03 01:59:53 +02:00
_ = viper . BindPFlag ( "prometheus.enabled" , rootCmd . Flags ( ) . Lookup ( "prometheus.enabled" ) )
_ = viper . BindPFlag ( "prometheus.metricspath" , rootCmd . Flags ( ) . Lookup ( "prometheus.metricspath" ) )
2020-07-03 00:17:31 +02:00
_ = viper . BindPFlag ( "enabletranscodingconfig" , rootCmd . Flags ( ) . Lookup ( "enabletranscodingconfig" ) )
_ = viper . BindPFlag ( "transcodingcachesize" , rootCmd . Flags ( ) . Lookup ( "transcodingcachesize" ) )
_ = viper . BindPFlag ( "imagecachesize" , rootCmd . Flags ( ) . Lookup ( "imagecachesize" ) )
2024-04-27 20:09:27 +02:00
_ = viper . BindPFlag ( "albumplaycountmode" , rootCmd . Flags ( ) . Lookup ( "albumplaycountmode" ) )
2020-07-02 22:34:21 +02:00
}