mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-01 07:21:17 +00:00
url.Parse puts the volume of file://C:/Music in Host, not Path, so localOSRoot dropped it and returned /Music — os.Open/os.Stat then failed and folder/embedded art on Windows looped as dangling. Rejoin the host volume, matching core/storage/local's newLocalStorage.
65 lines
1.8 KiB
Go
65 lines
1.8 KiB
Go
package artwork
|
|
|
|
import (
|
|
"context"
|
|
"net/url"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/navidrome/navidrome/core/storage"
|
|
"github.com/navidrome/navidrome/model"
|
|
)
|
|
|
|
// libraryView bundles the MusicFS for a library with its absolute root path,
|
|
// so readers can open library-relative paths through FS and compose absolute
|
|
// paths (for ffmpeg, which is path-based) via Abs.
|
|
type libraryView struct {
|
|
FS storage.MusicFS
|
|
absRoot string
|
|
}
|
|
|
|
// Abs returns the absolute path for a library-relative path. Returns "" for an
|
|
// empty rel so callers (fromFFmpegTag) can treat it as "no path available".
|
|
func (v libraryView) Abs(rel string) string {
|
|
if rel == "" {
|
|
return ""
|
|
}
|
|
return filepath.Join(v.absRoot, rel)
|
|
}
|
|
|
|
// loadLibraryView resolves the MusicFS and absolute root path in a single
|
|
// library lookup.
|
|
func loadLibraryView(ctx context.Context, ds model.DataStore, libID int) (libraryView, error) {
|
|
lib, err := ds.Library(ctx).Get(libID)
|
|
if err != nil {
|
|
return libraryView{}, err
|
|
}
|
|
s, err := storage.For(lib.Path)
|
|
if err != nil {
|
|
return libraryView{}, err
|
|
}
|
|
fs, err := s.FS()
|
|
if err != nil {
|
|
return libraryView{}, err
|
|
}
|
|
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
|
|
}
|
|
// Windows drive URLs (file://C:/Music) put the volume in Host; rejoin it, matching
|
|
// core/storage/local's newLocalStorage so os.Open/os.Stat get a valid path.
|
|
if filepath.VolumeName(u.Host) != "" {
|
|
return filepath.Join(u.Host, u.Path)
|
|
}
|
|
return u.Path
|
|
}
|