fix: correct yt-dlp duration filter — handle exit code 101, remove --playlist-items from filtered search
--playlist-items 1 in baseArgs caused filter to only check result #1 (filter useless). --max-downloads 1 exits with code 101 which we treated as an error — ffmpeg never ran, leaving untagged files (→ Unknown Artist/Album in Navidrome). Now code 101 resolves successfully and filtered search uses commonArgs without --playlist-items. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
fb02d3faf4
commit
03394cac68
1 file changed
+9
-7
@@ -182,16 +182,16 @@ async function downloadTrack({ jobId, artist, albumArtist, title, album, year, t
|
|||||||
const query = `${mainArtist} - ${title} official audio`;
|
const query = `${mainArtist} - ${title} official audio`;
|
||||||
|
|
||||||
// Step 1: yt-dlp — audio only, no thumbnail (we embed iTunes artwork ourselves)
|
// Step 1: yt-dlp — audio only, no thumbnail (we embed iTunes artwork ourselves)
|
||||||
const baseArgs = [
|
const commonArgs = [
|
||||||
'--extract-audio',
|
'--extract-audio',
|
||||||
'--audio-format', CONFIG.audioFmt,
|
'--audio-format', CONFIG.audioFmt,
|
||||||
'--audio-quality', CONFIG.audioQuality,
|
'--audio-quality', CONFIG.audioQuality,
|
||||||
'-o', outputTemplate,
|
'-o', outputTemplate,
|
||||||
'--no-playlist',
|
|
||||||
'--playlist-items', '1',
|
|
||||||
'--no-warnings',
|
'--no-warnings',
|
||||||
'--newline',
|
'--newline',
|
||||||
];
|
];
|
||||||
|
// --no-playlist + --playlist-items 1 only for single-result searches (prevents playlist bleed)
|
||||||
|
const singleArgs = [...commonArgs, '--no-playlist', '--playlist-items', '1'];
|
||||||
|
|
||||||
const spawnYtdlp = (args) => new Promise((resolve, reject) => {
|
const spawnYtdlp = (args) => new Promise((resolve, reject) => {
|
||||||
const proc = spawn(CONFIG.ytdlpBin, args, { env: { ...process.env, PYTHONUNBUFFERED: '1' } });
|
const proc = spawn(CONFIG.ytdlpBin, args, { env: { ...process.env, PYTHONUNBUFFERED: '1' } });
|
||||||
@@ -210,8 +210,9 @@ async function downloadTrack({ jobId, artist, albumArtist, title, album, year, t
|
|||||||
.forEach(l => log(jobId, l.trim()));
|
.forEach(l => log(jobId, l.trim()));
|
||||||
});
|
});
|
||||||
proc.on('error', reject);
|
proc.on('error', reject);
|
||||||
|
// code 101 = --max-downloads limit reached (success — file was downloaded)
|
||||||
proc.on('close', code =>
|
proc.on('close', code =>
|
||||||
code === 0 ? resolve() : reject(new Error(`yt-dlp code ${code}: ${stderr.slice(-300)}`))
|
(code === 0 || code === 101) ? resolve() : reject(new Error(`yt-dlp code ${code}: ${stderr.slice(-300)}`))
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -220,21 +221,22 @@ async function downloadTrack({ jobId, artist, albumArtist, title, album, year, t
|
|||||||
const minDur = Math.max(30, Math.round(durationSec * 0.6));
|
const minDur = Math.max(30, Math.round(durationSec * 0.6));
|
||||||
const maxDur = Math.round(durationSec * 1.5);
|
const maxDur = Math.round(durationSec * 1.5);
|
||||||
log(jobId, `🔍 Suche (~${durationSec}s): "${query}"`);
|
log(jobId, `🔍 Suche (~${durationSec}s): "${query}"`);
|
||||||
|
// Search 5 results, pick first matching duration — no --playlist-items so filter sees all 5
|
||||||
await spawnYtdlp([
|
await spawnYtdlp([
|
||||||
`ytsearch5:${query}`,
|
`ytsearch5:${query}`,
|
||||||
'--match-filter', `duration > ${minDur} & duration < ${maxDur} & !is_live`,
|
'--match-filter', `duration > ${minDur} & duration < ${maxDur} & !is_live`,
|
||||||
'--max-downloads', '1',
|
'--max-downloads', '1',
|
||||||
...baseArgs,
|
...commonArgs,
|
||||||
]);
|
]);
|
||||||
// Fallback if duration filter matched nothing
|
// Fallback if duration filter matched nothing
|
||||||
const hasFile = fs.readdirSync(dir).some(f => AUDIO_EXTS.some(e => f.endsWith(`.${e}`)));
|
const hasFile = fs.readdirSync(dir).some(f => AUDIO_EXTS.some(e => f.endsWith(`.${e}`)));
|
||||||
if (!hasFile) {
|
if (!hasFile) {
|
||||||
log(jobId, '⚠️ Kein Treffer im Dauerbereich — Suche ohne Filter…');
|
log(jobId, '⚠️ Kein Treffer im Dauerbereich — Suche ohne Filter…');
|
||||||
await spawnYtdlp([`ytsearch1:${query}`, ...baseArgs]);
|
await spawnYtdlp([`ytsearch1:${query}`, ...singleArgs]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log(jobId, `🔍 Suche: "${query}"`);
|
log(jobId, `🔍 Suche: "${query}"`);
|
||||||
await spawnYtdlp([`ytsearch1:${query}`, ...baseArgs]);
|
await spawnYtdlp([`ytsearch1:${query}`, ...singleArgs]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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)
|
||||||
|
|||||||
Reference in new issue
Block a user