[PR #5151] [CLOSED] Support series in playlists and collections #4447

Closed
opened 2026-04-25 00:19:46 +02:00 by adam · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/advplyr/audiobookshelf/pull/5151
Author: @pdevito3
Created: 3/25/2026
Status: Closed

Base: masterHead: feature/series-in-playlists-and-collections


📝 Commits (1)

  • 84e6006 Support series in playlists and collections

📊 Changes

11 files changed (+1748 additions, -102 deletions)

View changed files

📝 server/Database.js (+37 -1)
📝 server/controllers/CollectionController.js (+166 -42)
📝 server/controllers/PlaylistController.js (+156 -37)
server/migrations/v2.34.0-add-series-to-playlists-collections.js (+107 -0)
📝 server/models/Collection.js (+50 -3)
server/models/CollectionSeriesItem.js (+54 -0)
📝 server/models/Playlist.js (+135 -15)
📝 server/models/PlaylistMediaItem.js (+16 -2)
📝 server/routers/ApiRouter.js (+11 -2)
test/server/controllers/CollectionController.seriesEntries.test.js (+431 -0)
test/server/controllers/PlaylistController.seriesEntries.test.js (+585 -0)

📄 Description

Brief summary

Adds support for including series as first-class entries in playlists and collections, alongside existing book/episode items.

Note

This only includes backend functionality as i know you guys are working on a new UI. I'd be happy to contribute an enhance to support this in the ui when it's ready in a subsequent PR! In the meantime if there are any questions on this or changes you'd like to make just let me know!

Which issue is fixed?

N/A new feature

In-depth Description

Previously, collections could only contain books and playlists could only contain books or podcast episodes. This PR allows both to reference entire series as entries.

Data model:

  • New CollectionSeriesItem model and collectionSeriesItems join table (with migration v2.34.0) for series-in-collections, using a dedicated FK to series with ON DELETE CASCADE.
  • For playlists, the existing polymorphic PlaylistMediaItem table is extended with a new mediaItemType: 'series' variant. Since the polymorphic pattern has no FK constraint, series deletion is handled explicitly via Playlist.removeSeriesFromPlaylists().

API changes:

  • Create and batch-add endpoints for both playlists and collections now accept a seriesIds array.
  • Collections no longer require at least one book — series-only collections are valid.
  • Series entries are rejected for podcast playlists.
  • New removal endpoints: DELETE /api/playlists/:id/series/:seriesId and DELETE /api/collections/:id/series/:seriesId, both with order re-compaction.
  • API responses include a new entries array with { type, order, ... } objects providing a unified, ordered view of all entry types. The existing books (collections) and items (playlists) arrays are preserved for backward compatibility and contain only book/episode entries.

Other:

  • Database cleanup handles orphaned series-type records in both tables.
  • Collections with series entries are no longer hidden when all books are filtered out by user permissions.

How have you tested this?

  • Unit tests for CollectionController series entries (create, addBatch, removeSeries including idempotency and order compaction)
  • Unit tests for PlaylistController series entries (create, addBatch, removeSeries, and series deletion cascade)
  • All tests use in-memory SQLite with full model initialization

Screenshots

Screenshot 2026-03-24 at 10 37 36 PM Screenshot 2026-03-24 at 10 38 02 PM Screenshot 2026-03-24 at 10 38 14 PM

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/advplyr/audiobookshelf/pull/5151 **Author:** [@pdevito3](https://github.com/pdevito3) **Created:** 3/25/2026 **Status:** ❌ Closed **Base:** `master` ← **Head:** `feature/series-in-playlists-and-collections` --- ### 📝 Commits (1) - [`84e6006`](https://github.com/advplyr/audiobookshelf/commit/84e60067083a3e8dc9c3fb8fb3ce7aa6cb800663) Support series in playlists and collections ### 📊 Changes **11 files changed** (+1748 additions, -102 deletions) <details> <summary>View changed files</summary> 📝 `server/Database.js` (+37 -1) 📝 `server/controllers/CollectionController.js` (+166 -42) 📝 `server/controllers/PlaylistController.js` (+156 -37) ➕ `server/migrations/v2.34.0-add-series-to-playlists-collections.js` (+107 -0) 📝 `server/models/Collection.js` (+50 -3) ➕ `server/models/CollectionSeriesItem.js` (+54 -0) 📝 `server/models/Playlist.js` (+135 -15) 📝 `server/models/PlaylistMediaItem.js` (+16 -2) 📝 `server/routers/ApiRouter.js` (+11 -2) ➕ `test/server/controllers/CollectionController.seriesEntries.test.js` (+431 -0) ➕ `test/server/controllers/PlaylistController.seriesEntries.test.js` (+585 -0) </details> ### 📄 Description ## Brief summary Adds support for including series as first-class entries in playlists and collections, alongside existing book/episode items. > [!NOTE] > This only includes backend functionality as i know you guys are working on a new UI. I'd be happy to contribute an enhance to support this in the ui when it's ready in a subsequent PR! In the meantime if there are any questions on this or changes you'd like to make just let me know! ## Which issue is fixed? N/A new feature ## In-depth Description Previously, collections could only contain books and playlists could only contain books or podcast episodes. This PR allows both to reference entire series as entries. **Data model:** - New `CollectionSeriesItem` model and `collectionSeriesItems` join table (with migration `v2.34.0`) for series-in-collections, using a dedicated FK to `series` with `ON DELETE CASCADE`. - For playlists, the existing polymorphic `PlaylistMediaItem` table is extended with a new `mediaItemType: 'series'` variant. Since the polymorphic pattern has no FK constraint, series deletion is handled explicitly via `Playlist.removeSeriesFromPlaylists()`. **API changes:** - Create and batch-add endpoints for both playlists and collections now accept a `seriesIds` array. - Collections no longer require at least one book — series-only collections are valid. - Series entries are rejected for podcast playlists. - New removal endpoints: `DELETE /api/playlists/:id/series/:seriesId` and `DELETE /api/collections/:id/series/:seriesId`, both with order re-compaction. - API responses include a new `entries` array with `{ type, order, ... }` objects providing a unified, ordered view of all entry types. The existing `books` (collections) and `items` (playlists) arrays are preserved for backward compatibility and contain only book/episode entries. **Other:** - Database cleanup handles orphaned series-type records in both tables. - Collections with series entries are no longer hidden when all books are filtered out by user permissions. ## How have you tested this? - Unit tests for `CollectionController` series entries (create, addBatch, removeSeries including idempotency and order compaction) - Unit tests for `PlaylistController` series entries (create, addBatch, removeSeries, and series deletion cascade) - All tests use in-memory SQLite with full model initialization ## Screenshots <img width="686" height="849" alt="Screenshot 2026-03-24 at 10 37 36 PM" src="https://github.com/user-attachments/assets/d9ba57cc-8648-47f3-8f0b-19aee867a42c" /> <img width="652" height="498" alt="Screenshot 2026-03-24 at 10 38 02 PM" src="https://github.com/user-attachments/assets/61e9da9d-60e2-4c46-a441-b0b97af0cb8b" /> <img width="661" height="573" alt="Screenshot 2026-03-24 at 10 38 14 PM" src="https://github.com/user-attachments/assets/e5e4f388-63af-4686-8b71-b1458f139c09" /> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
adam added the pull-request label 2026-04-25 00:19:46 +02:00
adam closed this issue 2026-04-25 00:19:47 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/audiobookshelf#4447