mirror of
https://github.com/navidrome/navidrome.git
synced 2026-11-02 16:37:49 +01:00
A library configured with a file:// path stored absRoot as the raw URI, so Abs produced strings like file:/music/cover.jpg that os.Open/os.Stat reject — folder, upload and embedded art were treated as dangling on every request, looping forever. Normalize a file:// path to its parsed OS path (the same root os.DirFS uses); non-local schemes are left unchanged (out of scope, per the artwork-musicfs TODO).
59 lines
1.6 KiB
Go
59 lines
1.6 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
|
|
}
|
|
return u.Path
|
|
}
|