mirror of
https://github.com/SoPat712/allstarr.git
synced 2026-02-09 23:55:10 -05:00
feat: add tooltips, refresh & match button, and matching warning banner
This commit is contained in:
@@ -644,12 +644,18 @@
|
|||||||
|
|
||||||
<!-- Active Playlists Tab -->
|
<!-- Active Playlists Tab -->
|
||||||
<div class="tab-content" id="tab-playlists">
|
<div class="tab-content" id="tab-playlists">
|
||||||
|
<!-- Warning Banner (hidden by default) -->
|
||||||
|
<div id="matching-warning-banner" style="display:none;background:#f59e0b;color:#000;padding:16px;border-radius:8px;margin-bottom:16px;font-weight:600;text-align:center;box-shadow:0 4px 6px rgba(0,0,0,0.1);">
|
||||||
|
⚠️ TRACK MATCHING IN PROGRESS - Please wait for matching to complete before making changes to playlists or mappings!
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h2>
|
<h2>
|
||||||
Active Spotify Playlists
|
Active Spotify Playlists
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button onclick="matchAllPlaylists()">Match All Tracks</button>
|
<button onclick="matchAllPlaylists()" title="Match tracks for all playlists against your local library and external providers. This may take several minutes.">Match All Tracks</button>
|
||||||
<button onclick="refreshPlaylists()">Refresh All</button>
|
<button onclick="refreshPlaylists()" title="Fetch the latest playlist data from Spotify without re-matching tracks.">Refresh All</button>
|
||||||
|
<button onclick="refreshAndMatchAll()" title="Clear caches, fetch fresh data from Spotify, and match all tracks. This is a full rebuild and may take several minutes." style="background:var(--accent);border-color:var(--accent);">Refresh & Match All</button>
|
||||||
</div>
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
<p style="color: var(--text-secondary); margin-bottom: 12px;">
|
<p style="color: var(--text-secondary); margin-bottom: 12px;">
|
||||||
@@ -1910,6 +1916,9 @@
|
|||||||
if (!confirm(`Clear cache and rebuild for "${name}"?\n\nThis will:\n• Clear Redis cache\n• Delete file caches\n• Rebuild with latest Spotify IDs\n\nThis may take a minute.`)) return;
|
if (!confirm(`Clear cache and rebuild for "${name}"?\n\nThis will:\n• Clear Redis cache\n• Delete file caches\n• Rebuild with latest Spotify IDs\n\nThis may take a minute.`)) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Show warning banner
|
||||||
|
document.getElementById('matching-warning-banner').style.display = 'block';
|
||||||
|
|
||||||
showToast(`Clearing cache for ${name}...`, 'info');
|
showToast(`Clearing cache for ${name}...`, 'info');
|
||||||
const res = await fetch(`/api/admin/playlists/${encodeURIComponent(name)}/clear-cache`, { method: 'POST' });
|
const res = await fetch(`/api/admin/playlists/${encodeURIComponent(name)}/clear-cache`, { method: 'POST' });
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
@@ -1917,17 +1926,26 @@
|
|||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
showToast(`✓ ${data.message} (Cleared ${data.clearedKeys} cache keys, ${data.clearedFiles} files)`, 'success', 5000);
|
showToast(`✓ ${data.message} (Cleared ${data.clearedKeys} cache keys, ${data.clearedFiles} files)`, 'success', 5000);
|
||||||
// Refresh the playlists table after a delay to show updated counts
|
// Refresh the playlists table after a delay to show updated counts
|
||||||
setTimeout(fetchPlaylists, 3000);
|
setTimeout(() => {
|
||||||
|
fetchPlaylists();
|
||||||
|
// Hide warning banner after refresh
|
||||||
|
document.getElementById('matching-warning-banner').style.display = 'none';
|
||||||
|
}, 3000);
|
||||||
} else {
|
} else {
|
||||||
showToast(data.error || 'Failed to clear cache', 'error');
|
showToast(data.error || 'Failed to clear cache', 'error');
|
||||||
|
document.getElementById('matching-warning-banner').style.display = 'none';
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showToast('Failed to clear cache', 'error');
|
showToast('Failed to clear cache', 'error');
|
||||||
|
document.getElementById('matching-warning-banner').style.display = 'none';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function matchPlaylistTracks(name) {
|
async function matchPlaylistTracks(name) {
|
||||||
try {
|
try {
|
||||||
|
// Show warning banner
|
||||||
|
document.getElementById('matching-warning-banner').style.display = 'block';
|
||||||
|
|
||||||
showToast(`Matching tracks for ${name}...`, 'success');
|
showToast(`Matching tracks for ${name}...`, 'success');
|
||||||
const res = await fetch(`/api/admin/playlists/${encodeURIComponent(name)}/match`, { method: 'POST' });
|
const res = await fetch(`/api/admin/playlists/${encodeURIComponent(name)}/match`, { method: 'POST' });
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
@@ -1935,12 +1953,18 @@
|
|||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
showToast(`✓ ${data.message}`, 'success');
|
showToast(`✓ ${data.message}`, 'success');
|
||||||
// Refresh the playlists table after a delay to show updated counts
|
// Refresh the playlists table after a delay to show updated counts
|
||||||
setTimeout(fetchPlaylists, 2000);
|
setTimeout(() => {
|
||||||
|
fetchPlaylists();
|
||||||
|
// Hide warning banner after refresh
|
||||||
|
document.getElementById('matching-warning-banner').style.display = 'none';
|
||||||
|
}, 2000);
|
||||||
} else {
|
} else {
|
||||||
showToast(data.error || 'Failed to match tracks', 'error');
|
showToast(data.error || 'Failed to match tracks', 'error');
|
||||||
|
document.getElementById('matching-warning-banner').style.display = 'none';
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showToast('Failed to match tracks', 'error');
|
showToast('Failed to match tracks', 'error');
|
||||||
|
document.getElementById('matching-warning-banner').style.display = 'none';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1948,6 +1972,9 @@
|
|||||||
if (!confirm('Match tracks for ALL playlists? This may take a few minutes.')) return;
|
if (!confirm('Match tracks for ALL playlists? This may take a few minutes.')) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// Show warning banner
|
||||||
|
document.getElementById('matching-warning-banner').style.display = 'block';
|
||||||
|
|
||||||
showToast('Matching tracks for all playlists...', 'success');
|
showToast('Matching tracks for all playlists...', 'success');
|
||||||
const res = await fetch('/api/admin/playlists/match-all', { method: 'POST' });
|
const res = await fetch('/api/admin/playlists/match-all', { method: 'POST' });
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
@@ -1955,12 +1982,61 @@
|
|||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
showToast(`✓ ${data.message}`, 'success');
|
showToast(`✓ ${data.message}`, 'success');
|
||||||
// Refresh the playlists table after a delay to show updated counts
|
// Refresh the playlists table after a delay to show updated counts
|
||||||
setTimeout(fetchPlaylists, 2000);
|
setTimeout(() => {
|
||||||
|
fetchPlaylists();
|
||||||
|
// Hide warning banner after refresh
|
||||||
|
document.getElementById('matching-warning-banner').style.display = 'none';
|
||||||
|
}, 2000);
|
||||||
} else {
|
} else {
|
||||||
showToast(data.error || 'Failed to match tracks', 'error');
|
showToast(data.error || 'Failed to match tracks', 'error');
|
||||||
|
document.getElementById('matching-warning-banner').style.display = 'none';
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showToast('Failed to match tracks', 'error');
|
showToast('Failed to match tracks', 'error');
|
||||||
|
document.getElementById('matching-warning-banner').style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function refreshAndMatchAll() {
|
||||||
|
if (!confirm('Clear caches, refresh from Spotify, and match all tracks?\n\nThis will:\n• Clear all playlist caches\n• Fetch fresh data from Spotify\n• Match all tracks against local library and external providers\n\nThis may take several minutes.')) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Show warning banner
|
||||||
|
document.getElementById('matching-warning-banner').style.display = 'block';
|
||||||
|
|
||||||
|
showToast('Starting full refresh and match...', 'info', 3000);
|
||||||
|
|
||||||
|
// Step 1: Clear all caches
|
||||||
|
showToast('Step 1/3: Clearing caches...', 'info', 2000);
|
||||||
|
await fetch('/api/admin/cache/clear', { method: 'POST' });
|
||||||
|
|
||||||
|
// Step 2: Refresh playlists from Spotify
|
||||||
|
showToast('Step 2/3: Fetching from Spotify...', 'info', 2000);
|
||||||
|
await fetch('/api/admin/playlists/refresh', { method: 'POST' });
|
||||||
|
|
||||||
|
// Wait a bit for Spotify fetch to complete
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 3000));
|
||||||
|
|
||||||
|
// Step 3: Match all tracks
|
||||||
|
showToast('Step 3/3: Matching all tracks...', 'info', 2000);
|
||||||
|
const res = await fetch('/api/admin/playlists/match-all', { method: 'POST' });
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
showToast(`✓ Full refresh and match complete!`, 'success', 5000);
|
||||||
|
// Refresh the playlists table after a delay
|
||||||
|
setTimeout(() => {
|
||||||
|
fetchPlaylists();
|
||||||
|
// Hide warning banner after refresh
|
||||||
|
document.getElementById('matching-warning-banner').style.display = 'none';
|
||||||
|
}, 2000);
|
||||||
|
} else {
|
||||||
|
showToast(data.error || 'Failed to match tracks', 'error');
|
||||||
|
document.getElementById('matching-warning-banner').style.display = 'none';
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showToast('Failed to complete refresh and match', 'error');
|
||||||
|
document.getElementById('matching-warning-banner').style.display = 'none';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user