From ac474b17608af27609f9e86a2e0a3e18cebddba1 Mon Sep 17 00:00:00 2001 From: Honey Date: Fri, 5 Jun 2026 00:15:39 +0200 Subject: [PATCH] fix: correct onReady sync logic for single-track model; remove stale _setSkipping call Co-Authored-By: Claude Sonnet 4.6 --- src/player.js | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/player.js b/src/player.js index e98029a..15b7fb6 100644 --- a/src/player.js +++ b/src/player.js @@ -90,41 +90,48 @@ window.NSPlayer = { const state = raw ? (JSON.parse(raw) || {}) : {}; const nativeLen = state.queueLength || 0; const nativePlaying = state.isPlaying || false; - const nativeIdx = typeof state.currentIndex === 'number' ? state.currentIndex : S.qIdx; const nativeId = state.currentId || ''; - // Helper: true if native's current song matches JS queue at nativeIdx - const inSync = nativeIdx >= 0 && nativeIdx < S.queue.length && - (!nativeId || !S.queue[nativeIdx]?.id || - String(nativeId) === String(S.queue[nativeIdx].id)); + // Single-track model: native index is always 0, meaningless for queue position. + // Match by song ID against S.queue[S.qIdx] — the JS-side current position. + const currentSong = S.queue[S.qIdx]; + const idMatch = !nativeId || !currentSong?.id || + String(nativeId) === String(currentSong.id); if (nativeLen > 0 && nativePlaying) { - if (inSync) { - // Native is actively playing and we have the right song — re-sync. - S.qIdx = nativeIdx; + if (idMatch) { + // Native is playing our current song — re-sync UI without touching S.qIdx. _nativePlaying = true; _nativePos = state.positionMs || 0; - const s = S.queue[S.qIdx]; - if (s) { updatePlayerUI(s, true); onNpSongChange(s.id); } + if (currentSong) { updatePlayerUI(currentSong, true); onNpSongChange(currentSong.id); } setPlayIcon(true); renderQueue(); } else { - // Native is playing a song we don't have (e.g. radio advanced while backgrounded). - // Reset the stale JS queue to avoid showing the wrong song — native keeps playing. - S.queue = []; - S.qIdx = 0; + // Native advanced to a different song while backgrounded — find it in the queue. + const found = nativeId ? S.queue.findIndex(s => String(s.id) === String(nativeId)) : -1; + if (found >= 0) { + S.qIdx = found; + _nativePlaying = true; + _nativePos = state.positionMs || 0; + const s = S.queue[S.qIdx]; + if (s) { updatePlayerUI(s, true); onNpSongChange(s.id); } + setPlayIcon(true); + renderQueue(); + } else { + // Playing a song not in our queue (radio advanced past known tracks) — clear. + S.queue = []; + S.qIdx = 0; + } } - } else if (nativeLen > 0 && inSync) { - // Paused but we can confirm the current song — re-sync UI state only. - S.qIdx = nativeIdx; + } else if (nativeLen > 0 && !nativePlaying && idMatch) { + // Paused, song matches — re-sync UI state only. _nativePlaying = false; _nativePos = state.positionMs || 0; - const s = S.queue[S.qIdx]; - if (s) { updatePlayerUI(s, true); onNpSongChange(s.id); } + if (currentSong) { updatePlayerUI(currentSong, true); onNpSongChange(currentSong.id); } setPlayIcon(false); renderQueue(); - } else if (!nativePlaying) { - // Native is idle/empty — push just the current song (single-track model). + } else { + // Native is idle/empty or has a mismatched paused song — push current (single-track model). const s = S.queue[S.qIdx]; if (s) window.NSBridge.setQueue(_nativeSingle(s), 0, false); } @@ -849,7 +856,6 @@ function _initBarScrub(bar, fill, onMove, noTouch = false) { fill.style.width = (pos * 100) + '%'; const dur = _dur(); if (HAS_BRIDGE) { - _setSkipping(); _nsBridge('seekTo', Math.round(pos * _lastDurationMs)); S._scrubbing = false; requestAnimationFrame(() => { fill.style.transition = ''; });