feat: download playlist tracks in parallel batches (MAX_PARALLEL)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
c1a740240a
commit
252d2d3071
1 file changed
+15
-9
@@ -831,18 +831,17 @@ app.post('/api/download', async (req, res) => {
|
|||||||
if (!plTracks.length) throw new Error('Keine Tracks übergeben');
|
if (!plTracks.length) throw new Error('Keine Tracks übergeben');
|
||||||
log(jobId, `🎵 Playlist "${title}" — ${plTracks.length} Tracks`);
|
log(jobId, `🎵 Playlist "${title}" — ${plTracks.length} Tracks`);
|
||||||
let done = 0, skipped = 0;
|
let done = 0, skipped = 0;
|
||||||
for (const track of plTracks) {
|
const CONC = CONFIG.maxParallel || 2;
|
||||||
try {
|
for (let i = 0; i < plTracks.length; i += CONC) {
|
||||||
|
const batch = plTracks.slice(i, i + CONC);
|
||||||
|
const batchResults = await Promise.allSettled(batch.map(async track => {
|
||||||
const trackTitle = track.trackName || '';
|
const trackTitle = track.trackName || '';
|
||||||
// subtitle gives "Artist1, Artist2" — use first for iTunes search, keep full for tags
|
// subtitle gives "Artist1, Artist2" — use first for iTunes search, keep full for tags
|
||||||
const trackArtist = track.artistName || artist || '';
|
const trackArtist = track.artistName || artist || '';
|
||||||
const searchArtist = trackArtist.split(',')[0].trim();
|
const searchArtist = trackArtist.split(',')[0].trim();
|
||||||
|
|
||||||
// Always look up iTunes for correct album, artwork, year (Spotify flat format has none)
|
|
||||||
log(jobId, `📋 iTunes: "${trackArtist} – ${trackTitle}"`);
|
log(jobId, `📋 iTunes: "${trackArtist} – ${trackTitle}"`);
|
||||||
const itunes = await lookupItunesTrackMeta(searchArtist, trackTitle);
|
const itunes = await lookupItunesTrackMeta(searchArtist, trackTitle);
|
||||||
|
return downloadTrack({
|
||||||
const result = await downloadTrack({
|
|
||||||
jobId,
|
jobId,
|
||||||
artist: trackArtist,
|
artist: trackArtist,
|
||||||
albumArtist: trackArtist,
|
albumArtist: trackArtist,
|
||||||
@@ -856,10 +855,17 @@ app.post('/api/download', async (req, res) => {
|
|||||||
explicit: track.trackExplicitness === 'explicit',
|
explicit: track.trackExplicitness === 'explicit',
|
||||||
durationMs: itunes.durationMs || track.durationMs || undefined,
|
durationMs: itunes.durationMs || track.durationMs || undefined,
|
||||||
});
|
});
|
||||||
if (result?.skipped) skipped++; else done++;
|
}));
|
||||||
|
for (let j = 0; j < batchResults.length; j++) {
|
||||||
|
const r = batchResults[j];
|
||||||
|
if (r.status === 'rejected') {
|
||||||
|
log(jobId, `⚠️ Fehler bei "${batch[j].trackName || '?'}": ${r.reason?.message || r.reason}`);
|
||||||
|
} else if (r.value?.skipped) {
|
||||||
|
skipped++;
|
||||||
|
} else {
|
||||||
|
done++;
|
||||||
|
}
|
||||||
updateJob(jobId, { progress: Math.round(((done + skipped) / plTracks.length) * 90) });
|
updateJob(jobId, { progress: Math.round(((done + skipped) / plTracks.length) * 90) });
|
||||||
} catch(e) {
|
|
||||||
log(jobId, `⚠️ Fehler bei "${track.trackName || '?'}": ${e.message}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const allSkipped = skipped === plTracks.length;
|
const allSkipped = skipped === plTracks.length;
|
||||||
|
|||||||
Reference in new issue
Block a user