diff --git a/src-tauri/src/extension_server.rs b/src-tauri/src/extension_server.rs index 0b0a179..841d415 100644 --- a/src-tauri/src/extension_server.rs +++ b/src-tauri/src/extension_server.rs @@ -315,7 +315,13 @@ fn normalize_download(payload: ExtensionRequest) -> Option { silent: payload.silent, filename, headers: payload.headers.filter(|value| !value.trim().is_empty()), - cookies: payload.cookies.filter(|value| !value.trim().is_empty()), + // A full browser Cookie header can exceed upstream request-header + // limits. Media uses yt-dlp's configured browser-cookie source + // instead; regular captured downloads retain their exact cookies. + cookies: (!payload.media) + .then_some(payload.cookies) + .flatten() + .filter(|value| !value.trim().is_empty()), media: payload.media, }) } @@ -449,8 +455,8 @@ fn is_allowed_origin(origin: &str) -> bool { #[cfg(test)] mod tests { use super::{ - add_server_identity, is_valid_client_nonce, sign_server_proof, PROTOCOL_VERSION_HEADER, - SERVER_HEADER, + add_server_identity, is_valid_client_nonce, normalize_download, sign_server_proof, + ExtensionRequest, PROTOCOL_VERSION_HEADER, SERVER_HEADER, }; use axum::{http::StatusCode, middleware, routing::get, Router}; use hmac::{Hmac, KeyInit, Mac}; @@ -492,6 +498,24 @@ mod tests { assert!(!is_valid_client_nonce("0123456789abcdef0123456789abcdeg")); } + #[test] + fn explicit_media_drops_the_extension_cookie_header() { + let download = normalize_download(ExtensionRequest { + urls: vec!["https://www.youtube.com/watch?v=example".to_string()], + referer: None, + silent: false, + filename: None, + headers: Some("User-Agent: Firefox".to_string()), + cookies: Some("large=browser-cookie-header".to_string()), + media: true, + }) + .expect("valid media handoff"); + + assert!(download.media); + assert!(download.cookies.is_none()); + assert_eq!(download.headers.as_deref(), Some("User-Agent: Firefox")); + } + #[test] fn signs_server_proof_with_timestamp_nonce_and_bound_port() { let token = Arc::new(RwLock::new("pairing-token".to_string())); diff --git a/src/store/useDownloadStore.test.ts b/src/store/useDownloadStore.test.ts index c874d0f..fd4965c 100644 --- a/src/store/useDownloadStore.test.ts +++ b/src/store/useDownloadStore.test.ts @@ -818,6 +818,7 @@ describe('useDownloadStore', () => { expect(state.isAddModalOpen).toBe(true); expect(state.pendingAddUrls).toBe('https://adult.example/watch/123'); expect(state.pendingAddMediaUrls).toEqual(['https://adult.example/watch/123']); + expect(state.pendingAddCookies).toBe(''); }); it('deduplicates forced media URLs and drops stale media intent when opening fresh', async () => { diff --git a/src/store/useDownloadStore.ts b/src/store/useDownloadStore.ts index 8bea402..d56d8a6 100644 --- a/src/store/useDownloadStore.ts +++ b/src/store/useDownloadStore.ts @@ -552,12 +552,17 @@ export const useDownloadStore = create((set, get) => ({ const urls = [...new Set(request.urls.map(url => url.trim()).filter(Boolean))]; if (urls.length === 0) return; + // Explicit media uses yt-dlp and its configured browser-cookie source. + // Passing Firefox's complete page Cookie header can exceed YouTube's + // request-header limit; ordinary captured file downloads keep it. + const cookies = request.media === true ? null : request.cookies; + get().openAddModalWithUrls( urls.join('\n'), request.referer, urls.length === 1 ? request.filename : null, request.headers, - request.cookies, + cookies, request.media === true ); },