From b67d13164aa6e0a2089c1d1dc1cedca24f23507e Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Wed, 27 May 2026 07:08:21 -0700 Subject: [PATCH] Library: persist Enhanced / Standard view toggle in localStorage User feedback: the Enhanced view toggle on the artist detail page reset to Standard on every artist click, so admins who prefer Enhanced had to re-flip the toggle every single time. Persist the choice in localStorage and reapply on every artist navigation + page reload. - `toggleEnhancedView()` writes `soulsync-library-view-mode` to localStorage on every change. - `navigateToArtistDetail()` reads the saved value after the standard reset block runs; if `enhanced` AND `isEnhancedAdmin()` it calls `toggleEnhancedView(true)` after `loadArtistDetailData` kicks off. The brief Standard render is hidden as soon as the toggle flips. - Gated on `isEnhancedAdmin()` so non-admin profiles (which never see the toggle) can't end up with a stale Enhanced preference being applied silently. - Wrapped in try/catch since localStorage is unavailable in some private-browsing modes. No backend change; no DB migration needed. --- webui/static/helper.js | 1 + webui/static/library.js | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/webui/static/helper.js b/webui/static/helper.js index e3d96156..6ec49872 100644 --- a/webui/static/helper.js +++ b/webui/static/helper.js @@ -3415,6 +3415,7 @@ function closeHelperSearch() { const WHATS_NEW = { '2.6.3': [ { unreleased: true }, + { title: 'Library: Enhanced / Standard view toggle now sticks per browser', desc: 'the artist detail page used to revert to Standard view every time you clicked into a new artist — flipping to Enhanced was a per-click thing with no memory. now the choice is persisted in localStorage and reapplied automatically on every artist open. survives page reloads too. non-admins (who can\'t toggle Enhanced anyway) are unaffected; admins who never touched the Enhanced view stay on Standard since the saved value defaults to it.' }, { title: 'Fix popup: manual matches survive Playlist Pipeline runs', desc: 'manually mapping a mirrored-playlist track via the Fix popup (search or MBID) saved correctly and the download went through, but the next Playlist Pipeline run kept reverting the match — the track flipped back to "Provider Changed" and you had to map it again. three things were ganging up on it: the manual-fix save always stamped `provider: \'spotify\'` even when the match came from MusicBrainz / iTunes / Deezer, so prepare-discovery saw a provider mismatch on the next run; the discovery worker also re-queued any matched_data that lacked `track_number` / `album.id` / `release_date` for re-discovery, and Fix-popup saves never carry those fields by design (search results don\'t include track_number, MBID lookups don\'t include album.id) — so manual fixes always looked "incomplete" and got overwritten; and the prepare-discovery provider check didn\'t honour the `manual_match` flag at all. all three patched — manual matches now stamp the actual source, the worker short-circuits on `manual_match` before the incomplete-data branch, and prepare-discovery treats manual fixes as cached regardless of provider drift.' }, { title: 'Fix popup: artist + track fields no longer surface unrelated covers', desc: 'separate artist / track inputs in the Fix popup used to dump both into a bare MusicBrainz keyword query — and MB\'s scorer heavily favours title matches, so searching "Coffee Break" + "Zeds Dead" surfaced random "Coffee Break" tracks by other artists ahead of the canonical Zeds Dead one. fields-mode now uses a field-scoped Lucene query that actually anchors the artist, with the old bare query kept as a fallback for diacritic mismatches like "Bjork" vs "Björk" where strict phrase match misses. results also stable-prefer entries with known track length so the canonical 3:04 sibling sits above the 0:00 duplicate.' }, { title: 'Groundwork: unified playlist source layer', desc: 'first slice of a refactor that\'ll let ListenBrainz, Last.fm radio, and SoulSync Discovery playlists live as Sync-page tabs alongside Spotify / Tidal / Qobuz / YouTube — so they can be mirrored + scheduled like the rest. this commit adds the shared adapter layer all those sources will plug into; no UI changes yet. nothing to do on your end.' }, diff --git a/webui/static/library.js b/webui/static/library.js index 4e5467bf..dac0467a 100644 --- a/webui/static/library.js +++ b/webui/static/library.js @@ -879,6 +879,15 @@ function navigateToArtistDetail(artistId, artistName, sourceOverride = null, opt const bulkBar = document.getElementById('enhanced-bulk-bar'); if (bulkBar) bulkBar.classList.remove('visible'); + // Restore persisted view preference. Non-admins can't see / toggle the + // Enhanced control so only honour the saved choice for admins; default + // is still Standard. Wrapped in try/catch because localStorage can be + // disabled in private-browsing modes. + let _preferEnhanced = false; + try { + _preferEnhanced = localStorage.getItem('soulsync-library-view-mode') === 'enhanced'; + } catch (_) { /* localStorage unavailable */ } + // Navigate to artist detail page navigateToPage('artist-detail', { artistId, @@ -895,6 +904,13 @@ function navigateToArtistDetail(artistId, artistName, sourceOverride = null, opt // Load artist data loadArtistDetailData(artistId, artistName); + + // Apply persisted Enhanced view after the standard data load is kicked off. + // toggleEnhancedView() triggers its own loadEnhancedViewData() in parallel; + // the brief Standard render is hidden as soon as the toggle flips. + if (_preferEnhanced && isEnhancedAdmin()) { + toggleEnhancedView(true); + } } function _updateArtistDetailBackButtonLabel() { @@ -2905,6 +2921,12 @@ function toggleEnhancedView(enabled) { const bulkBar = document.getElementById('enhanced-bulk-bar'); if (bulkBar) bulkBar.classList.remove('visible'); } + + // Persist the choice so the next artist click (and the next page reload) + // honours it instead of always reverting to Standard. + try { + localStorage.setItem('soulsync-library-view-mode', enabled ? 'enhanced' : 'standard'); + } catch (_) { /* localStorage unavailable */ } } async function loadEnhancedViewData(artistId) {