From e644c6561bd55122c224fb53c462e32af8540a17 Mon Sep 17 00:00:00 2001 From: houssemko Date: Fri, 18 Sep 2026 10:07:31 +0100 Subject: [PATCH] Best match means best; preference preselects the combo row --- src/video.rs | 24 ++++++++++++++++++++++-- src/video_tests.rs | 39 +++++++++++++++++++++++++++++++++++++++ src/window.rs | 21 ++++++++++++++------- 3 files changed, 75 insertions(+), 9 deletions(-) diff --git a/src/video.rs b/src/video.rs index 443b773da..2f67ae6b4 100644 --- a/src/video.rs +++ b/src/video.rs @@ -1464,9 +1464,29 @@ fn select_muxed_format(formats: &[Format], want: Option) -> Option usize { + let want = match quality_height(quality) { + None => return 0, + Some(h) => h, + }; + formats + .iter() + .enumerate() + .map(|(i, opt)| (i + 1, opt.height)) + .min_by_key(|(_, h)| (h.abs_diff(want), std::cmp::Reverse(*h))) + .map(|(i, _)| i) + .unwrap_or(0) +} + /// Stored quality value to a height cap: `None` (Best) takes the -/// tallest variant available. -fn quality_height(value: &str) -> Option { +/// tallest variant available. Unknown values fall back to 1080p (same +/// fallback as the combo mapping and the extractor selector). +pub(crate) fn quality_height(value: &str) -> Option { match value { "best" => None, "2160p" => Some(2160), diff --git a/src/video_tests.rs b/src/video_tests.rs index 992515cd2..0f17a34ab 100644 --- a/src/video_tests.rs +++ b/src/video_tests.rs @@ -2556,3 +2556,42 @@ fn resolve_hls_input_prefers_binary_dump() { assert_eq!(input.referer.as_deref(), Some("https://www.tiktok.com/")); let _ = std::fs::remove_dir_all(&dir); } + +// ── default combo selection ────────────────────────────────────────── + +fn test_options() -> Vec { + [480u32, 720, 1080] + .iter() + .map(|h| VideoFormatOption { + id: format!("v{h}"), + label: format!("{h}p"), + height: *h, + }) + .collect() +} + +#[test] +fn default_quality_index_preselects() { + let opts = test_options(); + // Best (and empty listings) stay on "Best match". + assert_eq!(default_quality_index(&opts, "best"), 0); + assert_eq!(default_quality_index(&[], "720p"), 0); + // Otherwise the closest listed height wins (combo index 1-based). + assert_eq!(default_quality_index(&opts, "1080p"), 3); + assert_eq!(default_quality_index(&opts, "720p"), 2); + assert_eq!(default_quality_index(&opts, "480p"), 1); + // Between buckets the nearer height wins, ties go taller. + assert_eq!(default_quality_index(&opts, "2160p"), 3); + // Unknown stored values degrade like the extractor selector (1080p). + assert_eq!(default_quality_index(&opts, "mystery"), 3); + // Exact ties (odd extractor heights equidistant from the cap) go taller. + let odd = [600u32, 840] + .iter() + .map(|h| VideoFormatOption { + id: format!("v{h}"), + label: format!("{h}p"), + height: *h, + }) + .collect::>(); + assert_eq!(default_quality_index(&odd, "720p"), 2); +} diff --git a/src/window.rs b/src/window.rs index c56ca9d3b..eea35de20 100644 --- a/src/window.rs +++ b/src/window.rs @@ -1677,7 +1677,12 @@ pub fn show_add_dialog(manager: Rc) { .quality .set_model(Some(>k4::StringList::new(&refs))); *formats_b.borrow_mut() = ids; - step_b.quality.set_selected(0); + step_b + .quality + .set_selected(crate::video::default_quality_index( + &v.formats, + &settings_b.video_quality(), + ) as u32); *info_b.borrow_mut() = Some(v); show_video_ready(&step_b); set_lookup_add(&lookup_add_b, true); @@ -2058,15 +2063,17 @@ pub fn show_add_dialog(manager: Rc) { } else { Some(typed.as_str()) }; - // The fallback quality follows the picked format's - // height, so a dropped pin still degrades to the - // chosen height; "Best match" (index 0) keeps the - // live global preference. The combo lists Best - // match first, then the info formats in order. + // "Best match" (index 0) means best available, + // not the global preference: the preference + // already preselected a row at resolve time. + // Exact picks carry their height as the + // fallback, so a dropped pin still degrades to + // the chosen height. The combo lists Best match + // first, then the info formats in order. let selected = step2.quality.selected() as usize; let format_id = formats.borrow().get(selected).cloned().flatten(); let quality = match selected { - 0 => m.settings().video_quality(), + 0 => "best".to_string(), i => v .formats .get(i - 1)