diff --git a/core/artwork/library_fs.go b/core/artwork/library_fs.go index ff557294e..fab4b1f8c 100644 --- a/core/artwork/library_fs.go +++ b/core/artwork/library_fs.go @@ -2,7 +2,9 @@ package artwork import ( "context" + "net/url" "path/filepath" + "strings" "github.com/navidrome/navidrome/core/storage" "github.com/navidrome/navidrome/model" @@ -40,5 +42,18 @@ func loadLibraryView(ctx context.Context, ds model.DataStore, libID int) (librar if err != nil { return libraryView{}, err } - return libraryView{FS: fs, absRoot: lib.Path}, nil + return libraryView{FS: fs, absRoot: localOSRoot(lib.Path)}, nil +} + +// localOSRoot maps a library path to its on-disk root so Abs() yields paths os.Open/os.Stat accept: +// a file:// URL becomes its parsed OS path (bare paths already are; non-local schemes stay unchanged). +func localOSRoot(libPath string) string { + if !strings.Contains(libPath, "://") { + return libPath + } + u, err := url.Parse(libPath) + if err != nil || u.Scheme != storage.LocalSchemaID { + return libPath + } + return u.Path } diff --git a/core/artwork/library_fs_test.go b/core/artwork/library_fs_test.go index acf08fda3..22498e7a1 100644 --- a/core/artwork/library_fs_test.go +++ b/core/artwork/library_fs_test.go @@ -32,6 +32,13 @@ var _ = Describe("loadLibraryView", Ordered, func() { Expect(lib.absRoot).To(Equal("fake:///music")) }) + It("normalizes a library path to an OS root that Abs can join for os.Open/os.Stat", func() { + // file:// URLs become their parsed OS path; bare paths and non-local schemes are unchanged. + Expect(localOSRoot("file:///music/library")).To(Equal("/music/library")) + Expect(localOSRoot("/music/library")).To(Equal("/music/library")) + Expect(localOSRoot("fake:///music")).To(Equal("fake:///music")) + }) + It("returns an error when the library does not exist", func() { _, err := loadLibraryView(ctx, ds, 999) Expect(err).To(HaveOccurred())