From 0ea61a29a1dc7efdf6021fc315bfd92e2f830832 Mon Sep 17 00:00:00 2001 From: TheGeneralist <180094941+thegeneralist01@users.noreply.github.com> Date: Mon, 20 Jul 2026 22:47:37 +0200 Subject: [PATCH] fix(core): ignore per_item_quality for YTM playlist items YouTube Music playlists force child_quality = Some("audio") because yt-dlp can't download DRM-free audio-only tracks any other way. The previous per_item_quality lookup could override this with e.g. "best", defeating the invariant. Guard the lookup behind !is_audio so YTM items are always downloaded as audio regardless of what the caller sends. --- crates/archivr-core/src/capture.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/crates/archivr-core/src/capture.rs b/crates/archivr-core/src/capture.rs index 20865ed..72b7af1 100644 --- a/crates/archivr-core/src/capture.rs +++ b/crates/archivr-core/src/capture.rs @@ -1176,12 +1176,19 @@ pub fn perform_capture( None => playlist_item.title.clone(), }; - // Per-item quality override keyed by yt-dlp video ID; fall back to playlist-level. - let effective_child_quality: Option<&str> = config - .per_item_quality - .get(&playlist_item.id) - .map(String::as_str) - .or(child_quality); + // Per-item quality override keyed by yt-dlp video ID; fall back to + // playlist-level quality. YTM playlists are always audio-only — + // per_item_quality overrides are ignored so the audio-only guarantee + // cannot be bypassed by a caller sending e.g. "best". + let effective_child_quality: Option<&str> = if is_audio { + Some("audio") + } else { + config + .per_item_quality + .get(&playlist_item.id) + .map(String::as_str) + .or(child_quality) + }; // Download the media. match downloader::ytdlp::download(