From 0fab2849e5c2d4bd847e091245b6f3599a0359a0 Mon Sep 17 00:00:00 2001 From: Frank Stellmacher <171614930+Psychotoxical@users.noreply.github.com> Date: Tue, 5 May 2026 22:33:15 +0200 Subject: [PATCH] feat(queue): preserve Play Next order toggle (#464) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(queue): add preservePlayNextOrder setting + playNext store action - New Track.playNextAdded flag (analogous to autoAdded / radioAdded). Stale flags behind queueIndex are harmless — only forward streak scan. - New playerStore action playNext(tracks): tags incoming tracks and delegates to enqueueAt for unified undo + server sync. - New authStore boolean preservePlayNextOrder (default false). When on, playNext appends behind the existing Play-Next streak (Spotify-style) instead of inserting directly after the current track. * refactor(context-menu): centralise Play Next; add Settings toggle + i18n - Replace 3 inline splice/enqueueAt call sites in ContextMenu with the new playNext action. Side-benefit: the single-song path now goes through enqueueAt and gets undo + queue sync (previously missing). - Settings → Audio → Playback: new toggle below Gapless. - 8 locales: preservePlayNextOrder + preservePlayNextOrderDesc. * docs(contributors): credit + changelog entry for #464 --- CHANGELOG.md | 7 +++++++ src/components/ContextMenu.tsx | 32 +++++--------------------------- src/locales/de.ts | 2 ++ src/locales/en.ts | 2 ++ src/locales/es.ts | 2 ++ src/locales/fr.ts | 2 ++ src/locales/nb.ts | 2 ++ src/locales/nl.ts | 2 ++ src/locales/ru.ts | 2 ++ src/locales/zh.ts | 2 ++ src/pages/Settings.tsx | 17 +++++++++++++++++ src/store/authStore.ts | 4 ++++ src/store/playerStore.ts | 27 +++++++++++++++++++++++++++ 13 files changed, 76 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 986a03ac..320b73d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * New cover-source picker under Discord Rich Presence settings: **None** (app icon only), **Server**, or **Apple Music**. Mutually exclusive. * Fresh installs default to **Server** for opt-in-friendly cover art with no third-party data leak. Existing users keep their previous Apple-covers preference via migration. +### Queue — preserve "Play Next" insertion order (toggle) + +**By [@Psychotoxical](https://github.com/Psychotoxical), suggested by [@Sayykii](https://github.com/Sayykii), PR [#464](https://github.com/Psychotoxical/psysonic/pull/464)** + +* New optional toggle in Settings → Audio → Playback ("Preserve Play Next order"). When on, multiple "Play Next" insertions **queue up behind each other** instead of the latest one bumping earlier picks down. Default off — existing behaviour unchanged. +* Side-benefit: single-song "Play Next" now goes through the unified `enqueueAt` path and gets undo + server-sync support that the album path already had. + ## Changed ### Dependencies — npm / Cargo refresh and rodio 0.22 diff --git a/src/components/ContextMenu.tsx b/src/components/ContextMenu.tsx index 32bb6d3d..a5729575 100644 --- a/src/components/ContextMenu.tsx +++ b/src/components/ContextMenu.tsx @@ -1019,12 +1019,13 @@ function MultiPlaylistToPlaylistSubmenu({ playlists, onDone, triggerId }: { play export default function ContextMenu() { const { t } = useTranslation(); const orbitRole = useOrbitStore(s => s.role); - const { contextMenu, closeContextMenu, playTrack, enqueue, queue, currentTrack, removeTrack, lastfmLovedCache, setLastfmLovedForSong, starredOverrides, setStarredOverride, openSongInfo, userRatingOverrides, setUserRatingOverride } = usePlayerStore( + const { contextMenu, closeContextMenu, playTrack, enqueue, playNext, queue, currentTrack, removeTrack, lastfmLovedCache, setLastfmLovedForSong, starredOverrides, setStarredOverride, openSongInfo, userRatingOverrides, setUserRatingOverride } = usePlayerStore( useShallow(s => ({ contextMenu: s.contextMenu, closeContextMenu: s.closeContextMenu, playTrack: s.playTrack, enqueue: s.enqueue, + playNext: s.playNext, queue: s.queue, currentTrack: s.currentTrack, removeTrack: s.removeTrack, @@ -1528,16 +1529,7 @@ export default function ContextMenu() {