Clarify mirrored playlist auto-sync action
Rename the manual pipeline button to Auto-Sync and make non-JSON endpoint failures show an actionable restart message instead of a raw JSON parse error.
This commit is contained in:
parent
a1409576f4
commit
46a0999ca2
2 changed files with 26 additions and 10 deletions
|
|
@ -516,7 +516,7 @@ function renderMirroredCard(p, container) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
${disc > 0 ? `<button class="mirrored-card-clear" onclick="event.stopPropagation(); clearMirroredDiscovery(${p.id}, '${_escAttr(p.name)}')" title="Clear discovery data">↺</button>` : ''}
|
${disc > 0 ? `<button class="mirrored-card-clear" onclick="event.stopPropagation(); clearMirroredDiscovery(${p.id}, '${_escAttr(p.name)}')" title="Clear discovery data">↺</button>` : ''}
|
||||||
<button class="mirrored-card-pipeline" onclick="event.stopPropagation(); runMirroredPlaylistPipeline(${p.id}, '${_escAttr(p.name)}')" title="Run refresh, discover, sync, and wishlist">Run</button>
|
<button class="mirrored-card-pipeline" onclick="event.stopPropagation(); runMirroredPlaylistPipeline(${p.id}, '${_escAttr(p.name)}')" title="Refresh, discover, sync, and queue missing tracks">Auto-Sync</button>
|
||||||
<button class="mirrored-card-link" onclick="event.stopPropagation(); editMirroredSourceRef(${p.id}, '${_escAttr(p.name)}', '${_escAttr(p.source)}', '${_escAttr(sourceRef)}')" title="Edit original playlist link">🔗</button>
|
<button class="mirrored-card-link" onclick="event.stopPropagation(); editMirroredSourceRef(${p.id}, '${_escAttr(p.name)}', '${_escAttr(p.source)}', '${_escAttr(sourceRef)}')" title="Edit original playlist link">🔗</button>
|
||||||
<button class="mirrored-card-delete" onclick="event.stopPropagation(); deleteMirroredPlaylist(${p.id}, '${_escAttr(p.name)}')" title="Delete mirror">✕</button>
|
<button class="mirrored-card-delete" onclick="event.stopPropagation(); deleteMirroredPlaylist(${p.id}, '${_escAttr(p.name)}')" title="Delete mirror">✕</button>
|
||||||
`;
|
`;
|
||||||
|
|
@ -570,6 +570,25 @@ function getMirroredSourceRef(p) {
|
||||||
return (p && p.source_playlist_id) ? String(p.source_playlist_id) : '';
|
return (p && p.source_playlist_id) ? String(p.source_playlist_id) : '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function parseMirroredPipelineResponse(res, fallbackMessage) {
|
||||||
|
const text = await res.text();
|
||||||
|
let data = {};
|
||||||
|
if (text) {
|
||||||
|
try {
|
||||||
|
data = JSON.parse(text);
|
||||||
|
} catch (_err) {
|
||||||
|
const detail = res.status === 404
|
||||||
|
? 'Auto-Sync endpoint not found. Restart the SoulSync server so the new backend routes load.'
|
||||||
|
: fallbackMessage;
|
||||||
|
throw new Error(detail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!res.ok || data.error) {
|
||||||
|
throw new Error(data.error || fallbackMessage);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
async function editMirroredSourceRef(playlistId, name, source, currentRef) {
|
async function editMirroredSourceRef(playlistId, name, source, currentRef) {
|
||||||
const label = (source === 'spotify_public' || source === 'youtube')
|
const label = (source === 'spotify_public' || source === 'youtube')
|
||||||
? 'original playlist URL'
|
? 'original playlist URL'
|
||||||
|
|
@ -634,12 +653,9 @@ async function runMirroredPlaylistPipeline(playlistId, name) {
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({})
|
body: JSON.stringify({})
|
||||||
});
|
});
|
||||||
const data = await res.json();
|
const data = await parseMirroredPipelineResponse(res, 'Failed to start Auto-Sync');
|
||||||
if (!res.ok || data.error) {
|
|
||||||
throw new Error(data.error || 'Failed to start pipeline');
|
|
||||||
}
|
|
||||||
applyMirroredPipelineState(playlistId, data.state || { status: 'running', progress: 0, phase: 'Starting pipeline...' });
|
applyMirroredPipelineState(playlistId, data.state || { status: 'running', progress: 0, phase: 'Starting pipeline...' });
|
||||||
showToast(`Pipeline started for ${name}`, 'success');
|
showToast(`Auto-Sync started for ${name}`, 'success');
|
||||||
pollMirroredPipelineStatus(playlistId, name);
|
pollMirroredPipelineStatus(playlistId, name);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showToast(`Error: ${err.message}`, 'error');
|
showToast(`Error: ${err.message}`, 'error');
|
||||||
|
|
@ -653,14 +669,13 @@ function pollMirroredPipelineStatus(playlistId, name) {
|
||||||
const tick = async () => {
|
const tick = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch(`/api/mirrored-playlists/${playlistId}/pipeline/status`);
|
const res = await fetch(`/api/mirrored-playlists/${playlistId}/pipeline/status`);
|
||||||
const state = await res.json();
|
const state = await parseMirroredPipelineResponse(res, 'Failed to read Auto-Sync status');
|
||||||
if (!res.ok || state.error) throw new Error(state.error || 'Failed to read pipeline status');
|
|
||||||
applyMirroredPipelineState(playlistId, state);
|
applyMirroredPipelineState(playlistId, state);
|
||||||
|
|
||||||
if (state.status === 'finished') {
|
if (state.status === 'finished') {
|
||||||
clearInterval(mirroredPipelinePollers[key]);
|
clearInterval(mirroredPipelinePollers[key]);
|
||||||
delete mirroredPipelinePollers[key];
|
delete mirroredPipelinePollers[key];
|
||||||
showToast(`Pipeline complete for ${name}`, 'success');
|
showToast(`Auto-Sync complete for ${name}`, 'success');
|
||||||
loadMirroredPlaylists();
|
loadMirroredPlaylists();
|
||||||
} else if (state.status === 'error' || state.status === 'skipped') {
|
} else if (state.status === 'error' || state.status === 'skipped') {
|
||||||
clearInterval(mirroredPipelinePollers[key]);
|
clearInterval(mirroredPipelinePollers[key]);
|
||||||
|
|
@ -990,7 +1005,7 @@ async function openMirroredPlaylistModal(playlistId) {
|
||||||
</div>
|
</div>
|
||||||
<div class="mirrored-modal-footer-right" style="display:flex;gap:10px;">
|
<div class="mirrored-modal-footer-right" style="display:flex;gap:10px;">
|
||||||
<button class="mirrored-btn-close" onclick="editMirroredSourceRef(${playlistId}, '${_escAttr(data.name)}', '${_escAttr(source)}', '${_escAttr(sourceRef)}')">Edit Source</button>
|
<button class="mirrored-btn-close" onclick="editMirroredSourceRef(${playlistId}, '${_escAttr(data.name)}', '${_escAttr(source)}', '${_escAttr(sourceRef)}')">Edit Source</button>
|
||||||
<button class="mirrored-btn-pipeline" onclick="runMirroredPlaylistPipeline(${playlistId}, '${_escAttr(data.name)}')">Run Pipeline</button>
|
<button class="mirrored-btn-pipeline" onclick="runMirroredPlaylistPipeline(${playlistId}, '${_escAttr(data.name)}')">Auto-Sync</button>
|
||||||
<button class="mirrored-btn-close" onclick="closeMirroredModal()">Close</button>
|
<button class="mirrored-btn-close" onclick="closeMirroredModal()">Close</button>
|
||||||
<button class="mirrored-btn-discover" onclick="discoverMirroredPlaylist(${playlistId})">Discover</button>
|
<button class="mirrored-btn-discover" onclick="discoverMirroredPlaylist(${playlistId})">Discover</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -12056,6 +12056,7 @@ body.helper-mode-active #dashboard-activity-feed:hover {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
|
min-width: 76px;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue