about summary refs log tree commit diff stats
path: root/sys/nixpkgs/pkgs/yt/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'sys/nixpkgs/pkgs/yt/src/lib.rs')
-rw-r--r--sys/nixpkgs/pkgs/yt/src/lib.rs140
1 files changed, 140 insertions, 0 deletions
diff --git a/sys/nixpkgs/pkgs/yt/src/lib.rs b/sys/nixpkgs/pkgs/yt/src/lib.rs
new file mode 100644
index 00000000..a08b32db
--- /dev/null
+++ b/sys/nixpkgs/pkgs/yt/src/lib.rs
@@ -0,0 +1,140 @@
+use anyhow::{bail, Context};
+use serde::Deserialize;
+use url::Url;
+
+pub mod constants;
+pub mod downloader;
+
+#[derive(Deserialize)]
+pub struct YtccListData {
+    pub url: String,
+    pub title: String,
+    pub description: String,
+    pub publish_date: String,
+    pub watch_date: Option<String>,
+    pub duration: String,
+    pub thumbnail_url: String,
+    pub extractor_hash: String,
+    pub id: u32,
+    pub playlists: Vec<YtccPlaylistData>,
+}
+#[derive(Deserialize)]
+pub struct YtccPlaylistData {
+    pub name: String,
+    pub url: String,
+    pub reverse: bool,
+}
+
+pub enum LineCommand {
+    Pick,
+    Drop,
+    Watch,
+}
+
+impl std::str::FromStr for LineCommand {
+    type Err = anyhow::Error;
+    fn from_str(v: &str) -> Result<Self, <Self as std::str::FromStr>::Err> {
+        match v {
+            "pick" | "p" => Ok(Self::Pick),
+            "drop" | "d" => Ok(Self::Drop),
+            "watch" | "w" => Ok(Self::Watch),
+            other => bail!("'{}' is not a recognized command!", other),
+        }
+    }
+}
+
+pub struct Line {
+    pub cmd: LineCommand,
+    pub id: u32,
+    pub url: Url,
+}
+
+/// We expect that each line is correctly formatted, and simply use default ones if they are not
+impl From<&str> for Line {
+    fn from(v: &str) -> Self {
+        let buf: Vec<_> = v.split_whitespace().collect();
+        let url: Url = Url::parse(
+            buf.last()
+                .expect("This should always exists")
+                .trim_matches('"'),
+        )
+        .expect("This parsing should work,as the url is generated");
+
+        Line {
+            cmd: buf
+                .get(0)
+                .unwrap_or(&"pick")
+                .parse()
+                .unwrap_or(LineCommand::Pick),
+            id: buf.get(1).unwrap_or(&"0").parse().unwrap_or(0),
+            url,
+        }
+    }
+}
+
+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 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) - (((self.time % HOUR) % MINUTE) % SECOND);
+
+        let h = base_hour / HOUR;
+        let m = base_min / MINUTE;
+        let s = base_sec / SECOND;
+
+        if self.time == 0 {
+            write!(f, "[No Duration]")
+        } else if h > 0 {
+            write!(f, "[{h}h {m}m]")
+        } else {
+            write!(f, "[{m}m {s}s]")
+        }
+    }
+}
+#[cfg(test)]
+mod test {
+    use crate::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());
+    }
+}
+
+pub fn ytcc_drop(id: u32) -> anyhow::Result<()> {
+    let mut ytcc = std::process::Command::new("ytcc");
+    ytcc.args(["mark", &format!("{}", id)]);
+    if !ytcc.status().context("Failed to run ytcc")?.success() {
+        bail!("`ytcc mark {}` failed to execute", id)
+    }
+    Ok(())
+}