From 38e35930a98563c831fd08dbf8ab225752685094 Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Tue, 26 May 2026 15:24:23 -0700 Subject: [PATCH] Add Last.fm Radio tab to Sync page (Phase 1c.2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sibling to the ListenBrainz Sync tab from Phase 1c.1. Last.fm Radio playlists already live in the same ``listenbrainz_playlists`` table as LB ones (``playlist_type='lastfm_radio'``) and run through the same MB-track discovery worker, so this tab is intentionally thin β€” list + render + delegate. Card click hands straight off to the LB Sync-tab click handler since the downstream modal + state machine are identical. - ``webui/index.html``: new `` + + `; + }).join(''); + + container.querySelectorAll('.lastfm-playlist-card').forEach(card => { + card.addEventListener('click', () => { + const mbid = card.dataset.lbMbid; + const title = card.dataset.lbTitle; + // Reuses the LB Sync-tab click handler β€” Last.fm radios are + // stored in the same table + matched by the same discovery + // worker, so the click flow is byte-identical. + if (typeof handleListenBrainzSyncCardClick === 'function') { + handleListenBrainzSyncCardClick(mbid, title); + } + }); + }); + + // Reuse the shared refresh loop from sync-listenbrainz.js β€” it + // already iterates Last.fm cards alongside LB cards. + if (typeof _startLbSyncCardRefreshLoop === 'function') { + const tab = document.getElementById('lastfm-sync-tab-content'); + if (tab && tab.classList.contains('active')) { + _startLbSyncCardRefreshLoop(); + } + } +} + +document.addEventListener('DOMContentLoaded', () => { + const btn = document.getElementById('lastfm-sync-refresh-btn'); + if (btn) btn.addEventListener('click', loadLastfmSyncPlaylists); +}); diff --git a/webui/static/sync-listenbrainz.js b/webui/static/sync-listenbrainz.js index d025b485..b8415ce6 100644 --- a/webui/static/sync-listenbrainz.js +++ b/webui/static/sync-listenbrainz.js @@ -284,15 +284,28 @@ function _refreshOneLbSyncCard(card) { } function _refreshAllLbSyncCards() { - document.querySelectorAll('#listenbrainz-sync-tab-content .listenbrainz-playlist-card') - .forEach(_refreshOneLbSyncCard); + // Both LB and Last.fm-radio tabs render MB-track cards that share + // the ``listenbrainzPlaylistStates`` state machine (Last.fm radios + // are stored in the same listenbrainz_playlists table with + // ``playlist_type='lastfm_radio'``). The refresh loop iterates + // visible cards from either tab so we don't need a second loop. + document.querySelectorAll( + '#listenbrainz-sync-tab-content .listenbrainz-playlist-card, ' + + '#lastfm-sync-tab-content .lastfm-playlist-card' + ).forEach(_refreshOneLbSyncCard); +} + +function _isMbStyleSyncTabActive() { + const lb = document.getElementById('listenbrainz-sync-tab-content'); + const lfm = document.getElementById('lastfm-sync-tab-content'); + return (lb && lb.classList.contains('active')) + || (lfm && lfm.classList.contains('active')); } function _startLbSyncCardRefreshLoop() { if (_lbSyncCardRefreshInterval) return; _lbSyncCardRefreshInterval = setInterval(() => { - const tab = document.getElementById('listenbrainz-sync-tab-content'); - if (!tab || !tab.classList.contains('active')) { + if (!_isMbStyleSyncTabActive()) { _stopLbSyncCardRefreshLoop(); return; } diff --git a/webui/static/sync-services.js b/webui/static/sync-services.js index 085ed157..67f6ded7 100644 --- a/webui/static/sync-services.js +++ b/webui/static/sync-services.js @@ -3751,6 +3751,19 @@ function initializeSyncPage() { _startLbSyncCardRefreshLoop(); } } + + // Last.fm Sync tab β€” same MB-track shape as LB, shares the + // listenbrainzPlaylistStates machinery + refresh loop. + if (tabId === 'lastfm-sync') { + if (typeof loadLastfmSyncPlaylists === 'function' + && !window._lastfmSyncTabLoaded) { + window._lastfmSyncTabLoaded = true; + loadLastfmSyncPlaylists(); + } + if (typeof _startLbSyncCardRefreshLoop === 'function') { + _startLbSyncCardRefreshLoop(); + } + } }); });