diff --git a/cmd/gonic/gonic.go b/cmd/gonic/gonic.go index e445df4..4de7704 100644 --- a/cmd/gonic/gonic.go +++ b/cmd/gonic/gonic.go @@ -9,6 +9,7 @@ import ( "log" "os" "path" + "path/filepath" "regexp" "strings" "time" @@ -20,6 +21,7 @@ import ( "go.senan.xyz/gonic" "go.senan.xyz/gonic/db" + "go.senan.xyz/gonic/paths" "go.senan.xyz/gonic/server" ) @@ -48,7 +50,7 @@ func main() { confHTTPLog := set.Bool("http-log", true, "http request logging (optional)") confShowVersion := set.Bool("version", false, "show gonic version") - var confMusicPaths musicPaths + var confMusicPaths paths.MusicPaths set.Var(&confMusicPaths, "music-path", "path to music") _ = set.String("config-path", "", "path to config (optional)") @@ -77,8 +79,8 @@ func main() { log.Fatalf("please provide a music directory") } for _, confMusicPath := range confMusicPaths { - if _, err := os.Stat(confMusicPath); os.IsNotExist(err) { - log.Fatalf("music directory %q not found", confMusicPath) + if _, err := os.Stat(confMusicPath.Path); os.IsNotExist(err) { + log.Fatalf("music directory %q not found", confMusicPath.Path) } } if _, err := os.Stat(*confPodcastPath); os.IsNotExist(err) { @@ -109,7 +111,7 @@ func main() { defer dbc.Close() err = dbc.Migrate(db.MigrationContext{ - OriginalMusicPath: confMusicPaths[0], + OriginalMusicPath: confMusicPaths[0].Path, }) if err != nil { log.Panicf("error migrating database: %v\n", err) @@ -120,11 +122,11 @@ func main() { server, err := server.New(server.Options{ DB: dbc, MusicPaths: confMusicPaths, - CachePath: cacheDirAudio, + CachePath: filepath.Clean(cacheDirAudio), CoverCachePath: cacheDirCovers, ProxyPrefix: *confProxyPrefix, GenreSplit: *confGenreSplit, - PodcastPath: *confPodcastPath, + PodcastPath: filepath.Clean(*confPodcastPath), HTTPLog: *confHTTPLog, JukeboxEnabled: *confJukeboxEnabled, }) @@ -158,14 +160,3 @@ func main() { log.Panicf("error in job: %v", err) } } - -type musicPaths []string - -func (m musicPaths) String() string { - return strings.Join(m, ", ") -} - -func (m *musicPaths) Set(value string) error { - *m = append(*m, value) - return nil -} diff --git a/paths/paths.go b/paths/paths.go new file mode 100644 index 0000000..34bc71e --- /dev/null +++ b/paths/paths.go @@ -0,0 +1,61 @@ +package paths + +import ( + "fmt" + "path/filepath" + "strings" +) + +const sep = "->" + +type MusicPaths []MusicPath + +func (mps MusicPaths) String() string { + var strs []string + for _, path := range mps { + strs = append(strs, path.String()) + } + return strings.Join(strs, ", ") +} + +func (mps *MusicPaths) Set(value string) error { + alias, path, ok := strings.Cut(value, sep) + if !ok { + *mps = append(*mps, MusicPath{ + Path: filepath.Clean(strings.TrimSpace(value)), + }) + return nil + } + *mps = append(*mps, MusicPath{ + Alias: strings.TrimSpace(alias), + Path: filepath.Clean(strings.TrimSpace(path)), + }) + return nil +} + +func (mps MusicPaths) Paths() []string { + var paths []string + for _, mp := range mps { + paths = append(paths, mp.Path) + } + return paths +} + +type MusicPath struct { + Alias string + Path string +} + +func (mp MusicPath) String() string { + if mp.Alias == "" { + return mp.Path + } + return fmt.Sprintf("%s %s %s", mp.Alias, sep, mp.Path) +} + +func (mp MusicPath) DisplayAlias() string { + if mp.Alias == "" { + return filepath.Base(mp.Path) + } + return mp.Alias +} diff --git a/server/ctrlsubsonic/ctrl.go b/server/ctrlsubsonic/ctrl.go index 6049735..cce0aea 100644 --- a/server/ctrlsubsonic/ctrl.go +++ b/server/ctrlsubsonic/ctrl.go @@ -10,6 +10,7 @@ import ( "net/http" "go.senan.xyz/gonic/jukebox" + "go.senan.xyz/gonic/paths" "go.senan.xyz/gonic/podcasts" "go.senan.xyz/gonic/scrobble" "go.senan.xyz/gonic/server/ctrlbase" @@ -31,7 +32,7 @@ type Controller struct { CachePath string CoverCachePath string PodcastsPath string - MusicPaths []string + MusicPaths paths.MusicPaths Jukebox *jukebox.Jukebox Scrobblers []scrobble.Scrobbler Podcasts *podcasts.Podcasts diff --git a/server/ctrlsubsonic/ctrl_test.go b/server/ctrlsubsonic/ctrl_test.go index 6305523..2427f5d 100644 --- a/server/ctrlsubsonic/ctrl_test.go +++ b/server/ctrlsubsonic/ctrl_test.go @@ -19,6 +19,7 @@ import ( "go.senan.xyz/gonic/db" "go.senan.xyz/gonic/mockfs" + "go.senan.xyz/gonic/paths" "go.senan.xyz/gonic/server/ctrlbase" "go.senan.xyz/gonic/server/ctrlsubsonic/params" "go.senan.xyz/gonic/transcode" @@ -158,9 +159,9 @@ func makec(t *testing.T, roots []string, audio bool) *Controller { m.ScanAndClean() m.ResetDates() - var absRoots []string + var absRoots paths.MusicPaths for _, root := range roots { - absRoots = append(absRoots, filepath.Join(m.TmpDir(), root)) + absRoots = append(absRoots, paths.MusicPath{Alias: "", Path: filepath.Join(m.TmpDir(), root)}) } base := &ctrlbase.Controller{DB: m.DB()} diff --git a/server/ctrlsubsonic/handlers_common.go b/server/ctrlsubsonic/handlers_common.go index 3a3c419..e23430d 100644 --- a/server/ctrlsubsonic/handlers_common.go +++ b/server/ctrlsubsonic/handlers_common.go @@ -15,6 +15,7 @@ import ( "go.senan.xyz/gonic/db" "go.senan.xyz/gonic/multierr" + "go.senan.xyz/gonic/paths" "go.senan.xyz/gonic/scanner" "go.senan.xyz/gonic/server/ctrlsubsonic/params" "go.senan.xyz/gonic/server/ctrlsubsonic/spec" @@ -29,7 +30,7 @@ func lowerUDecOrHash(in string) string { return string(lower) } -func getMusicFolder(musicPaths []string, p params.Params) string { +func getMusicFolder(musicPaths paths.MusicPaths, p params.Params) string { idx, err := p.GetInt("musicFolderId") if err != nil { return "" @@ -37,7 +38,7 @@ func getMusicFolder(musicPaths []string, p params.Params) string { if idx < 0 || idx > len(musicPaths) { return "" } - return musicPaths[idx] + return musicPaths[idx].Path } func (c *Controller) ServeGetLicence(r *http.Request) *spec.Response { @@ -91,7 +92,7 @@ func (c *Controller) ServeGetMusicFolders(r *http.Request) *spec.Response { sub.MusicFolders = &spec.MusicFolders{} sub.MusicFolders.List = make([]*spec.MusicFolder, len(c.MusicPaths)) for i, path := range c.MusicPaths { - sub.MusicFolders.List[i] = &spec.MusicFolder{ID: i, Name: filepath.Base(path)} + sub.MusicFolders.List[i] = &spec.MusicFolder{ID: i, Name: path.DisplayAlias()} } return sub } diff --git a/server/server.go b/server/server.go index 730739a..c154f25 100644 --- a/server/server.go +++ b/server/server.go @@ -5,7 +5,6 @@ import ( "log" "net/http" "os" - "path/filepath" "time" "github.com/gorilla/mux" @@ -14,6 +13,7 @@ import ( "go.senan.xyz/gonic/db" "go.senan.xyz/gonic/jukebox" + "go.senan.xyz/gonic/paths" "go.senan.xyz/gonic/podcasts" "go.senan.xyz/gonic/scanner" "go.senan.xyz/gonic/scanner/tags" @@ -29,7 +29,7 @@ import ( type Options struct { DB *db.DB - MusicPaths []string + MusicPaths paths.MusicPaths PodcastPath string CachePath string CoverCachePath string @@ -48,15 +48,9 @@ type Server struct { } func New(opts Options) (*Server, error) { - for i, musicPath := range opts.MusicPaths { - opts.MusicPaths[i] = filepath.Clean(musicPath) - } - opts.CachePath = filepath.Clean(opts.CachePath) - opts.PodcastPath = filepath.Clean(opts.PodcastPath) - tagger := &tags.TagReader{} - scanner := scanner.New(opts.MusicPaths, opts.DB, opts.GenreSplit, tagger) + scanner := scanner.New(opts.MusicPaths.Paths(), opts.DB, opts.GenreSplit, tagger) base := &ctrlbase.Controller{ DB: opts.DB, ProxyPrefix: opts.ProxyPrefix,