fix(player): gapless media session, resume, repeat-all, queue-select, history order
Media Session
- Surface the OS/lock-screen controls for the Web Audio (wasm) path via a hidden
silent looping <audio> anchor (browsers only show controls for a playing media
element). Drive the anchor synchronously inside the media-key handlers so
RESUME works — the deferred effect can't play() in-gesture (autoplay policy).
- Full metadata (title/artist/album + multi-size artwork), live play/pause
state, scrubbable position, and all transport actions incl. seek.
Repeat all
- publishRepeat/publishShuffle on the engine, remembered + applied on init, so
repeat "all" set before the first play loops the queue instead of stopping.
Queue
- Selecting a queue track pins the chosen index briefly (pinQueueIndex /
effectiveQueueIndex) so a late status from the outgoing track can't revert
the "up next" the user just picked.
- History listed chronologically (oldest top, most-recent bottom).
Persistence / resume
- Persist {queue, index, progressMs} to localStorage (jotai atomWithStorage)
every few seconds + on pagehide. On reload, rehydrate the queue + position
(paused); on the next play, rebuild the engine at the saved index and seek to
the saved elapsed time. Mobile ensureEngineQueue returns {p, loaded} so a
fresh resume isn't immediately toggled to pause.
All app-side (works with rockbox-wasm@0.1.3).
port mobile app to React Native: search, miniplayer, icons, sign-in copy
This covers the major threads: the full Search screen rewrite (correct
endpoint, flat hits shape, Feather icon), MiniPlayer with Rockbox WebSocket
controls and playback lock, app icon replaced with the Rocksky favicon, and
sign-in copy aligned with web/web-mobile (Handle label, atproto signup text,
selfhosted.social OAuth flow).