Skip to content

Add playlistFolders extension for organizing playlists in nested folders - #255

Open
DahliaWitt wants to merge 1 commit into
opensubsonic:mainfrom
DahliaWitt:playlist-folders-extension
Open

Add playlistFolders extension for organizing playlists in nested folders#255
DahliaWitt wants to merge 1 commit into
opensubsonic:mainfrom
DahliaWitt:playlist-folders-extension

Conversation

@DahliaWitt

Copy link
Copy Markdown

Follow-up to #75 (and #14 before it). This adds a playlistFolders extension: nested, ordered playlist folders like iTunes, Spotify, and Rekordbox have.

TL;DR

Adds a per-user, ordered playlist folder hierarchy.

  • New extension page: playlistFolders (v1)
  • New endpoints: getPlaylistFolders, createPlaylistFolder, updatePlaylistFolder, deletePlaylistFolder, movePlaylist
  • New responses: playlistFolder, playlistFolders
  • Adds optional playlistFolderId and playlistFolderSortOrder fields to the playlist response
  • OpenAPI schema and endpoint definitions with formPost variants

Design notes, mostly answering questions/topics raised in #75:

  • Nesting. Arbitrary depth via parentId returned as a flat list. This was the big open question in the discussion. Apple and Spotify both do multi-level folders and Rekordbox users (like me!) rely on deep trees, so one level only would miss the point. A client that only wants one level can flatten deeper folders and every playlist stays reachable.
  • Placement is per-user. A folder placement lives in the requesting user's organization and never modifies the playlist. So you can file shared or public playlists you don't own (readonly too), and two users can file the same playlist differently. Trees are private: referencing another user's folder ID behaves exactly like a nonexistent ID (error 70), so IDs can't be probed. Placements follow playlist visibility, which means a deleted or unshared playlist can't leave behind a ghost folder you're unable to empty.
  • Manual ordering. Sibling folders and playlists share one ordering space of client-assigned integers. This allows one to reproduce a manually ordered iTunes or Rekordbox tree exactly.
  • movePlaylist is its own endpoint because placement is an operation on the (user, playlist) pair, not on the playlist. updatePlaylist is owner-restricted, so a folder parameter there can't express filing someone else's playlist. One endpoint covers moving into a folder, moving to the root, and reordering. Batch moves pair repeated playlistId/sortOrder parameters the same way scrobble pairs id/time.
  • The whole tree comes from two requests, getPlaylistFolders + getPlaylists, and a per-folder endpoint just invites N+1 loops.
  • Deletion is conservative. Only empty folders can be deleted; servers must never implicitly delete or move contents.

Backward compatibility

This is a no-op for existing users and clients. Nothing will break with this addition.

  • No existing endpoint changes behavior. getPlaylists returns the same complete flat list it always has, so a legacy client talking to a folder-supporting server still sees every playlist. Folders are invisible to it.
  • The two new playlist fields follow the standard optional-field rules: only servers advertising the extension return them, and clients that don't know them ignore them.
  • New endpoints gated behind getOpenSubsonicExtensions.

Server/implementer cost

Two small tables (folders and placements) and one LEFT JOIN on getPlaylists, only for servers that advertise the extension. The cycle check is a walk up the parent chain. getPlaylistFolders returns folders only, and even heavy users have tens of folders, so I don't think pagination is needed (if I'm wrong happy to implement it).

Out of scope

Can be added later or as a follow-up upon request.

  • created/changed timestamps on folders
  • folder cover art
  • a folder parameter on createPlaylist. Creating into a folder takes two calls. I'd rather cost clients an extra request than grow a base Subsonic endpoint.

Tags Debate

Tags came up in #75 as the alternative. I think they're a good feature, but a different one. What I need is to bring over folder hierarchies that already exist in iTunes exports, Rekordbox crates, and Koel, with their structure and ordering intact. The hierarchy is the data; a flat tag set can't carry a tree like these other apps have. I want to add support for an existing idiom in popular music software.

I don't think this is a one or the other situation. I see no reason why tags could not still be added later in addition to this.

Implementation/Clients

Koel ships nested playlist folders natively (one level since koel/koel#1499, arbitrary nesting in koel/koel#2612, which I wrote), and Koel implements OpenSubsonic. In #75 it was mentioned that no server had the feature, so there was nothing for clients to build against. Now a server has it and is missing the API surface.

I'll create a PR these endpoints into Koel's Subsonic layer as the reference implementation, and I'm willing to do a Navidrome implementation too (navidrome/navidrome#1858 is the request there).

Feedback

Client authors: feedback wanted, in particular on the flat list + parentId shape and on movePlaylist. This is a feature that I desperately need to fully move over from a proprietary ecosystem. Seeing the discussions around this on several different clients (such as (navidrome/navidrome#1858) demonstrates a clear need and demand for such a feature.

Note

AI Disclaimer: I used LLMs to assist with authoring these changes. All changes were manually reviewed and I am not wasting your time with clanker slop.

Adds a per-user, ordered playlist folder hierarchy as proposed in
discussion opensubsonic#75:

- New extension page: playlistFolders (v1)
- New endpoints: getPlaylistFolders, createPlaylistFolder,
  updatePlaylistFolder, deletePlaylistFolder, movePlaylist
- New responses: playlistFolder, playlistFolders
- Adds optional playlistFolderId and playlistFolderSortOrder fields to
  the playlist response
- OpenAPI schema and endpoint definitions with formPost variants
@netlify

netlify Bot commented Jul 13, 2026

Copy link
Copy Markdown

Deploy Preview for opensubsonic ready!

Name Link
🔨 Latest commit eeb7b9e
🔍 Latest deploy log https://app.netlify.com/projects/opensubsonic/deploys/6a5577641fd9de0008b3c348
😎 Deploy Preview https://deploy-preview-255--opensubsonic.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant