diff --git a/webui/index.html b/webui/index.html
index 4e614f3c..23703a9e 100644
--- a/webui/index.html
+++ b/webui/index.html
@@ -3692,6 +3692,10 @@
+
diff --git a/webui/static/script.js b/webui/static/script.js
index b51bd7c0..64568c61 100644
--- a/webui/static/script.js
+++ b/webui/static/script.js
@@ -7328,6 +7328,29 @@ async function disconnectSpotify() {
}
}
+async function clearSpotifyCacheAndFallback() {
+ const fallbackName = currentMusicSourceName !== 'Spotify' ? currentMusicSourceName : 'the configured fallback source';
+ if (!await showConfirmDialog({
+ title: 'Clear Spotify Cache',
+ message: `This will clear the Spotify token cache and switch metadata to ${fallbackName}. You can re-authenticate later.`
+ })) return;
+ try {
+ showLoadingOverlay('Clearing Spotify cache...');
+ const response = await fetch('/api/spotify/disconnect', { method: 'POST' });
+ const data = await response.json();
+ if (data.success) {
+ showToast(data.message || `Switched to ${fallbackName}`, 'success');
+ await fetchAndUpdateServiceStatus();
+ } else {
+ showToast(`Failed: ${data.error}`, 'error');
+ }
+ } catch (error) {
+ showToast('Failed to clear Spotify cache', 'error');
+ } finally {
+ hideLoadingOverlay();
+ }
+}
+
// ── Spotify Rate Limit Handling ───────────────────────────────────────────
let _spotifyRateLimitShown = false;
let _spotifyInCooldown = false;
@@ -36094,29 +36117,15 @@ function updateServiceStatus(service, statusData) {
}
}
- // Update music source title and status based on active source
+ // Update music source title based on active source
if (service === 'spotify' && statusData.source) {
const musicSourceTitleElement = document.getElementById('music-source-title');
if (musicSourceTitleElement) {
- // Card title always says "Spotify" — it represents the metadata source slot
- musicSourceTitleElement.textContent = 'Spotify';
- // Update global variable for use in discovery modals
const sourceName = statusData.source === 'spotify' ? 'Spotify' : statusData.source === 'deezer' ? 'Deezer' : 'iTunes';
+ musicSourceTitleElement.textContent = sourceName;
currentMusicSourceName = sourceName;
}
- // When using fallback, update status text to show which fallback is active
- if (statusData.source !== 'spotify' && !statusData.rate_limited && !statusData.post_ban_cooldown) {
- const fallbackName = statusData.source === 'deezer' ? 'Deezer' : 'iTunes';
- if (statusText) {
- statusText.textContent = `Using ${fallbackName}`;
- statusText.className = 'service-card-status-text fallback';
- }
- if (indicator) {
- indicator.className = 'service-card-indicator fallback';
- }
- }
-
// Show/hide Spotify disconnect button based on connection state
const disconnectBtn = document.getElementById('spotify-disconnect-btn');
if (disconnectBtn) {
@@ -36163,20 +36172,12 @@ function updateSidebarServiceStatus(service, statusData) {
}
}
- // Update music source name — always "Spotify" in sidebar
+ // Update music source name in sidebar based on active source
if (service === 'spotify' && statusData.source) {
const musicSourceNameElement = document.getElementById('music-source-name');
if (musicSourceNameElement) {
- musicSourceNameElement.textContent = 'Spotify';
- }
-
- // Show fallback state in sidebar dot
- if (statusData.source !== 'spotify' && !statusData.rate_limited && !statusData.post_ban_cooldown) {
- if (dot) {
- dot.className = 'status-dot fallback';
- const fallbackName = statusData.source === 'deezer' ? 'Deezer' : 'iTunes';
- dot.title = `Using ${fallbackName} fallback`;
- }
+ const sourceName = statusData.source === 'spotify' ? 'Spotify' : statusData.source === 'deezer' ? 'Deezer' : 'iTunes';
+ musicSourceNameElement.textContent = sourceName;
}
}