about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-02-14 16:54:33 +0100
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2025-02-14 16:54:33 +0100
commite9024377cf5b16f9a81b0f750891307cd6acebe4 (patch)
tree6ea89673cd93df534b013236c48a69e161e2b9cb
parentfeat(yt/select/selection_file/duration): Support durations up to days (diff)
downloadyt-e9024377cf5b16f9a81b0f750891307cd6acebe4.zip
feat(yt/status): Include the approximate total watch time
-rw-r--r--yt/src/status/mod.rs47
1 files changed, 47 insertions, 0 deletions
diff --git a/yt/src/status/mod.rs b/yt/src/status/mod.rs
index 2f7db25..2f493f7 100644
--- a/yt/src/status/mod.rs
+++ b/yt/src/status/mod.rs
@@ -8,6 +8,10 @@
 // You should have received a copy of the License along with this program.
 // If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
 
+use std::time::Duration;
+
+use crate::select::selection_file::duration::Duration as YtDuration;
+
 use anyhow::{Context, Result};
 use bytes::Bytes;
 
@@ -27,6 +31,14 @@ macro_rules! get {
             .filter(|vid| vid.status == VideoStatus::$status)
             .count()
     };
+
+    (@collect $videos:expr, $status:ident) => {
+        $videos
+            .iter()
+            .filter(|vid| vid.status == VideoStatus::$status)
+            .collect()
+    };
+
     (@changing $videos:expr, $status:ident) => {
         $videos
             .iter()
@@ -58,6 +70,7 @@ pub async fn show(app: &App) -> Result<()> {
     let watch_videos_len = get!(all_videos, Watch);
     let cached_videos_len = get!(all_videos, Cached);
     let watched_videos_len = get!(all_videos, Watched);
+    let watched_videos: Vec<_> = get!(@collect all_videos, Watched);
 
     let drop_videos_len = get!(all_videos, Drop);
     let dropped_videos_len = get!(all_videos, Dropped);
@@ -75,6 +88,39 @@ pub async fn show(app: &App) -> Result<()> {
     let subscriptions = get(app).await?;
     let subscriptions_len = subscriptions.0.len();
 
+    let watchtime_status = {
+        let total_watch_time_raw = YtDuration::from_std(Duration::from_secs_f64(
+            watched_videos
+                .iter()
+                .fold(0f64, |acc, vid| acc + vid.duration.unwrap_or(0f64)),
+        ));
+
+        // Most things are watched at a speed of s (which is defined in the config file).
+        // Thus
+        //      y = x * s -> y / s = x
+        #[allow(clippy::cast_precision_loss)]
+        let total_watch_time = YtDuration::from_std(Duration::from_secs_f64(
+            (total_watch_time_raw.value() as f64) / app.config.select.playback_speed,
+        ));
+
+        if total_watch_time.value() == 0 {
+            // do not display a watchtime, if it is 0
+            String::new()
+        } else {
+            let speed = app.config.select.playback_speed;
+
+            // Do not print the adjusted time, if the user has keep the speed level at 1.
+            #[allow(clippy::float_cmp)]
+            if speed == 1.0 {
+                format!("Total Watchtime: {total_watch_time_raw}\n")
+            } else {
+                format!(
+                    "Total Watchtime: {total_watch_time_raw} (at {speed} speed: {total_watch_time})\n",
+                )
+            }
+        }
+    };
+
     let cache_usage_raw = Downloader::get_current_cache_allocation(app)
         .await
         .context("Failed to get current cache allocation")?;
@@ -90,6 +136,7 @@ Watched  Videos: {watched_videos_len} ({watched_videos_changing} changing)
 Drop     Videos: {drop_videos_len} ({drop_videos_changing} changing)
 Dropped  Videos: {dropped_videos_len} ({dropped_videos_changing} changing)
 
+{watchtime_status}
 
   Subscriptions: {subscriptions_len}
     Cache usage: {cache_usage}"