feat(library): add library ID filtering for album resources

Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
Deluan 2025-06-26 10:21:41 -04:00
commit d44292cdc7
2 changed files with 64 additions and 1 deletions

View file

@ -6,6 +6,7 @@ import (
"fmt"
"maps"
"slices"
"strconv"
"strings"
"sync"
"time"
@ -123,6 +124,7 @@ var albumFilters = sync.OnceValue(func() map[string]filterFunc {
"missing": booleanFilter,
"genre_id": tagIDFilter,
"role_total_id": allRolesFilter,
"library_id": libraryIdFilter,
}
// Add all album tags as filters
for tag := range model.AlbumLevelTags() {
@ -183,6 +185,42 @@ func allRolesFilter(_ string, value interface{}) Sqlizer {
return Like{"participants": fmt.Sprintf(`%%"%s"%%`, value)}
}
func libraryIdFilter(field string, value interface{}) Sqlizer {
switch v := value.(type) {
case string:
// Handle single library ID as string
if libID, err := strconv.Atoi(v); err == nil {
return Eq{"library_id": libID}
}
return Eq{"library_id": v}
case int:
return Eq{"library_id": v}
case int64:
return Eq{"library_id": v}
case float64:
return Eq{"library_id": int(v)}
case []interface{}:
// Handle multiple library IDs
var ids []interface{}
for _, id := range v {
switch idVal := id.(type) {
case string:
if libID, err := strconv.Atoi(idVal); err == nil {
ids = append(ids, libID)
} else {
ids = append(ids, idVal)
}
case int, int64, float64:
ids = append(ids, idVal)
}
}
if len(ids) > 0 {
return Eq{"library_id": ids}
}
}
return Eq{"library_id": value}
}
func (r *albumRepository) CountAll(options ...model.QueryOptions) (int64, error) {
query := r.newSelect()
query = r.withAnnotation(query, "album.id")

View file

@ -9,6 +9,15 @@ const isAdmin = () => {
return role === 'admin'
}
const getSelectedLibraries = () => {
try {
const state = JSON.parse(localStorage.getItem('state'))
return state?.library?.selectedLibraries || []
} catch (err) {
return []
}
}
const mapResource = (resource, params) => {
switch (resource) {
case 'playlistTrack': {
@ -24,10 +33,26 @@ const mapResource = (resource, params) => {
}
case 'album':
case 'song':
case 'artist': {
case 'artist':
case 'playlist': {
// Content resources that should be filtered by selected libraries
const contentResources = ['album', 'song', 'artist', 'playlist']
// Get selected libraries from localStorage
const selectedLibraries = getSelectedLibraries()
if (params.filter && !isAdmin()) {
params.filter.missing = false
}
// Add library filter for content resources if libraries are selected
if (contentResources.includes(resource) && selectedLibraries.length > 0) {
if (!params.filter) {
params.filter = {}
}
params.filter.library_id = selectedLibraries
}
return [resource, params]
}
default: