diff --git a/src/main.js b/src/main.js index b206661..eaa2797 100644 --- a/src/main.js +++ b/src/main.js @@ -9,7 +9,7 @@ import { initProgressScrub, updateProgress, updatePreviewProgress, stopPreview, toggleRadioMode, starCurrent, downloadCurrent, renderQueue, playPreview, toggleStar, dlSongLocal, _applyRadioBtn, _applyShuffleRepeat, _restoreLastPlayed, setPlayIcon, - npToggleStar, updateMediaSession, updateNpColorMode, + npToggleStar, updateMediaSession, updateNpColorMode, reconcileNativeState, } from './player.js'; import { navigate, _navGoBack, _navLoad, onHeaderSearch, closeHeaderSearch, @@ -174,6 +174,7 @@ window.addEventListener('load', () => { let _wasPlayingBeforeHide = false; function _onForeground() { + reconcileNativeState(); const s = S.queue[S.qIdx]; if(!s) return; updateMediaSession(s); diff --git a/src/player.js b/src/player.js index fe1d030..91d59fd 100644 --- a/src/player.js +++ b/src/player.js @@ -1236,6 +1236,28 @@ if (HAS_BRIDGE) { } } +// Immediately sync JS track/play state with the native bridge snapshot. +// Called on app foreground so the UI is correct before any deferred evaluateJavascript callbacks fire. +export function reconcileNativeState() { + if (!HAS_BRIDGE) return; + try { + const snap = JSON.parse(window.NSBridge.getState() || '{}'); + const snapId = String(snap.currentId || ''); + if (snapId && snapId !== String(S.queue[S.qIdx]?.id || '')) { + const found = S.queue.findIndex(s => String(s.id) === snapId); + if (found >= 0) { + S.qIdx = found; + const s = S.queue[S.qIdx]; + if (s) { updatePlayerUI(s, true); syncNowPlaying(); onNpSongChange(s.id); renderQueue(); } + } + } + if (typeof snap.isPlaying === 'boolean' && snap.isPlaying !== _nativePlaying) { + _nativePlaying = snap.isPlaying; + setPlayIcon(snap.isPlaying); + } + } catch {} +} + export function _restoreLastPlayed() { try { const saved = JSON.parse(localStorage.getItem('ns_last_played') || 'null'); diff --git a/src/ui.js b/src/ui.js index 6abaf79..0b0be44 100644 --- a/src/ui.js +++ b/src/ui.js @@ -4,7 +4,7 @@ import { api, coverUrl, ndAuth, fetchRomajiIndex, romajiConvert, romajiLookup, i import { THEMES, applyTheme, getCurrentThemeId } from './themes.js'; // Circular imports — safe (only used inside function bodies) import { playQueue, dlSongLocal, toggleStar, togglePlay, renderQueue, syncNpStar, updateStarBtn, npToggleStar, playCurrent, _syncNpDirect, setPlayIcon, nativeInsertAt, refreshDisplayMode, updateNpColorMode } from './player.js'; -import { navigate, loadPlaylists } from './views.js'; +import { navigate, loadPlaylists, loadPlaylistDetail } from './views.js'; // ─── SIDEBAR ─── export function openSidebar() { @@ -536,6 +536,13 @@ export async function deleteSong() { if (!r.ok) throw new Error(d.error || `HTTP ${r.status}`); toast(`🗑 "${s.title}" gelöscht`); closeInfoModal(); + // Refresh playlist views after Navidrome's background scan has a chance to finish + setTimeout(() => { + if (document.getElementById('page-playlists')?.classList.contains('active')) + loadPlaylists(); + else if (document.getElementById('page-playlist-detail')?.classList.contains('active') && S._currentPlaylist) + loadPlaylistDetail(S._currentPlaylist); + }, 2000); } catch (e) { status.textContent = '❌ Fehler: ' + e.message; }