Fix Wing It sync live status and button persistence across all modals

Live status: updateYouTubeModalSyncProgress was hardcoded to youtube-*
element IDs but each source uses its own prefix (listenbrainz-*, tidal-*,
deezer-*, etc). Now tries all prefixes to find the correct elements.
Fixes Wing It sync progress AND a pre-existing bug where normal LB/Tidal
sync from the modal wouldn't show live progress.

Wing It button added to sync_complete phase so it persists after sync.
Fixed tracks lookup with state.playlist?.tracks fallback. Increased
button size in modal to match other action buttons.
pull/253/head
Broque Thomas 2 months ago
parent 3c19cc085b
commit a9dd93b176

@ -11805,11 +11805,11 @@ function _pollWingItSyncProgress(syncPlaylistId, playlistName, cardPlaylistId) {
setTimeout(() => clearInterval(poll), 180000);
}
function _wingItFromModal(urlHash) {
// Extract tracks from the discovery modal state
async function _wingItFromModal(urlHash) {
// Extract tracks from the discovery modal state — tracks can be in various locations
const state = listenbrainzPlaylistStates[urlHash] || youtubePlaylistStates[urlHash] || {};
const tracks = state.tracks || state.rawTracks || [];
const name = state.playlistName || state.name || 'Playlist';
const tracks = state.tracks || state.rawTracks || state.playlist?.tracks || [];
const name = state.playlistName || state.name || state.playlist?.name || 'Playlist';
const isTidal = state.is_tidal_playlist;
const isLB = state.is_listenbrainz_playlist;
const isBeatport = state.is_beatport_playlist;
@ -11821,7 +11821,56 @@ function _wingItFromModal(urlHash) {
return;
}
// Close the discovery modal first
const choice = await _showWingItChoiceDialog(tracks.length, source);
if (!choice) return;
if (choice === 'sync') {
// Sync inline — keep modal open, show progress in modal
showToast('Starting Wing It sync...', 'info');
updateYouTubeModalButtons(urlHash, 'syncing');
try {
// Format and send sync request
const syncTracks = tracks.map((t, i) => {
let artists = t.artists || [];
if (!Array.isArray(artists)) artists = [{ name: String(artists) }];
return {
id: t.id || t.source_track_id || `wing_it_${i}`,
name: t.name || t.track_name || 'Unknown',
artists: artists.map(a => typeof a === 'string' ? { name: a } : a),
album: typeof t.album === 'object' ? t.album : { name: t.album || t.album_name || '' },
duration_ms: t.duration_ms || 0,
};
});
const res = await fetch('/api/wing-it/sync', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ tracks: syncTracks, playlist_name: name })
});
const data = await res.json();
if (data.error) {
showToast(`Sync failed: ${data.error}`, 'error');
updateYouTubeModalButtons(urlHash, 'discovered');
return;
}
// Use the same sync polling as normal sync — works for any source
if (isLB) {
if (state) state.syncPlaylistId = data.sync_playlist_id;
startListenBrainzSyncPolling(urlHash, data.sync_playlist_id);
} else {
startYouTubeSyncPolling(urlHash, data.sync_playlist_id);
}
} catch (e) {
showToast('Sync failed: ' + e.message, 'error');
updateYouTubeModalButtons(urlHash, 'discovered');
}
return;
}
// choice === 'download' — close modal and open download modal
const modal = document.getElementById(`youtube-discovery-modal-${urlHash}`);
if (modal) modal.remove();
const overlay = document.getElementById(`youtube-discovery-overlay-${urlHash}`);
@ -30970,6 +31019,9 @@ function getModalActionButtons(urlHash, phase, state = null) {
syncCompleteButtons += `<button class="modal-btn modal-btn-secondary" onclick="resetYouTubePlaylist('${urlHash}')">🔄 Rediscover</button>`;
}
// Wing It button
syncCompleteButtons += ` <button class="modal-btn wing-it-btn" onclick="_wingItFromModal('${urlHash}')">⚡ Wing It</button>`;
return syncCompleteButtons;
case 'download_complete':
@ -31617,16 +31669,20 @@ function updateYouTubeCardSyncProgress(urlHash, progress) {
}
function updateYouTubeModalSyncProgress(urlHash, progress) {
const statusDisplay = document.getElementById(`youtube-sync-status-${urlHash}`);
// Try all source-specific element ID prefixes
const prefixes = ['youtube', 'listenbrainz', 'tidal', 'deezer', 'spotify-public', 'beatport'];
let statusDisplay = null;
let prefix = 'youtube';
for (const p of prefixes) {
statusDisplay = document.getElementById(`${p}-sync-status-${urlHash}`);
if (statusDisplay) { prefix = p; break; }
}
if (!statusDisplay || !progress) return;
console.log(`📊 Updating YouTube modal sync progress for ${urlHash}:`, progress);
// Update individual counters exactly like Spotify sync
const totalEl = document.getElementById(`youtube-total-${urlHash}`);
const matchedEl = document.getElementById(`youtube-matched-${urlHash}`);
const failedEl = document.getElementById(`youtube-failed-${urlHash}`);
const percentageEl = document.getElementById(`youtube-percentage-${urlHash}`);
const totalEl = document.getElementById(`${prefix}-total-${urlHash}`);
const matchedEl = document.getElementById(`${prefix}-matched-${urlHash}`);
const failedEl = document.getElementById(`${prefix}-failed-${urlHash}`);
const percentageEl = document.getElementById(`${prefix}-percentage-${urlHash}`);
const total = progress.total_tracks || 0;
const matched = progress.matched_tracks || 0;

@ -5171,18 +5171,18 @@ body.helper-mode-active #dashboard-activity-feed:hover {
/* ── Wing It Button ── */
.wing-it-btn {
background: transparent !important;
background: rgba(255, 183, 77, 0.08) !important;
border: 1px solid rgba(255, 183, 77, 0.3) !important;
color: #ffb74d !important;
font-size: 12px !important;
font-weight: 600 !important;
padding: 6px 14px !important;
border-radius: 8px !important;
font-size: 14px !important;
font-weight: 700 !important;
padding: 10px 20px !important;
border-radius: 10px !important;
cursor: pointer;
transition: all 0.2s;
}
.wing-it-btn:hover {
background: rgba(255, 183, 77, 0.1) !important;
background: rgba(255, 183, 77, 0.15) !important;
border-color: rgba(255, 183, 77, 0.5) !important;
}

Loading…
Cancel
Save