about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-02-14 16:44:53 +0100
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-02-14 16:44:53 +0100
commit14db4eadd57d0a3837227d9d74b84a133bacd434 (patch)
tree6a269bb25cf7204cfbdf776a12eeb3490a1ed6cd
parentfix(yt/download/download_options): Stop trying to write annotations (diff)
downloadyt-14db4eadd57d0a3837227d9d74b84a133bacd434.zip
feat(yt/select/selection_file/duration): Support durations up to days
The current maximum of hours was enough in most cases, but not for all
cases.
-rw-r--r--yt/src/select/selection_file/duration.rs61
1 files changed, 43 insertions, 18 deletions
diff --git a/yt/src/select/selection_file/duration.rs b/yt/src/select/selection_file/duration.rs
index ab3a18b..2953bd3 100644
--- a/yt/src/select/selection_file/duration.rs
+++ b/yt/src/select/selection_file/duration.rs
@@ -14,19 +14,36 @@ use anyhow::{Context, Result};
 
 use crate::unreachable::Unreachable;
 
+const SECOND: u64 = 1;
+const MINUTE: u64 = 60 * SECOND;
+const HOUR: u64 = 60 * MINUTE;
+const DAY: u64 = 24 * HOUR;
+
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
 pub struct Duration {
-    time: u32,
+    time: u64,
+}
+
+impl Duration {
+    #[must_use]
+    pub fn from_std(d: std::time::Duration) -> Self {
+        Self { time: d.as_secs() }
+    }
+
+    #[must_use]
+    pub fn value(&self) -> u64 {
+        self.time
+    }
 }
 
 impl FromStr for Duration {
     type Err = anyhow::Error;
 
     fn from_str(s: &str) -> Result<Self, Self::Err> {
-        fn parse_num(str: &str, suffix: char) -> Result<u32> {
+        fn parse_num(str: &str, suffix: char) -> Result<u64> {
             str.strip_suffix(suffix)
                 .with_context(|| format!("Failed to strip suffix '{suffix}' of number: '{str}'"))?
-                .parse::<u32>()
+                .parse::<u64>()
                 .with_context(|| format!("Failed to parse '{suffix}'"))
         }
 
@@ -36,17 +53,25 @@ impl FromStr for Duration {
 
         let buf: Vec<_> = s.split(' ').collect();
 
+        let days;
         let hours;
         let minutes;
         let seconds;
 
         assert_eq!(buf.len(), 2, "Other lengths should not happen");
 
-        if buf[0].ends_with('h') {
+        if buf[0].ends_with('d') {
+            days = parse_num(buf[0], 'd')?;
+            hours = parse_num(buf[1], 'h')?;
+            minutes = parse_num(buf[2], 'm')?;
+            seconds = 0;
+        } else if buf[0].ends_with('h') {
+            days = 0;
             hours = parse_num(buf[0], 'h')?;
             minutes = parse_num(buf[1], 'm')?;
             seconds = 0;
         } else if buf[0].ends_with('m') {
+            days = 0;
             hours = 0;
             minutes = parse_num(buf[0], 'm')?;
             seconds = parse_num(buf[1], 's')?;
@@ -58,7 +83,7 @@ impl FromStr for Duration {
         }
 
         Ok(Self {
-            time: (hours * 60 * 60) + (minutes * 60) + seconds,
+            time: days * DAY + hours * HOUR + minutes * MINUTE + seconds * SECOND,
         })
     }
 }
@@ -67,32 +92,32 @@ impl From<Option<f64>> for Duration {
     fn from(value: Option<f64>) -> Self {
         Self {
             #[allow(clippy::cast_possible_truncation)]
-            time: u32::try_from(value.unwrap_or(0.0).ceil() as i128)
-                .unreachable("This should not exceed `u32::MAX`"),
+            time: u64::try_from(value.unwrap_or(0.0).ceil() as i128)
+                .unreachable("This should not exceed `u64::MAX`"),
         }
     }
 }
 
 impl std::fmt::Display for Duration {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
-        const SECOND: u32 = 1;
-        const MINUTE: u32 = 60 * SECOND;
-        const HOUR: u32 = 60 * MINUTE;
-
-        let base_hour = self.time - (self.time % HOUR);
-        let base_min = (self.time % HOUR) - ((self.time % HOUR) % MINUTE);
-        let base_sec = (self.time % HOUR) % MINUTE;
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+        let base_day = self.time - (self.time % DAY);
+        let base_hour = (self.time % DAY) - ((self.time % DAY) % HOUR);
+        let base_min = (self.time % HOUR) - (((self.time % DAY) % HOUR) % MINUTE);
+        let base_sec = ((self.time % DAY) % HOUR) % MINUTE;
 
+        let d = base_day / DAY;
         let h = base_hour / HOUR;
         let m = base_min / MINUTE;
         let s = base_sec / SECOND;
 
         if self.time == 0 {
-            write!(f, "[No duration]")
+            write!(fmt, "[No duration]")
+        } else if d > 0 {
+            write!(fmt, "{d}d {h}h {m}m")
         } else if h > 0 {
-            write!(f, "{h}h {m}m")
+            write!(fmt, "{h}h {m}m")
         } else {
-            write!(f, "{m}m {s}s")
+            write!(fmt, "{m}m {s}s")
         }
     }
 }