From 30fd8a19b8957d321d00211b5f5c88d7eb7850dc Mon Sep 17 00:00:00 2001 From: saopig1 <4x7sw862st@gmail.com> Date: Wed, 6 May 2026 16:32:23 +0800 Subject: [PATCH] fix(queue): restore playedIndices clear in playAt; test HISTORY_LIMIT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Code review of 390d3fa flagged that dropping playedIndices.clear() from playAt is an unnecessary behavior change. The two operations (push history, reset random pool) are not in tension — restoring the clear preserves the original 'explicit pick restarts shuffle' semantic that Random mode users rely on, while still tracking the prev-history stack. Also add a regression test that the 50-entry HISTORY_LIMIT cap works. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/audio/queue.test.ts | 22 ++++++++++++++++++++++ src/audio/queue.ts | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/src/audio/queue.test.ts b/src/audio/queue.test.ts index bb51cd1..2416527 100644 --- a/src/audio/queue.test.ts +++ b/src/audio/queue.test.ts @@ -363,5 +363,27 @@ describe("PlayQueue", () => { queue.prev(); // pops 0, history: [] expect(queue.prev()).toBeNull(); // no fallback target in random mode }); + + it("caps history at HISTORY_LIMIT (50) entries, dropping oldest", () => { + queue.setMode(PlayMode.Random); + // Build a queue large enough to overflow HISTORY_LIMIT + for (let i = 0; i < 60; i++) queue.add(makeSong(`s${i}`)); + // Walk through 60 explicit picks → 59 pushes to history + // (playAt pushes the previous currentIndex; first call has -1 + // which pushHistory rejects). After 60 playAts, history holds + // the last 50 of those 59 entries. + for (let i = 0; i < 60; i++) queue.playAt(i); + + // Walk back through history. The first prev returns whatever the + // 50th-most-recent push was (= index 9, since pushes 0..58 happened + // and the oldest 9 fell off). We can verify by counting prevs that + // succeed before history exhausts and prev returns null in random. + let count = 0; + while (queue.prev() !== null) { + count++; + if (count > 100) break; // safety + } + expect(count).toBe(50); + }); }); }); diff --git a/src/audio/queue.ts b/src/audio/queue.ts index 6e1d0fc..578dee1 100644 --- a/src/audio/queue.ts +++ b/src/audio/queue.ts @@ -86,6 +86,10 @@ export class PlayQueue { playAt(index: number): QueuedSong | null { if (index < 0 || index >= this.songs.length) return null; this.pushHistory(this.currentIndex); + // Reset the Random-mode "unplayed" pool — explicit picks restart + // shuffle from this point. History tracking is independent and + // unaffected by this clear. + this.playedIndices.clear(); this.currentIndex = index; this.playedIndices.add(index); return this.songs[index];