mirror of
https://github.com/navidrome/navidrome.git
synced 2026-02-07 21:41:07 -05:00
Compare commits
4 Commits
transcodin
...
service
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af4b2bb4c9 | ||
|
|
4773adba00 | ||
|
|
7bbf4cbaea | ||
|
|
cff19445ba |
@@ -27,9 +27,10 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var plsCmd = &cobra.Command{
|
var plsCmd = &cobra.Command{
|
||||||
Use: "pls",
|
Use: "playlists",
|
||||||
Short: "Export playlists",
|
Aliases: []string{"pls", "playlist"},
|
||||||
Long: "Export Navidrome playlists to M3U files",
|
Short: "Export playlists",
|
||||||
|
Long: "Export Navidrome playlists to M3U files",
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
runExporter()
|
runExporter()
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ Complete documentation is available at https://www.navidrome.org/docs`,
|
|||||||
preRun()
|
preRun()
|
||||||
},
|
},
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
runNavidrome()
|
runNavidrome(context.Background())
|
||||||
},
|
},
|
||||||
Version: consts.Version,
|
Version: consts.Version,
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ func preRun() {
|
|||||||
conf.Load()
|
conf.Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
func runNavidrome() {
|
func runNavidrome(ctx context.Context) {
|
||||||
db.Init()
|
db.Init()
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := db.Close(); err != nil {
|
if err := db.Close(); err != nil {
|
||||||
@@ -69,7 +69,7 @@ func runNavidrome() {
|
|||||||
log.Info("Navidrome stopped, bye.")
|
log.Info("Navidrome stopped, bye.")
|
||||||
}()
|
}()
|
||||||
|
|
||||||
g, ctx := errgroup.WithContext(context.Background())
|
g, ctx := errgroup.WithContext(ctx)
|
||||||
g.Go(startServer(ctx))
|
g.Go(startServer(ctx))
|
||||||
g.Go(startSignaler(ctx))
|
g.Go(startSignaler(ctx))
|
||||||
g.Go(startScheduler(ctx))
|
g.Go(startScheduler(ctx))
|
||||||
|
|||||||
191
cmd/svc.go
Normal file
191
cmd/svc.go
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/kardianos/service"
|
||||||
|
"github.com/navidrome/navidrome/conf"
|
||||||
|
"github.com/navidrome/navidrome/log"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
svcStatusLabels = map[service.Status]string{
|
||||||
|
service.StatusUnknown: "Unknown",
|
||||||
|
service.StatusStopped: "Stopped",
|
||||||
|
service.StatusRunning: "Running",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
svcCmd.AddCommand(buildInstallCmd())
|
||||||
|
svcCmd.AddCommand(buildUninstallCmd())
|
||||||
|
svcCmd.AddCommand(buildStartCmd())
|
||||||
|
svcCmd.AddCommand(buildStopCmd())
|
||||||
|
svcCmd.AddCommand(buildStatusCmd())
|
||||||
|
rootCmd.AddCommand(svcCmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
var svcCmd = &cobra.Command{
|
||||||
|
Use: "service",
|
||||||
|
Aliases: []string{"svc"},
|
||||||
|
Short: "Manage Navidrome as a service",
|
||||||
|
Long: fmt.Sprintf("Manage Navidrome as a service, using the OS service manager (%s)", service.Platform()),
|
||||||
|
Run: runServiceCmd,
|
||||||
|
}
|
||||||
|
|
||||||
|
type svcControl struct {
|
||||||
|
ctx context.Context
|
||||||
|
cancel context.CancelFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *svcControl) Start(_ service.Service) error {
|
||||||
|
p.ctx, p.cancel = context.WithCancel(context.Background())
|
||||||
|
go p.run()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *svcControl) run() {
|
||||||
|
runNavidrome(p.ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *svcControl) Stop(_ service.Service) error {
|
||||||
|
log.Info("Stopping service")
|
||||||
|
p.cancel()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
svc service.Service
|
||||||
|
svcOnce = sync.Once{}
|
||||||
|
)
|
||||||
|
|
||||||
|
func svcInstance() service.Service {
|
||||||
|
svcOnce.Do(func() {
|
||||||
|
options := make(service.KeyValue)
|
||||||
|
options["Restart"] = "on-success"
|
||||||
|
options["SuccessExitStatus"] = "1 2 8 SIGKILL"
|
||||||
|
options["UserService"] = true
|
||||||
|
options["LogDirectory"] = conf.Server.DataFolder
|
||||||
|
svcConfig := &service.Config{
|
||||||
|
Name: "Navidrome",
|
||||||
|
DisplayName: "Navidrome",
|
||||||
|
Description: "Navidrome is a self-hosted music server and streamer",
|
||||||
|
Dependencies: []string{
|
||||||
|
"Requires=network.target",
|
||||||
|
"After=network-online.target syslog.target"},
|
||||||
|
WorkingDirectory: executablePath(),
|
||||||
|
Option: options,
|
||||||
|
}
|
||||||
|
if conf.Server.ConfigFile != "" {
|
||||||
|
svcConfig.Arguments = []string{"-c", conf.Server.ConfigFile}
|
||||||
|
}
|
||||||
|
prg := &svcControl{}
|
||||||
|
var err error
|
||||||
|
svc, err = service.New(prg, svcConfig)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return svc
|
||||||
|
}
|
||||||
|
|
||||||
|
func runServiceCmd(cmd *cobra.Command, _ []string) {
|
||||||
|
_ = cmd.Help()
|
||||||
|
}
|
||||||
|
|
||||||
|
func executablePath() string {
|
||||||
|
ex, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
return filepath.Dir(ex)
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildInstallCmd() *cobra.Command {
|
||||||
|
runInstallCmd := func(_ *cobra.Command, _ []string) {
|
||||||
|
var err error
|
||||||
|
println("Installing service with:")
|
||||||
|
println(" working directory: " + executablePath())
|
||||||
|
println(" music folder: " + conf.Server.MusicFolder)
|
||||||
|
println(" data folder: " + conf.Server.DataFolder)
|
||||||
|
if cfgFile != "" {
|
||||||
|
conf.Server.ConfigFile, err = filepath.Abs(cfgFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
println(" config file: " + conf.Server.ConfigFile)
|
||||||
|
}
|
||||||
|
err = svcInstance().Install()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
println("Service installed. Use 'navidrome svc start' to start it.")
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cobra.Command{
|
||||||
|
Use: "install",
|
||||||
|
Short: "Install Navidrome service.",
|
||||||
|
Run: runInstallCmd,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildUninstallCmd() *cobra.Command {
|
||||||
|
return &cobra.Command{
|
||||||
|
Use: "uninstall",
|
||||||
|
Short: "Uninstall Navidrome service. Does not delete the music or data folders",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := svcInstance().Uninstall()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
println("Service uninstalled. Music and data folders are still intact.")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildStartCmd() *cobra.Command {
|
||||||
|
return &cobra.Command{
|
||||||
|
Use: "start",
|
||||||
|
Short: "Start Navidrome service",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := svcInstance().Start()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
println("Service started. Use 'navidrome svc status' to check its status.")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildStopCmd() *cobra.Command {
|
||||||
|
return &cobra.Command{
|
||||||
|
Use: "stop",
|
||||||
|
Short: "Stop Navidrome service",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := svcInstance().Stop()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
println("Service stopped. Use 'navidrome svc status' to check its status.")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildStatusCmd() *cobra.Command {
|
||||||
|
return &cobra.Command{
|
||||||
|
Use: "status",
|
||||||
|
Short: "Show Navidrome service status",
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
status, err := svcInstance().Status()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("Navidrome is %s.\n", svcStatusLabels[status])
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
1
go.mod
1
go.mod
@@ -24,6 +24,7 @@ require (
|
|||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
github.com/google/wire v0.5.0
|
github.com/google/wire v0.5.0
|
||||||
github.com/hashicorp/go-multierror v1.1.1
|
github.com/hashicorp/go-multierror v1.1.1
|
||||||
|
github.com/kardianos/service v1.2.2
|
||||||
github.com/kr/pretty v0.3.1
|
github.com/kr/pretty v0.3.1
|
||||||
github.com/lestrrat-go/jwx/v2 v2.0.9
|
github.com/lestrrat-go/jwx/v2 v2.0.9
|
||||||
github.com/matoous/go-nanoid/v2 v2.0.0
|
github.com/matoous/go-nanoid/v2 v2.0.0
|
||||||
|
|||||||
3
go.sum
3
go.sum
@@ -208,6 +208,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
|
|||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||||
|
github.com/kardianos/service v1.2.2 h1:ZvePhAHfvo0A7Mftk/tEzqEZ7Q4lgnR8sGz4xu1YX60=
|
||||||
|
github.com/kardianos/service v1.2.2/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM=
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
@@ -500,6 +502,7 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
|||||||
Reference in New Issue
Block a user