feat(player): playNext for M7 #372 track-actions menu

Inserts at _queue[_index + 1] so the next-up slot is overwritten with
the chosen track. Empty-queue seeding mirrors enqueueTrack's behavior.
Clears _radioSeedId since user-driven enqueue invalidates the M4c
auto-refresh trigger.
This commit is contained in:
2026-05-02 22:45:13 -04:00
parent 905b5f0da7
commit f43ea6af5b
2 changed files with 33 additions and 1 deletions
+16
View File
@@ -211,6 +211,22 @@ export function enqueueTrack(t: TrackRef): void {
if (_state === 'idle') _index = 0;
}
/**
* M7 #372: insert a track immediately after the currently-playing one
* so it plays next. If the queue is empty, behaves like enqueueTrack
* and starts the queue with this track at index 0.
*/
export function playNext(t: TrackRef): void {
_radioSeedId = null; // M4c: any user-driven enqueue clears the radio refresh state
if (_queue.length === 0) {
_queue = [t];
_index = 0;
return;
}
const next = _index + 1;
_queue = [..._queue.slice(0, next), t, ..._queue.slice(next)];
}
export function enqueueTracks(ts: TrackRef[]): void {
_radioSeedId = null; // M4c
if (ts.length === 0) return;
+17 -1
View File
@@ -280,7 +280,7 @@ describe('player store — shuffle + repeat + audio reports', () => {
});
});
import { enqueueTrack, enqueueTracks, playRadio } from './store.svelte';
import { enqueueTrack, enqueueTracks, playNext, playRadio } from './store.svelte';
import * as client from '$lib/api/client';
describe('player store — enqueue + playRadio', () => {
@@ -334,6 +334,22 @@ describe('player store — enqueue + playRadio', () => {
});
});
describe('playNext', () => {
test('splices at _index + 1, leaving _index unchanged', () => {
playQueue([track('a'), track('b')], 0);
playNext(track('c'));
expect(player.queue.map((t) => t.id)).toEqual(['a', 'c', 'b']);
expect(player.index).toBe(0);
});
test('on empty queue, seeds with the track at index 0', () => {
playQueue([]);
playNext(track('x'));
expect(player.queue.map((t) => t.id)).toEqual(['x']);
expect(player.index).toBe(0);
});
});
describe('M4c radio auto-refresh at 80%', () => {
test('refresh fires at 80% queue consumption', async () => {
const tracks = [track('seed'), track('t1'), track('t2'), track('t3'), track('t4')];