[API Request] Per-user Library for a user-managed filter over the server's catalog #229
Replies: 3 comments 1 reply
|
Oh and once I have some traction with this and a nice implementation (hopefully in Navidrome) I'd be happy to tackle the Collections spec. I have opinions there too coming from the MusicBrainz side of the world. |
|
As an alternative idea, maybe there could be a system to add user-defined labels/tags to songs, albums, and artists? It wouldn't be awfully much more complex than the original suggestion but would provide much more possibilities for the end-user. |
|
We've actually implemented something similar in Astiga - profile filters: https://asti.ga/docs/library/hiding-storage-with-profiles/ It's not exposed via the Subsonic API as such, but having a profile for Subsonic clients will filter the results that are returned. Currently it's only implemented for filtering by cloud storage backend. The intention is to make the selector (profile) take in more info than just the client type, and the filter being able to have more criteria - genre, bitrate, arbitrary tags etc. So year, promoting the filter itself through the Subsonic API would also be useful for management of the filter. |
Uh oh!
There was an error while loading. Please reload this page.
Type of change
API extension
Proposal description
This is my first foray into Subsonic and the personal media server space. I've been a "files-only" media user for a long time. I'd be happy to implement this in one of the servers whichever is easier for a newcomer and has people who can help guide me through the contribution by answering any questions I may have. I spent more time on this than I'd like to admit, it's my first time writing a proposal/specification so pardon any mistakes I may have made - happy to learn if you can point out what to change.
Also I hope I didn't overdo it in terms of the details. This was mostly just thinking work so no code would be wasted anyway.
The problem
Large personal collections: A user with 100k tracks may only actively listen to 30k of them. The rest are archives, RIPs that haven't been triaged or music kept for completeness. Shuffle and "recently added" show everything with no way to curate except playlists.
Multi-user households: A family sharing a Navidrome instance has kid's music, one person's jazz and another's metal all in one catalog. No way for each person to say "this is mine" without the admin pre-organizing files into separate directories and assigning access. That's static, fragile, and doesn't handle overlapping taste.
Navidrome's multi-library feature solves the admin-managed, folder-based case. Users still can't dynamically curate their own view.
This proposal adds a per-user library: a user-managed set of items (artists, albums, songs) that scopes browsing, search, and playback across existing endpoints. Each user gets one implicit library. It is not named or ordered. It acts as a filter on the catalog, not a content container.
Relationship to #73 (Album Collections) and #75 (Playlist Folders)
This is not a generalization of #73. Different problem.
#73 wants curated, named, ordered lists of albums. That's structurally identical to playlists but with album entries instead of songs. The clean path for #73 is extending playlists to support album-level (and potentially artist-level) entries and it should be a separate, complementary proposal.
As @Tolriq noted in #73 "should this work for artists, not just albums? Should it support cross-media types?" The user library holds artists, albums, and songs in one set with cascading membership.
Why existing features don't work
Favorites/starred
Users could star everything and use
getStarred2as their entry point. Problems:getStarred2is a standalone dump, not a filter across the APIgetAlbumList2,getRandomSongsorsearch3to starred itemsJellyfin made this compromise (
isFavoriteis effectively "in my library") and users can't distinguish favorites from things they've just added.Playlists
A mega-playlist of all library songs. We can do better than Spotify. 😅
getAlbumList2orgetArtiststo a playlistPrior art
Other APIs
isFavoriteon/Itemsas a library filter + admin library access. Closest model, but conflating favorites with library membership is a known pain point.Community discussions
Backward compatibility impact
Fully additive. New endpoints plus one new optional parameter (
inLibrary) on existing browsing endpoints.getOpenSubsonicExtensionswon't listuserLibraryso clients won't send library parameters.inLibraryand will see the full catalog.musicFolderId: unchanged.inLibraryis separate and composable.musicFolderId=2&inLibrary=truemeans "items from music folder 2 that are also in my library".Backward compatibility
API details
New endpoints
getUserLibrary: Metadata about the authenticated user's library.One implicit library per user. No create/delete - it exists when the account exists and is initially empty.
Parameters: none
itemCountartistCountalbumCountsongCountlastModifiedgetUserLibraryEntries: Explicit entries in the user's library with optional type filtering and pagination.typeartist,album,songoffsetcountidtypeartist,album, orsongaddedaddToUserLibrary: Add items to the library. Idempotent - re-adding is a no-op.artistIdalbumIdsongIdAt least one required. Use form POST (#26) for bulk operations.
Returns empty
<subsonic-response>withstatus="ok".removeFromUserLibrary: Remove items from the library. Idempotent - removing an absent item is a no-op.artistIdalbumIdsongIdAt least one required.
Returns empty
<subsonic-response>withstatus="ok".Removing an artist removes the artist-level entry but does not remove individually-added albums or songs by that artist. A user adds { Album Y by Artist X, Artist X } and then removes { Artist X }. The library would still contain { Album Y by Artist X } because it was added separately.
New parameter on existing endpoints
Optional boolean
inLibraryon these endpoints:inLibrary=truegetArtistsgetIndexesgetAlbumListgetAlbumList2getRandomSongsgetSongsByGenregetStarredgetStarred2search2search3getSimilarSongsgetSimilarSongs2getTopSongsComposable with
musicFolderId- both present means intersection.Absent or
false= full catalog, same as today.Cascading membership
Adding an artist to library means all their albums and songs are in the library (including future releases the server ingests).
Adding an album to library means all songs on that album are in the library. The album's artist appears in
getArtistswheninLibrary=true.Adding individual songs means only those songs. Their album/artist appear in library-scoped browsing only if at least one song/album is in the library.
So Artist = "I want everything by this artist", Album = "I want this specific album" and Song = "I want just this track".
Response augmentation
Servers supporting
userLibrarySHOULD addinLibrary(boolean) toChildandAlbumID3responses. Lets clients show library status inline (a "+" icon or similar) without extra calls.Extension registration
{ "name": "userLibrary", "versions": [1] }Security impacts
addToUserLibraryMUST respect existing access controls - can't add items from music folders the user doesn't have access to.Potential issues
Cascading membership is opinionated: "Add artist" means follow, including future releases. Some users may want static snapshots. I chose what most users would expect. The alternative is to make the library only accept tracks which also solves the next point but requires more user effort.
Performance: A library with 50k cascaded songs makes filtered queries expensive. Servers should index library membership.
getUserLibraryEntriesreturns only explicit entries (not cascaded), keeping responses manageable. Clients should use theinLibraryresponse field for inline status instead of fetching the full entry list.Multi-library interaction: User adds an item from Library A, then loses access to Library A. Item should become invisible in library-scoped queries but not deleted. If access is restored it reappears.
POST support for bulk operations: Servers SHOULD support form POST ([API Request] Officialise POST support #26). Initial library population may need multiple batched calls.
Alternative solutions
This used to be my first v0 proposal idea but it didn't compose well and was bad design IMO.
Virtual musicFolderId workaround (existing clients, no changes needed)
A server or proxy can offer partial library support by:
{id: 9999, name: "⭐ My Library"}) intogetMusicFoldersresponses.musicFolderId=9999filter responses to only include items in the user's library.Works for all 10 endpoints that accept
musicFolderId(getArtists, getIndexes, getAlbumList, getAlbumList2, getRandomSongs, getSongsByGenre, getStarred, getStarred2, search2, search3). Does NOT cover getSimilarSongs, getSimilarSongs2, getTopSongs.Works with Symfonium, Ultrasonic, Feishin and likely more as they already pass musicFolderId to browsing calls when a folder is selected.
Limitations:
Bridge solution only. The extension supersedes it.
All reactions