diff --git a/allstarr/wwwroot/index.html b/allstarr/wwwroot/index.html index 263bb2b..ab2c4e9 100644 --- a/allstarr/wwwroot/index.html +++ b/allstarr/wwwroot/index.html @@ -1174,7 +1174,7 @@
- Map this track to an external provider (SquidWTF, Deezer, or Qobuz). For local Jellyfin tracks, use the Spotify Import plugin instead. + Map this track to an external provider (SquidWTF, Deezer, or Qobuz). For local Jellyfin tracks, use the Jellyfin mapping modal instead.
@@ -1216,6 +1216,43 @@+ Search your Jellyfin library and select a local track to map to this Spotify track. +
+ + +Searching...
'; + + try { + const res = await fetch('/api/admin/jellyfin/search?query=' + encodeURIComponent(query)); + const data = await res.json(); + + if (!res.ok) { + resultsDiv.innerHTML = 'Search failed
'; + return; + } + + if (!data.tracks || data.tracks.length === 0) { + resultsDiv.innerHTML = 'No tracks found
'; + return; + } + + resultsDiv.innerHTML = data.tracks.map(track => ` +Search failed
'; + } } - // Save manual mapping (external only) + // Select a Jellyfin track for mapping + function selectJellyfinTrack(jellyfinId, name, artist) { + document.getElementById('local-map-jellyfin-id').value = jellyfinId; + document.getElementById('local-map-save-btn').disabled = false; + + // Highlight selected track + document.querySelectorAll('#local-map-results > div').forEach(div => { + div.style.background = 'transparent'; + div.style.border = '1px solid var(--border)'; + }); + event.target.closest('div').style.background = 'var(--primary)'; + event.target.closest('div').style.border = '1px solid var(--primary)'; + } + + // Save local Jellyfin mapping + async function saveLocalMapping() { + const playlistName = document.getElementById('local-map-playlist-name').value; + const spotifyId = document.getElementById('local-map-spotify-id').value; + const jellyfinId = document.getElementById('local-map-jellyfin-id').value; + + if (!jellyfinId) { + showToast('Please select a Jellyfin track', 'error'); + return; + } + + const requestBody = { + spotifyId, + jellyfinId + }; + + // Show loading state + const saveBtn = document.getElementById('local-map-save-btn'); + const originalText = saveBtn.textContent; + saveBtn.textContent = 'Saving...'; + saveBtn.disabled = true; + + try { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), 30000); + + const res = await fetch(`/api/admin/playlists/${encodeURIComponent(playlistName)}/map`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(requestBody), + signal: controller.signal + }); + + clearTimeout(timeoutId); + + if (res.ok) { + showToast('Track mapped successfully!', 'success'); + closeModal('local-map-modal'); + + // Refresh the tracks view if it's open + const tracksModal = document.getElementById('tracks-modal'); + if (tracksModal.style.display === 'flex') { + await viewTracks(playlistName); + } + } else { + const data = await res.json(); + showToast(data.error || 'Failed to save mapping', 'error'); + saveBtn.textContent = originalText; + saveBtn.disabled = false; + } + } catch (error) { + if (error.name === 'AbortError') { + showToast('Request timed out. The mapping may still be processing.', 'warning'); + } else { + showToast('Failed to save mapping', 'error'); + } + saveBtn.textContent = originalText; + saveBtn.disabled = false; + } + } + + // Save manual mapping (external only) - kept for backward compatibility async function saveManualMapping() { const playlistName = document.getElementById('map-playlist-name').value; const spotifyId = document.getElementById('map-spotify-id').value;