fix(ui): playlist search with artist+title, artist in missing list, no bounce on job cards
- Playlist track search: use 'Artist Title' query + songCount=10 (was title-only + 5) fixes songs like 'Dead' by Geoxor being missed due to common-word collision - Missing tracks now show 'Artist – Title' instead of just title - renderJobs: update existing cards instead of full innerHTML wipe every 1.5s eliminates slideUp animation re-triggering on every poll tick Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
4b6095f213
commit
cf8ba70af8
1 file changed
+22
-8
@@ -355,16 +355,19 @@ async function _createNdPlaylist(tracks, name) {
|
|||||||
const norm = s => s?.toLowerCase().trim() || '';
|
const norm = s => s?.toLowerCase().trim() || '';
|
||||||
for (const t of tracks) {
|
for (const t of tracks) {
|
||||||
if (!t.trackName) continue;
|
if (!t.trackName) continue;
|
||||||
|
const missingLabel = t.artistName ? `${t.artistName} – ${t.trackName}` : t.trackName;
|
||||||
try {
|
try {
|
||||||
const r = await api('search3', `&query=${encodeURIComponent(t.trackName)}&songCount=5&albumCount=0&artistCount=0`);
|
// Search with artist+title first for precision, fall back to title-only with more results
|
||||||
|
const artistQuery = t.artistName ? `${t.artistName} ${t.trackName}` : t.trackName;
|
||||||
|
const r = await api('search3', `&query=${encodeURIComponent(artistQuery)}&songCount=10&albumCount=0&artistCount=0`);
|
||||||
const songs = r.searchResult3?.song || [];
|
const songs = r.searchResult3?.song || [];
|
||||||
const match = songs.find(s =>
|
const match = songs.find(s =>
|
||||||
norm(s.title) === norm(t.trackName) &&
|
norm(s.title) === norm(t.trackName) &&
|
||||||
norm(s.artist).split(' ')[0] === norm(t.artistName).split(' ')[0]
|
norm(s.artist).split(' ')[0] === norm(t.artistName).split(' ')[0]
|
||||||
) || songs.find(s => norm(s.title) === norm(t.trackName));
|
) || songs.find(s => norm(s.title) === norm(t.trackName));
|
||||||
if (match) songIds.push(match.id);
|
if (match) songIds.push(match.id);
|
||||||
else missing.push(t.trackName);
|
else missing.push(missingLabel);
|
||||||
} catch { missing.push(t.trackName); }
|
} catch { missing.push(missingLabel); }
|
||||||
}
|
}
|
||||||
if (!songIds.length) {
|
if (!songIds.length) {
|
||||||
toast('⚠ Keine Tracks in Navidrome gefunden — zuerst Library scannen, dann Playlist manuell anlegen');
|
toast('⚠ Keine Tracks in Navidrome gefunden — zuerst Library scannen, dann Playlist manuell anlegen');
|
||||||
@@ -521,10 +524,22 @@ function updateJob(id, status, msg, progress) {
|
|||||||
}
|
}
|
||||||
function renderJobs() {
|
function renderJobs() {
|
||||||
const panel = document.getElementById('jobs-panel');
|
const panel = document.getElementById('jobs-panel');
|
||||||
panel.innerHTML = '';
|
const activeIds = new Set(Object.keys(S.jobs));
|
||||||
Object.entries(S.jobs).forEach(([id,j]) => {
|
|
||||||
const c = document.createElement('div'); c.className = 'job-card';
|
// Remove cards whose jobs are gone
|
||||||
const isDone=j.status==='done', isErr=j.status==='error';
|
panel.querySelectorAll('[data-job-id]').forEach(el => {
|
||||||
|
if (!activeIds.has(el.dataset.jobId)) el.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.entries(S.jobs).forEach(([id, j]) => {
|
||||||
|
let c = panel.querySelector(`[data-job-id="${id}"]`);
|
||||||
|
if (!c) {
|
||||||
|
c = document.createElement('div');
|
||||||
|
c.className = 'job-card';
|
||||||
|
c.dataset.jobId = id;
|
||||||
|
panel.appendChild(c);
|
||||||
|
}
|
||||||
|
const isDone = j.status === 'done', isErr = j.status === 'error';
|
||||||
const statusText = isErr ? 'Fehler' : isDone ? '✓ Fertig! Bibliothek wird gescannt…' : j.msg || 'Wird heruntergeladen…';
|
const statusText = isErr ? 'Fehler' : isDone ? '✓ Fertig! Bibliothek wird gescannt…' : j.msg || 'Wird heruntergeladen…';
|
||||||
c.innerHTML = `<div class="job-header">
|
c.innerHTML = `<div class="job-header">
|
||||||
<div class="job-title">${esc(j.title)}</div>
|
<div class="job-title">${esc(j.title)}</div>
|
||||||
@@ -532,7 +547,6 @@ function renderJobs() {
|
|||||||
</div>
|
</div>
|
||||||
<div class="job-bar"><div class="job-fill ${isDone?'done':isErr?'error':''}" style="width:${isDone?100:isErr?100:j.progress}%"></div></div>
|
<div class="job-bar"><div class="job-fill ${isDone?'done':isErr?'error':''}" style="width:${isDone?100:isErr?100:j.progress}%"></div></div>
|
||||||
<div class="job-sub">${statusText}</div>`;
|
<div class="job-sub">${statusText}</div>`;
|
||||||
panel.appendChild(c);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
async function pollJob(jobId) {
|
async function pollJob(jobId) {
|
||||||
|
|||||||
Reference in new issue
Block a user