From aed9c581fd1ca3efb80aa9a528dddcb8419bdca1 Mon Sep 17 00:00:00 2001 From: TheGeneralist <180094941+thegeneralist01@users.noreply.github.com> Date: Mon, 20 Jul 2026 23:04:15 +0200 Subject: [PATCH] doc(server): scope per_item_quality guarantee to the UI The server validates per_item_quality value shapes but does not enforce that every playlist item has an entry. Items without an override get the global quality as a yt-dlp cap with graceful fallback. The 'must choose quality for unsupported videos' invariant is a UI constraint enforced by the frontend before submission. A direct API caller bypassing the UI accepts yt-dlp's standard cap-and-fallback behavior. Document this scope explicitly so the gap is intentional, not accidental. --- crates/archivr-server/src/routes.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/archivr-server/src/routes.rs b/crates/archivr-server/src/routes.rs index 8d26d75..a7bb4f6 100644 --- a/crates/archivr-server/src/routes.rs +++ b/crates/archivr-server/src/routes.rs @@ -872,6 +872,13 @@ async fn capture_handler( ))); } } + // NOTE: the server does not enforce that every playlist item has a per_item_quality + // entry. Items without an override receive the global `quality` value, which + // yt-dlp applies as a format-selector cap (e.g. bestvideo[height<=1080]) and + // falls back gracefully to the best available format below that cap. The + // "must choose quality for unsupported videos" invariant is enforced by the + // frontend before submission; a direct API caller bypassing the UI accepts + // yt-dlp's standard cap-and-fallback behavior. let mounted = mounted_archive(&state, &archive_id)?; let archive_paths = archive::read_archive_paths(&mounted.archive_path).map_err(ApiError::from)?;