mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-08-11 11:19:24 +00:00
play-queue: peekNext() — expose the following track for queue-aware UIs (#719)
A results screen that offers "Up next: <song> — starting in 10s" needs to
know WHAT follows without reaching into queue internals. peekNext() returns
{filename, index, total} for the next track (null when nothing follows),
pure — peeking never plays or mutates.
First consumer: the note_detect results card's queue-advance strip (the
"Playlist Play All has no way to progress" tester issue).
Claude-Session: https://claude.ai/code/session_01Nm7tHs1Yvjjtnnu4nzJgdN
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
4b6cbe8b11
commit
28b0319e27
@@ -6778,6 +6778,14 @@ window.feedBack.playQueue = (function () {
|
|||||||
start: start, advance: advance, hasNext: hasNext, active: active, clear: clear,
|
start: start, advance: advance, hasNext: hasNext, active: active, clear: clear,
|
||||||
source: function () { return source; },
|
source: function () { return source; },
|
||||||
remaining: function () { return active() ? list.length - idx - 1 : 0; },
|
remaining: function () { return active() ? list.length - idx - 1 : 0; },
|
||||||
|
// What's coming, for consumers that RENDER the queue (a results
|
||||||
|
// screen's "Up next: … starting in 10s" strip) without reaching into
|
||||||
|
// queue internals. Null when nothing follows.
|
||||||
|
peekNext: function () {
|
||||||
|
return hasNext()
|
||||||
|
? { filename: list[idx + 1], index: idx + 1, total: list.length }
|
||||||
|
: null;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// playQueue.peekNext() (queue-advance UX): consumers that render "Up next"
|
||||||
|
// (the results card's countdown strip) need to know WHAT follows without
|
||||||
|
// reaching into queue internals. Extract the playQueue IIFE from app.js and
|
||||||
|
// drive it against a playSong stub.
|
||||||
|
'use strict';
|
||||||
|
const test = require('node:test');
|
||||||
|
const assert = require('node:assert');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
const path = require('node:path');
|
||||||
|
|
||||||
|
function makeQueue() {
|
||||||
|
const src = fs.readFileSync(path.join(__dirname, '..', '..', 'static', 'app.js'), 'utf8');
|
||||||
|
const start = src.indexOf('window.feedBack.playQueue = (function () {');
|
||||||
|
assert.ok(start !== -1, 'playQueue IIFE found in app.js');
|
||||||
|
const end = src.indexOf('})();', start);
|
||||||
|
assert.ok(end !== -1, 'playQueue IIFE terminator found');
|
||||||
|
const iife = src.slice(start, end + 5);
|
||||||
|
const played = [];
|
||||||
|
const sandbox = {
|
||||||
|
window: {
|
||||||
|
feedBack: {},
|
||||||
|
playSong: (fn, arr, opts) => played.push({ fn, arr, opts }),
|
||||||
|
fbNotify: null,
|
||||||
|
},
|
||||||
|
encodeURIComponent,
|
||||||
|
};
|
||||||
|
// eslint-disable-next-line no-new-func
|
||||||
|
new Function('window', 'encodeURIComponent', iife)(sandbox.window, encodeURIComponent);
|
||||||
|
return { q: sandbox.window.feedBack.playQueue, played };
|
||||||
|
}
|
||||||
|
|
||||||
|
test('peekNext exposes the following track without mutating the queue', () => {
|
||||||
|
const { q, played } = makeQueue();
|
||||||
|
assert.strictEqual(q.peekNext(), null); // idle queue → null
|
||||||
|
q.start(['a.sloppak', 'b.sloppak', 'c.sloppak'], { source: 'My list' });
|
||||||
|
assert.deepStrictEqual(q.peekNext(), { filename: 'b.sloppak', index: 1, total: 3 });
|
||||||
|
assert.deepStrictEqual(q.peekNext(), { filename: 'b.sloppak', index: 1, total: 3 }); // pure
|
||||||
|
assert.strictEqual(played.length, 1); // peeking never plays
|
||||||
|
q.advance();
|
||||||
|
assert.deepStrictEqual(q.peekNext(), { filename: 'c.sloppak', index: 2, total: 3 });
|
||||||
|
q.advance();
|
||||||
|
assert.strictEqual(q.peekNext(), null); // last track → nothing next
|
||||||
|
assert.strictEqual(q.remaining(), 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('peekNext is null after clear', () => {
|
||||||
|
const { q } = makeQueue();
|
||||||
|
q.start(['a.sloppak', 'b.sloppak']);
|
||||||
|
q.clear();
|
||||||
|
assert.strictEqual(q.peekNext(), null);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user