From 61d4ca16debdb1b654ba32cb0c0307088d133ada Mon Sep 17 00:00:00 2001 From: Geert Rademakes Date: Fri, 8 Aug 2025 14:25:50 +0200 Subject: [PATCH] feat(playlists): track custom order in separate 'order' array; reading API honors 'order' while preserving 'tracks' --- packages/backend/src/models/Playlist.ts | 2 ++ packages/backend/src/routes/playlists.ts | 10 +++------- packages/backend/src/routes/songs.ts | 10 ++++++++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/backend/src/models/Playlist.ts b/packages/backend/src/models/Playlist.ts index d9661d7..b88f11b 100644 --- a/packages/backend/src/models/Playlist.ts +++ b/packages/backend/src/models/Playlist.ts @@ -9,6 +9,8 @@ const playlistSchema = new mongoose.Schema({ required: true }, tracks: [String], + // Optional custom order of track IDs (display-only, not exported) + order: [String], children: [{ type: mongoose.Schema.Types.Mixed }] diff --git a/packages/backend/src/routes/playlists.ts b/packages/backend/src/routes/playlists.ts index 5450c1a..bb454d5 100644 --- a/packages/backend/src/routes/playlists.ts +++ b/packages/backend/src/routes/playlists.ts @@ -80,7 +80,7 @@ router.post('/batch', async (req, res) => { } }); -// Reorder tracks inside a playlist (by name) +// Reorder tracks inside a playlist (by name). Stores order separately in `order` to avoid interfering with original `tracks`. router.post('/reorder', async (req: Request, res: Response) => { try { const { playlistName, orderedIds } = req.body as { playlistName: string; orderedIds: string[] }; @@ -94,13 +94,9 @@ router.post('/reorder', async (req: Request, res: Response) => { const reorderNode = (node: any): any => { if (!node) return node; if (node.type === 'playlist' && node.name === playlistName) { - // Ensure unique order and only include known IDs + // Store order separately; do not mutate tracks const unique = Array.from(new Set(orderedIds)); - // If tracks exist, keep only ids present in unique, and append any tracks not included to preserve membership - const current: string[] = Array.isArray(node.tracks) ? node.tracks : []; - const orderedKnown = unique.filter(id => current.includes(id)); - const missing = current.filter(id => !unique.includes(id)); - node.tracks = [...orderedKnown, ...missing]; + node.order = unique; updated = true; return node; } diff --git a/packages/backend/src/routes/songs.ts b/packages/backend/src/routes/songs.ts index 88f7100..6b5b10a 100644 --- a/packages/backend/src/routes/songs.ts +++ b/packages/backend/src/routes/songs.ts @@ -110,8 +110,14 @@ router.get('/playlist/*', async (req: Request, res: Response) => { // Get all track IDs from the playlist (including nested playlists) const getAllTrackIds = (node: any): string[] => { - if (node.type === 'playlist' && node.tracks) { - return node.tracks; + if (node.type === 'playlist') { + const base = Array.isArray(node.tracks) ? node.tracks : []; + const order = Array.isArray(node.order) ? node.order : []; + if (order.length === 0) return base; + const setBase = new Set(base); + const orderedKnown = order.filter((id: string) => setBase.has(id)); + const missing = base.filter((id: string) => !order.includes(id)); + return [...orderedKnown, ...missing]; } if (node.type === 'folder' && node.children) { return node.children.flatMap((child: any) => getAllTrackIds(child));