mirror of
https://github.com/navidrome/navidrome.git
synced 2026-11-04 17:28:39 +01:00
57 lines
1.8 KiB
Go
57 lines
1.8 KiB
Go
|
|
package model
|
||
|
|
|
||
|
|
import (
|
||
|
|
"cmp"
|
||
|
|
"path/filepath"
|
||
|
|
"slices"
|
||
|
|
"strings"
|
||
|
|
)
|
||
|
|
|
||
|
|
// LibraryMatcher finds the library that contains an absolute path.
|
||
|
|
type LibraryMatcher struct {
|
||
|
|
libraries Libraries
|
||
|
|
cleanedPaths []string
|
||
|
|
}
|
||
|
|
|
||
|
|
// NewLibraryMatcher sorts the libraries longest path first, so /music-classical is checked before /music.
|
||
|
|
func NewLibraryMatcher(libs Libraries) *LibraryMatcher {
|
||
|
|
libs = slices.Clone(libs)
|
||
|
|
slices.SortFunc(libs, func(i, j Library) int {
|
||
|
|
return cmp.Compare(len(j.Path), len(i.Path))
|
||
|
|
})
|
||
|
|
cleanedPaths := make([]string, len(libs))
|
||
|
|
for i, lib := range libs {
|
||
|
|
cleanedPaths[i] = filepath.Clean(lib.Path)
|
||
|
|
}
|
||
|
|
return &LibraryMatcher{libraries: libs, cleanedPaths: cleanedPaths}
|
||
|
|
}
|
||
|
|
|
||
|
|
// FindLibrary returns the library whose path contains absolutePath.
|
||
|
|
func (lm *LibraryMatcher) FindLibrary(absolutePath string) (Library, bool) {
|
||
|
|
for i, libPath := range lm.cleanedPaths {
|
||
|
|
// A cleaned path only ends with a separator when it is a filesystem root
|
||
|
|
if strings.HasPrefix(absolutePath, libPath) && (len(absolutePath) == len(libPath) ||
|
||
|
|
absolutePath[len(libPath)] == filepath.Separator || strings.HasSuffix(libPath, string(filepath.Separator))) {
|
||
|
|
return lm.libraries[i], true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return Library{}, false
|
||
|
|
}
|
||
|
|
|
||
|
|
// LibraryRelativePath rebases an absolute path onto the library root, as the scanner's io/fs sees it
|
||
|
|
// (forward slashes). Relative paths, and absolute paths outside the library root, are returned unchanged.
|
||
|
|
func LibraryRelativePath(libPath, path string) string {
|
||
|
|
if !filepath.IsAbs(path) {
|
||
|
|
return path
|
||
|
|
}
|
||
|
|
// The library root may be relative (e.g. the default "./music"); it resolves against the same cwd
|
||
|
|
absLib, err := filepath.Abs(libPath)
|
||
|
|
if err != nil {
|
||
|
|
return path
|
||
|
|
}
|
||
|
|
rel, err := filepath.Rel(absLib, path)
|
||
|
|
if err != nil || !filepath.IsLocal(rel) {
|
||
|
|
return path
|
||
|
|
}
|
||
|
|
return filepath.ToSlash(rel)
|
||
|
|
}
|