about summary refs log blame commit diff stats
path: root/crates/yt_dlp/src/duration.rs
blob: 19181a58d1dfb4dc86ebfc8e0d344904472e2068 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11









                                                                                            
                             















                                                                           



                                                 

































                                                                                   
                                                        


                                             
                                                         
     
// yt - A fully featured command line YouTube client
//
// Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This file is part of Yt.
//
// 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>.

// TODO: This file should be de-duplicated with the same file in the 'yt' crate <2024-06-25>

#[derive(Debug, Clone, Copy)]
pub struct Duration {
    time: u32,
}

impl From<&str> for Duration {
    fn from(v: &str) -> Self {
        let buf: Vec<_> = v.split(':').take(2).collect();
        Self {
            time: (buf[0].parse::<u32>().expect("Should be a number") * 60)
                + buf[1].parse::<u32>().expect("Should be a number"),
        }
    }
}

impl From<Option<f64>> for Duration {
    fn from(value: Option<f64>) -> Self {
        Self {
            #[allow(
                clippy::cast_possible_truncation,
                clippy::cast_precision_loss,
                clippy::cast_sign_loss
            )]
            time: value.unwrap_or(0.0).ceil() as u32,
        }
    }
}

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;

        let h = base_hour / HOUR;
        let m = base_min / MINUTE;
        let s = base_sec / SECOND;

        if self.time == 0 {
            write!(f, "0s")
        } else if h > 0 {
            write!(f, "{h}h {m}m")
        } else {
            write!(f, "{m}m {s}s")
        }
    }
}
#[cfg(test)]
mod test {
    use super::Duration;

    #[test]
    fn test_display_duration_1h() {
        let dur = Duration { time: 60 * 60 };
        assert_eq!("1h 0m".to_owned(), dur.to_string());
    }
    #[test]
    fn test_display_duration_30min() {
        let dur = Duration { time: 60 * 30 };
        assert_eq!("30m 0s".to_owned(), dur.to_string());
    }
}