aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--crates/yt/src/download/progress_hook.rs141
1 files changed, 49 insertions, 92 deletions
diff --git a/crates/yt/src/download/progress_hook.rs b/crates/yt/src/download/progress_hook.rs
index 99d1a74..e5605fd 100644
--- a/crates/yt/src/download/progress_hook.rs
+++ b/crates/yt/src/download/progress_hook.rs
@@ -23,6 +23,29 @@ use crate::{
shared::bytes::Bytes,
};
+macro_rules! json_get_default {
+ ($value:expr, $name:literal, $convert:ident, $default:expr) => {
+ $value.get($name).map_or($default, |v| {
+ if v == &serde_json::Value::Null {
+ $default
+ } else {
+ json_cast!(@log_key $name, v, $convert)
+ }
+ })
+ };
+}
+
+fn format_bytes(bytes: u64) -> String {
+ let bytes = Bytes::new(bytes);
+ bytes.to_string()
+}
+
+fn format_speed(speed: f64) -> String {
+ #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
+ let bytes = Bytes::new(speed.floor() as u64);
+ format!("{bytes}/s")
+}
+
/// # Panics
/// If expectations fail.
#[allow(clippy::needless_pass_by_value)]
@@ -35,110 +58,44 @@ pub(crate) fn progress_hook(
return Ok(());
}
- macro_rules! get {
- (@interrogate $item:ident, $type_fun:ident, $get_fun:ident, $name:expr) => {{
- let a = $item.get($name).expect(concat!(
- "The field '",
- stringify!($name),
- "' should exist."
- ));
-
- if a.$type_fun() {
- a.$get_fun().expect(
- "The should have been checked in the if guard, so unpacking here is fine",
- )
- } else {
- panic!(
- "Value {} => \n{}\n is not of type: {}",
- $name,
- a,
- stringify!($type_fun)
- );
- }
- }};
-
- ($type_fun:ident, $get_fun:ident, $name1:expr, $name2:expr) => {{
- let a = get! {@interrogate input, is_object, as_object, $name1};
- let b = get! {@interrogate a, $type_fun, $get_fun, $name2};
- b
- }};
-
- ($type_fun:ident, $get_fun:ident, $name:expr) => {{
- get! {@interrogate input, $type_fun, $get_fun, $name}
- }};
- }
-
- macro_rules! default_get {
- (@interrogate $item:ident, $default:expr, $get_fun:ident, $name:expr) => {{
- let a = if let Some(field) = $item.get($name) {
- field.$get_fun().unwrap_or($default)
- } else {
- $default
- };
- a
- }};
-
- ($get_fun:ident, $default:expr, $name1:expr, $name2:expr) => {{
- let a = get! {@interrogate input, is_object, as_object, $name1};
- let b = default_get! {@interrogate a, $default, $get_fun, $name2};
- b
- }};
-
- ($get_fun:ident, $default:expr, $name:expr) => {{
- default_get! {@interrogate input, $default, $get_fun, $name}
- }};
- }
-
- macro_rules! c {
- ($color:expr, $format:expr) => {
- format!("\x1b[{}m{}\x1b[0m", $color, $format)
- };
- }
-
- #[allow(clippy::items_after_statements)]
- fn format_bytes(bytes: u64) -> String {
- let bytes = Bytes::new(bytes);
- bytes.to_string()
- }
-
- #[allow(clippy::items_after_statements)]
- fn format_speed(speed: f64) -> String {
- #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
- let bytes = Bytes::new(speed.floor() as u64);
- format!("{bytes}/s")
- }
+ let info_dict = json_get!(input, "info_dict", as_object);
let get_title = || -> String {
- match get! {is_string, as_str, "info_dict", "ext"} {
+ match json_get!(info_dict, "ext", as_str) {
"vtt" => {
format!(
"Subtitles ({})",
- default_get! {as_str, "<No Subtitle Language>", "info_dict", "name"}
+ json_get_default!(info_dict, "name", as_str, "<No Subtitle Language>")
)
}
"webm" | "mp4" | "mp3" | "m4a" => {
- default_get! { as_str, "<No title>", "info_dict", "title"}.to_owned()
+ json_get_default!(info_dict, "title", as_str, "<No title>").to_owned()
}
other => panic!("The extension '{other}' is not yet implemented"),
}
};
- match get! {is_string, as_str, "status"} {
+ match json_get!(input, "status", as_str) {
"downloading" => {
- let elapsed = default_get! {as_f64, 0.0f64, "elapsed"};
- let eta = default_get! {as_f64, 0.0, "eta"};
- let speed = default_get! {as_f64, 0.0, "speed"};
+ let elapsed = json_get_default!(input, "elapsed", as_f64, 0.0);
+ let eta = json_get_default!(input, "eta", as_f64, 0.0);
+ let speed = json_get_default!(input, "speed", as_f64, 0.0);
- let downloaded_bytes = get! {is_u64, as_u64, "downloaded_bytes"};
+ let downloaded_bytes = json_get!(input, "downloaded_bytes", as_u64);
let (total_bytes, bytes_is_estimate): (u64, &'static str) = {
- let total_bytes = default_get!(as_u64, 0, "total_bytes");
+ let total_bytes = json_get_default!(input, "total_bytes", as_u64, 0);
+
if total_bytes == 0 {
- let maybe_estimate = default_get!(as_u64, 0, "total_bytes_estimate");
+ #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
+ let maybe_estimate =
+ json_get_default!(input, "total_bytes_estimate", as_f64, 0.0) as u64;
#[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)]
if maybe_estimate == 0 {
- // The download speed should be in bytes per second and the eta in seconds.
- // Thus multiplying them gets us the raw bytes (which were estimated by `yt_dlp`, from their `info.json`)
+ // The download speed should be in bytes
+ // per second and the eta in seconds.
+ // Thus multiplying them gets us the raw bytes
+ // (which were estimated by `yt_dlp`, from their `info.json`)
let bytes_still_needed = (speed * eta).ceil() as u64;
(downloaded_bytes + bytes_still_needed, "~")
@@ -170,14 +127,14 @@ pub(crate) fn progress_hook(
eprint!(
"{} [{}/{} at {}] -> [{} of {}{} {}] ",
- c!("34;1", get_title()),
- c!("33;1", MaybeDuration::from_secs_f64(elapsed)),
- c!("33;1", MaybeDuration::from_secs_f64(eta)),
- c!("32;1", format_speed(speed)),
- c!("31;1", format_bytes(downloaded_bytes)),
- c!("31;1", bytes_is_estimate),
- c!("31;1", format_bytes(total_bytes)),
- c!("36;1", format!("{:.02}%", percent))
+ get_title().bold().blue(),
+ MaybeDuration::from_secs_f64(elapsed).bold().yellow(),
+ MaybeDuration::from_secs_f64(eta).bold().yellow(),
+ format_speed(speed).bold().green(),
+ format_bytes(downloaded_bytes).bold().red(),
+ bytes_is_estimate.bold().red(),
+ format_bytes(total_bytes).bold().red(),
+ format!("{percent:.02}%").bold().cyan(),
);
stderr().flush()?;
}