DeleteByPatternAsync(string pattern)
+ {
+ if (!IsEnabled) return 0;
+
+ try
+ {
+ var server = _redis!.GetServer(_redis.GetEndPoints().First());
+ var keys = server.Keys(pattern: pattern).ToArray();
+
+ if (keys.Length == 0)
+ {
+ _logger.LogDebug("No keys found matching pattern: {Pattern}", pattern);
+ return 0;
+ }
+
+ var deleted = await _db!.KeyDeleteAsync(keys);
+ _logger.LogInformation("Deleted {Count} Redis keys matching pattern: {Pattern}", deleted, pattern);
+ return (int)deleted;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "Redis DELETE BY PATTERN failed for pattern: {Pattern}", pattern);
+ return 0;
+ }
+ }
}
diff --git a/allstarr/wwwroot/index.html b/allstarr/wwwroot/index.html
index 28e2a3d..b9b40bc 100644
--- a/allstarr/wwwroot/index.html
+++ b/allstarr/wwwroot/index.html
@@ -873,11 +873,22 @@
-
+
+
+ Tip: Use commas to search multiple terms (e.g., "It Ain't Easy, David Bowie")
+
+
+ โ OR โ
+
+
+
+
+ Paste the full URL from your Jellyfin web interface
+
- Type to search for local tracks...
+ Type to search for local tracks or paste a Jellyfin URL...
@@ -1757,10 +1768,13 @@
const query = document.getElementById('map-search-query').value.trim();
if (!query) {
- document.getElementById('map-search-results').innerHTML = 'Type to search for local tracks...
';
+ document.getElementById('map-search-results').innerHTML = 'Type to search for local tracks or paste a Jellyfin URL...
';
return;
}
+ // Clear URL input when searching
+ document.getElementById('map-jellyfin-url').value = '';
+
// Debounce search
clearTimeout(searchTimeout);
searchTimeout = setTimeout(async () => {
@@ -1792,6 +1806,77 @@
}, 300);
}
+ async function extractJellyfinId() {
+ const url = document.getElementById('map-jellyfin-url').value.trim();
+
+ if (!url) {
+ document.getElementById('map-search-results').innerHTML = 'Type to search for local tracks or paste a Jellyfin URL...
';
+ document.getElementById('map-selected-jellyfin-id').value = '';
+ document.getElementById('map-save-btn').disabled = true;
+ return;
+ }
+
+ // Clear search input when using URL
+ document.getElementById('map-search-query').value = '';
+
+ // Extract ID from URL patterns:
+ // https://jellyfin.example.com/web/#/details?id=XXXXX&serverId=...
+ // https://jellyfin.example.com/web/index.html#!/details?id=XXXXX
+ let jellyfinId = null;
+
+ try {
+ const idMatch = url.match(/[?&]id=([a-f0-9]+)/i);
+ if (idMatch) {
+ jellyfinId = idMatch[1];
+ }
+ } catch (e) {
+ // Invalid URL format
+ }
+
+ if (!jellyfinId) {
+ document.getElementById('map-search-results').innerHTML = 'Could not extract track ID from URL. Make sure it contains "?id=..."
';
+ document.getElementById('map-selected-jellyfin-id').value = '';
+ document.getElementById('map-save-btn').disabled = true;
+ return;
+ }
+
+ // Fetch track details to show preview
+ document.getElementById('map-search-results').innerHTML = ' Loading track details...
';
+
+ try {
+ const res = await fetch('/api/admin/jellyfin/track/' + jellyfinId);
+ const track = await res.json();
+
+ if (res.ok && track.id) {
+ document.getElementById('map-selected-jellyfin-id').value = track.id;
+ document.getElementById('map-save-btn').disabled = false;
+
+ document.getElementById('map-search-results').innerHTML = `
+
+
+
${escapeHtml(track.title)}
+ ${escapeHtml(track.artist)}
+
+
+ ${track.album ? escapeHtml(track.album) : ''}
+
+
+
+ โ Track loaded from URL. Click "Save Mapping" to confirm.
+
+ `;
+ } else {
+ document.getElementById('map-search-results').innerHTML = 'Track not found in Jellyfin
';
+ document.getElementById('map-selected-jellyfin-id').value = '';
+ document.getElementById('map-save-btn').disabled = true;
+ }
+ } catch (error) {
+ document.getElementById('map-search-results').innerHTML = 'Failed to load track details
';
+ document.getElementById('map-selected-jellyfin-id').value = '';
+ document.getElementById('map-save-btn').disabled = true;
+ }
+ }
+
function selectJellyfinTrack(jellyfinId, element) {
// Remove selection from all tracks
document.querySelectorAll('#map-search-results .track-item').forEach(el => {