diff --git a/src/player.js b/src/player.js index cc4e30c..b162300 100644 --- a/src/player.js +++ b/src/player.js @@ -199,6 +199,7 @@ window.NSPlayer = { const trackId = p.trackId || ''; if (trackId && S.queue[idx]?.id && String(trackId) !== String(S.queue[idx].id) && p.reason !== 'queue') return; const indexChanged = (idx !== S.qIdx); + if (indexChanged && p.reason !== 'queue') _histPush(S.qIdx); S.qIdx = idx; const s = S.queue[S.qIdx]; if (!s) return; @@ -314,6 +315,17 @@ function _clearPreload() { if(_preLink) { _preLink.remove(); _preLink = null; } } +// ─── PLAY HISTORY (for prev-in-shuffle) ────────────────────────────────────── +// Records the qIdx before each forward advance so prevSong() can retrace the +// actual play order instead of blindly decrementing (which is wrong in shuffle). +const _playHist = []; +function _histPush(idx) { + if (_playHist[_playHist.length - 1] === idx) return; + _playHist.push(idx); + if (_playHist.length > 50) _playHist.shift(); +} +function _histClear() { _playHist.length = 0; } + // ─── PLAYBACK ───────────────────────────────────────────────────────────── let _playGen = 0; // Incremented on every playQueue() call so in-flight fillRadioQueue callbacks @@ -324,6 +336,7 @@ export function playQueue(songs, startIdx) { _queueGen++; _radioFilling = false; // cancel any in-flight radio fill for the old queue S._origQueue = null; + _histClear(); if (!HAS_BRIDGE && S.shuffle && songs.length > 1) { const start = songs[startIdx]; const rest = songs.filter((_, i) => i !== startIdx).sort(() => Math.random() - 0.5); @@ -647,11 +660,13 @@ export function prevSong() { _nsBridge('seekTo', 0); return; } - if (S.qIdx > 0) { - S.qIdx--; + // Pop history to retrace actual play order (correct in shuffle where next jumps randomly). + // Fall back to S.qIdx-1 when history is empty (e.g. at the very start of a queue). + const prevIdx = _playHist.length > 0 ? _playHist.pop() : (S.qIdx > 0 ? S.qIdx - 1 : -1); + if (prevIdx >= 0 && prevIdx < S.queue.length) { + S.qIdx = prevIdx; const s = S.queue[S.qIdx]; - if (s) { _resetProgressUI(); updatePlayerUI(s, true); onNpSongChange(s.id); renderQueue(); } - // Explicit index so native doesn't have to agree on what "previous" means. + if (s) { _resetProgressUI(); updatePlayerUI(s, true); syncNowPlaying(); onNpSongChange(s.id); renderQueue(); } _nsBridge('seekToIndex', S.qIdx, 0); _nsBridge('play'); } @@ -667,6 +682,7 @@ export function nextSong() { _setSkipping(); const ni = _computeNextIdx(); if (ni >= 0 && ni < S.queue.length) { + _histPush(S.qIdx); S.qIdx = ni; const s = S.queue[S.qIdx]; if (s) { _resetProgressUI(); updatePlayerUI(s, true); onNpSongChange(s.id); renderQueue(); }