From 20706fb9a4ec646816b44a10842aa8f58ea0fd75 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Wed, 16 Sep 2026 11:01:02 +0200 Subject: music: play, play next, add to queue The player's queue could only be replaced: every onPlayQueue reset tracks/order/pos together. It becomes one reducer (queue-ops.js) with an `op`, because two appends batched into one tick cannot both read the track count out of separate useStates. A shared pop-up menu (menu.js) carries the three verbs, on right-click and on a dots button. A track row is now a div holding two buttons: a button cannot contain a button. Found by the browser probe: both music wrappers took two arguments and forwarded two, so every "add to queue" arrived as a plain play. Co-Authored-By: Claude Opus 5 --- packages/meshbay-hub/src/meshbay_hub/static/app.js | 30 ++++++++++++++-------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'packages/meshbay-hub/src/meshbay_hub/static/app.js') diff --git a/packages/meshbay-hub/src/meshbay_hub/static/app.js b/packages/meshbay-hub/src/meshbay_hub/static/app.js index a249ccf..ef8d1e9 100644 --- a/packages/meshbay-hub/src/meshbay_hub/static/app.js +++ b/packages/meshbay-hub/src/meshbay_hub/static/app.js @@ -725,17 +725,27 @@ function App() { return { transport: conn.transport, gek: conn.gek }; }, []); - const handlePlayQueue = useCallback((tracks, startIndex, source) => { - if (source && source.transportRef) { - groupTransportRef.current = { - groupId: source.groupId, - transportRef: source.transportRef, - gekRef: source.gekRef, - }; - } else { - groupTransportRef.current = null; + // `op` is 'replace' (the default, and what playing an album or loading a + // playlist means), 'next', or 'append' — docs/playlists.md §9.2. + const handlePlayQueue = useCallback((tracks, startIndex, source, op) => { + const how = op || 'replace'; + // A single-slot fast path for the group whose page is open, so playing + // from it reuses the live transport instead of dialing through the pool. + // Only a replace is about that group: repointing it because one track + // from somewhere else was enqueued would drop whatever is *playing* back + // to the pool, for nothing. + if (how === 'replace') { + if (source && source.transportRef) { + groupTransportRef.current = { + groupId: source.groupId, + transportRef: source.transportRef, + gekRef: source.gekRef, + }; + } else { + groupTransportRef.current = null; + } } - setMusicQueue({ tracks, startIndex, nonce: Date.now() }); + setMusicQueue({ tracks, startIndex, nonce: Date.now(), op: how }); }, []); const handleStopMusic = useCallback(() => setMusicQueue(null), []); -- cgit v1.2.3