Skip to content

Commit 318adef

Browse files
author
houssemko
committed
Explain format rejections; reseed name on audio toggle
1 parent de91475 commit 318adef

4 files changed

Lines changed: 116 additions & 1 deletion

File tree

‎po/grab.pot‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,3 +981,23 @@ msgstr ""
981981
#: src/preferences.rs:649
982982
msgid "Couldn't check for updates"
983983
msgstr ""
984+
985+
#: src/video.rs:340
986+
msgid "No suitable formats found for this media ({total} listed: {reasons})"
987+
msgstr ""
988+
989+
#: src/video.rs:330
990+
msgid "manifest"
991+
msgstr ""
992+
993+
#: src/video.rs:331
994+
msgid "DRM"
995+
msgstr ""
996+
997+
#: src/video.rs:332
998+
msgid "no link"
999+
msgstr ""
1000+
1001+
#: src/video.rs:333
1002+
msgid "video-only"
1003+
msgstr ""

‎src/video.rs‎

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,56 @@ impl VideoError {
292292
fn unavailable() -> Self {
293293
Self::Message(gettext("No suitable formats found for this media"))
294294
}
295+
/// Same failure with a rejection census, so a page of manifest-only
296+
/// variants (live/HLS pages) reads differently from a DRM or
297+
/// link-less one instead of guessing.
298+
fn unavailable_detail(formats: &[Format]) -> Self {
299+
let total = formats.len();
300+
if total == 0 {
301+
return Self::Message(gettext(
302+
"No suitable formats found for this media (the page listed none)",
303+
));
304+
}
305+
let (mut manifest, mut drm, mut no_link, mut video_only) = (0, 0, 0, 0);
306+
for f in formats {
307+
if f.protocol != Protocol::Https {
308+
manifest += 1;
309+
} else if matches!(f.has_drm, Some(DrmStatus::Yes)) {
310+
drm += 1;
311+
} else if f
312+
.download_info
313+
.url
314+
.as_deref()
315+
.filter(|u| !u.is_empty())
316+
.is_none()
317+
{
318+
no_link += 1;
319+
} else if f
320+
.codec_info
321+
.audio_codec
322+
.as_deref()
323+
.is_none_or(|c| c == "none")
324+
{
325+
video_only += 1;
326+
}
327+
}
328+
let mut reasons = Vec::new();
329+
for (n, label) in [
330+
(manifest, gettext("manifest")),
331+
(drm, gettext("DRM")),
332+
(no_link, gettext("no link")),
333+
(video_only, gettext("video-only")),
334+
] {
335+
if n > 0 {
336+
reasons.push(format!("{label}: {n}"));
337+
}
338+
}
339+
Self::Message(
340+
gettext("No suitable formats found for this media ({total} listed: {reasons})")
341+
.replace("{total}", &total.to_string())
342+
.replace("{reasons}", &reasons.join(", ")),
343+
)
344+
}
295345
fn part_failed(e: impl std::fmt::Display) -> Self {
296346
Self::Message(
297347
gettext("Media download failed: {detail}").replace("{detail}", &e.to_string()),
@@ -1570,7 +1620,7 @@ pub async fn run_video_download(
15701620
}
15711621
}
15721622
let Some(audio_sel) = audio_sel else {
1573-
return Err(VideoError::unavailable());
1623+
return Err(VideoError::unavailable_detail(&video.formats));
15741624
};
15751625

15761626
tracing::info!(

‎src/video_tests.rs‎

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,33 @@ fn video_format_options_lists_best_per_height() {
10021002
assert_eq!(opts[1].label, "720p · av01 · 60.0 MB");
10031003
}
10041004

1005+
#[test]
1006+
fn unavailable_detail_counts_rejections() {
1007+
let mut no_link = test_format_full("n", "avc1", "none", Some(720), None, "https", false);
1008+
no_link.as_object_mut().unwrap().remove("url");
1009+
let formats: Vec<yt_dlp::model::format::Format> = serde_json::from_value(serde_json::json!([
1010+
test_format_full("v", "avc1", "none", Some(720), None, "https", false),
1011+
test_format_full("h", "avc1", "none", Some(720), None, "m3u8_native", false),
1012+
test_format_full("d", "avc1", "none", Some(720), None, "https", true),
1013+
no_link,
1014+
]))
1015+
.unwrap();
1016+
let message = match VideoError::unavailable_detail(&formats) {
1017+
VideoError::Message(m) => m,
1018+
other => panic!("expected message, got {other:?}"),
1019+
};
1020+
assert!(message.contains("4 listed"), "{message}");
1021+
assert!(message.contains("manifest: 1"), "{message}");
1022+
assert!(message.contains("DRM: 1"), "{message}");
1023+
assert!(message.contains("no link: 1"), "{message}");
1024+
assert!(message.contains("video-only: 1"), "{message}");
1025+
let empty = match VideoError::unavailable_detail(&[]) {
1026+
VideoError::Message(m) => m,
1027+
other => panic!("expected message, got {other:?}"),
1028+
};
1029+
assert!(empty.contains("listed none"), "{empty}");
1030+
}
1031+
10051032
#[test]
10061033
fn codec_rank_orders_newest_first() {
10071034
assert!(codec_rank("av01.0.08M.08") < codec_rank("vp9"));

‎src/window.rs‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1798,6 +1798,24 @@ pub fn show_add_dialog(manager: Rc<DownloadManager>) {
17981798
}
17991799
});
18001800
}
1801+
// Toggling the mode re-seeds an untouched name: the resolve-time
1802+
// seed ran under the other mode, so without this the row keeps a
1803+
// .mp4 name for an audio download (or vice versa). An edited name
1804+
// is never clobbered.
1805+
{
1806+
let (name, audio, info) = (step.name.clone(), step.audio.clone(), video_info.clone());
1807+
audio.connect_active_notify(move |sw| {
1808+
if let Some(v) = info.borrow().as_ref() {
1809+
let active = sw.is_active();
1810+
let current = name.text().to_string();
1811+
if current.trim().is_empty()
1812+
|| current == crate::video::default_video_filename(&v.title, !active)
1813+
{
1814+
name.set_text(&crate::video::default_video_filename(&v.title, active));
1815+
}
1816+
}
1817+
});
1818+
}
18011819

18021820
{
18031821
let m = manager.clone();

0 commit comments

Comments
 (0)