Add duplicate check before downloading tracks

Before starting yt-dlp, check if Artist/Album/Title.{ext} already
exists on disk. If found, log a skip message and return early instead
of re-downloading and overwriting the existing file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-04-26 13:53:03 +02:00
1 parent 023d3710ab
commit f08303753c
1 file changed
+18 -4
+18 -4
View File
@@ -107,6 +107,14 @@ async function downloadArtwork(url, dir) {
}); });
} }
const AUDIO_EXTS = ['mp3', 'flac', 'opus', 'm4a', 'ogg', 'wav'];
function findExistingTrack(dir, trackPrefix, safeTitle) {
return AUDIO_EXTS
.map(ext => path.join(dir, `${trackPrefix}${safeTitle}.${ext}`))
.find(f => fs.existsSync(f)) || null;
}
// Download a single track: yt-dlp audio + ffmpeg clean metadata + iTunes cover embedded // Download a single track: yt-dlp audio + ffmpeg clean metadata + iTunes cover embedded
async function downloadTrack({ jobId, artist, albumArtist, title, album, year, trackNum, totalTracks, discNum, discTotal, compilation, genre, artworkUrl, outputDir }) { async function downloadTrack({ jobId, artist, albumArtist, title, album, year, trackNum, totalTracks, discNum, discTotal, compilation, genre, artworkUrl, outputDir }) {
const mainArtist = albumArtist || artist; const mainArtist = albumArtist || artist;
@@ -115,8 +123,15 @@ async function downloadTrack({ jobId, artist, albumArtist, title, album, year, t
const dir = path.join(outputDir || CONFIG.musicPath, safeArtist, safeAlbum); const dir = path.join(outputDir || CONFIG.musicPath, safeArtist, safeAlbum);
fs.mkdirSync(dir, { recursive: true }); fs.mkdirSync(dir, { recursive: true });
const safeTitle = sanitize(title); const safeTitle = sanitize(title);
const trackPrefix = trackNum ? String(trackNum).padStart(2, '0') + ' - ' : ''; const trackPrefix = trackNum ? String(trackNum).padStart(2, '0') + ' - ' : '';
const existing = findExistingTrack(dir, trackPrefix, safeTitle);
if (existing) {
log(jobId, `⏭ Bereits vorhanden: ${path.basename(existing)} — übersprungen`);
return { success: true, dir, skipped: true };
}
const outputTemplate = path.join(dir, `${trackPrefix}${safeTitle}.%(ext)s`); const outputTemplate = path.join(dir, `${trackPrefix}${safeTitle}.%(ext)s`);
const query = `${mainArtist} - ${title} official audio`; const query = `${mainArtist} - ${title} official audio`;
log(jobId, `🔍 Suche: "${query}"`); log(jobId, `🔍 Suche: "${query}"`);
@@ -156,9 +171,8 @@ async function downloadTrack({ jobId, artist, albumArtist, title, album, year, t
}); });
// Step 2: find the audio file yt-dlp wrote (newest audio file in dir) // Step 2: find the audio file yt-dlp wrote (newest audio file in dir)
const audioExts = ['mp3', 'flac', 'opus', 'm4a', 'ogg', 'wav'];
const audioFile = fs.readdirSync(dir) const audioFile = fs.readdirSync(dir)
.filter(f => audioExts.some(e => f.endsWith(`.${e}`))) .filter(f => AUDIO_EXTS.some(e => f.endsWith(`.${e}`)))
.map(f => path.join(dir, f)) .map(f => path.join(dir, f))
.sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs)[0]; .sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs)[0];