package plugins
import (
"context"
"fmt"
"github.com/navidrome/navidrome/model"
"github.com/navidrome/navidrome/plugins/host"
)
type libraryServiceImpl struct {
ds model.DataStore
hasFilesystemPerm bool
allowedLibraryIDs []int
allLibraries bool
libraryIDMap map[int]struct{}
}
func newLibraryService(ds model.DataStore, perm *LibraryPermission, allowedLibraryIDs []int, allLibraries bool) host.LibraryService {
hasFS := perm != nil && perm.Filesystem
libraryIDMap := make(map[int]struct{})
for _, id := range allowedLibraryIDs {
libraryIDMap[id] = struct{}{}
}
return &libraryServiceImpl{
ds: ds,
hasFilesystemPerm: hasFS,
allowedLibraryIDs: allowedLibraryIDs,
allLibraries: allLibraries,
libraryIDMap: libraryIDMap,
}
}
func (s *libraryServiceImpl) GetLibrary(ctx context.Context, id int32) (*host.Library, error) {
if !s.isLibraryAccessible(int(id)) {
return nil, fmt.Errorf("library not accessible: library ID %d is not in the allowed list", id)
}
lib, err := s.ds.Library(ctx).Get(int(id))
if err != nil {
return nil, fmt.Errorf("library not found: %w", err)
}
return s.convertLibrary(lib), nil
}
func (s *libraryServiceImpl) isLibraryAccessible(id int) bool {
if s.allLibraries {
return true
}
_, ok := s.libraryIDMap[id]
return ok
}
func (s *libraryServiceImpl) GetAllLibraries(ctx context.Context) ([]host.Library, error) {
libs, err := s.ds.Library(ctx).GetAll()
if err != nil {
return nil, fmt.Errorf("failed to get libraries: %w", err)
}
var result []host.Library
for _, lib := range libs {
if s.isLibraryAccessible(lib.ID) {
result = append(result, *s.convertLibrary(&lib))
}
}
return result, nil
}
func (s *libraryServiceImpl) convertLibrary(lib *model.Library) *host.Library {
hostLib := &host.Library{
ID: int32(lib.ID),
Name: lib.Name,
LastScanAt: lib.LastScanAt.Unix(),
TotalSongs: int32(lib.TotalSongs),
TotalAlbums: int32(lib.TotalAlbums),
TotalArtists: int32(lib.TotalArtists),
TotalSize: lib.TotalSize,
TotalDuration: lib.TotalDuration,
}
if s.hasFilesystemPerm {
hostLib.Path = lib.Path
hostLib.MountPoint = toPluginMountPoint(int32(lib.ID))
}
return hostLib
}
func toPluginMountPoint(libID int32) string {
return fmt.Sprintf("/libraries/%d", libID)
}
var _ host.LibraryService = (*libraryServiceImpl)(nil)