ClearPlaylistCache(string name)
+ {
+ var decodedName = Uri.UnescapeDataString(name);
+ _logger.LogInformation("Clear cache & rebuild triggered for playlist: {Name}", decodedName);
+
+ if (_matchingService == null)
+ {
+ return BadRequest(new { error = "Track matching service is not available" });
+ }
+
+ try
+ {
+ // Clear all cache keys for this playlist
+ var cacheKeys = new[]
+ {
+ $"spotify:playlist:items:{decodedName}", // Pre-built items cache
+ $"spotify:matched:ordered:{decodedName}", // Ordered matched tracks
+ $"spotify:matched:{decodedName}", // Legacy matched tracks
+ $"spotify:missing:{decodedName}" // Missing tracks
+ };
+
+ foreach (var key in cacheKeys)
+ {
+ await _cache.DeleteAsync(key);
+ _logger.LogDebug("Cleared cache key: {Key}", key);
+ }
+
+ // Delete file caches
+ var safeName = string.Join("_", decodedName.Split(Path.GetInvalidFileNameChars()));
+ var filesToDelete = new[]
+ {
+ Path.Combine(CacheDirectory, $"{safeName}_items.json"),
+ Path.Combine(CacheDirectory, $"{safeName}_matched.json")
+ };
+
+ foreach (var file in filesToDelete)
+ {
+ if (System.IO.File.Exists(file))
+ {
+ System.IO.File.Delete(file);
+ _logger.LogDebug("Deleted cache file: {File}", file);
+ }
+ }
+
+ _logger.LogInformation("✓ Cleared all caches for playlist: {Name}", decodedName);
+
+ // Trigger rebuild
+ await _matchingService.TriggerMatchingForPlaylistAsync(decodedName);
+
+ // Invalidate playlist summary cache
+ InvalidatePlaylistSummaryCache();
+
+ return Ok(new
+ {
+ message = $"Cache cleared and rebuild triggered for {decodedName}",
+ timestamp = DateTime.UtcNow,
+ clearedKeys = cacheKeys.Length,
+ clearedFiles = filesToDelete.Count(System.IO.File.Exists)
+ });
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Failed to clear cache for {Name}", decodedName);
+ return StatusCode(500, new { error = "Failed to clear cache", details = ex.Message });
+ }
+ }
+
///
/// Search Jellyfin library for tracks (for manual mapping)
///
diff --git a/allstarr/wwwroot/index.html b/allstarr/wwwroot/index.html
index 3a8111e..9510c96 100644
--- a/allstarr/wwwroot/index.html
+++ b/allstarr/wwwroot/index.html
@@ -1331,6 +1331,7 @@
| ${p.cacheAge || '-'} |
+
@@ -1672,6 +1673,26 @@
}
}
+ async function clearPlaylistCache(name) {
+ 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 {
+ showToast(`Clearing cache for ${name}...`, 'info');
+ const res = await fetch(`/api/admin/playlists/${encodeURIComponent(name)}/clear-cache`, { method: 'POST' });
+ const data = await res.json();
+
+ if (res.ok) {
+ showToast(`✓ ${data.message} (Cleared ${data.clearedKeys} cache keys, ${data.clearedFiles} files)`, 'success', 5000);
+ // Refresh the playlists table after a delay to show updated counts
+ setTimeout(fetchPlaylists, 3000);
+ } else {
+ showToast(data.error || 'Failed to clear cache', 'error');
+ }
+ } catch (error) {
+ showToast('Failed to clear cache', 'error');
+ }
+ }
+
async function matchPlaylistTracks(name) {
try {
showToast(`Matching tracks for ${name}...`, 'success');
|