From b53a8d82a07c29010a690b7126795fd7ddcabe0c Mon Sep 17 00:00:00 2001 From: Soispha Date: Sat, 20 Jan 2024 18:38:18 +0100 Subject: feat(sys/nixpkgs/yt): Add support for the 'url' command This simply opens the youtube url in the browser --- sys/nixpkgs/pkgs/yt/src/bin/yt/main.rs | 46 ++++++++++------------------- sys/nixpkgs/pkgs/yt/src/bin/ytc/main.rs | 2 +- sys/nixpkgs/pkgs/yt/src/bin/yts/main.rs | 52 +++++++++++---------------------- sys/nixpkgs/pkgs/yt/src/constants.rs | 23 +++++++-------- sys/nixpkgs/pkgs/yt/src/downloader.rs | 15 ++++++++-- sys/nixpkgs/pkgs/yt/src/help.str | 7 +++-- sys/nixpkgs/pkgs/yt/src/lib.rs | 31 +++++++++++++++++++- 7 files changed, 90 insertions(+), 86 deletions(-) (limited to 'sys/nixpkgs/pkgs/yt/src') diff --git a/sys/nixpkgs/pkgs/yt/src/bin/yt/main.rs b/sys/nixpkgs/pkgs/yt/src/bin/yt/main.rs index ae1bcacd..f3c16613 100644 --- a/sys/nixpkgs/pkgs/yt/src/bin/yt/main.rs +++ b/sys/nixpkgs/pkgs/yt/src/bin/yt/main.rs @@ -7,8 +7,8 @@ use std::{ use tempfile::Builder; use yt::{ constants::{last_select, HELP_STR}, - downloader::{Downloadable, Downloader}, - ytcc_drop, Line, LineCommand, YtccListData, + downloader::Downloader, + filter_line, YtccListData, }; fn main() -> Result<()> { @@ -41,16 +41,14 @@ fn main() -> Result<()> { { let mut edit_file = BufWriter::new(&temp_file); - json_map - .iter() - .map(|line| line.to_string()) - .for_each(|line| { - edit_file - .write(line.as_bytes()) - .expect("This write should not fail"); - }); + json_map.iter().for_each(|line| { + let line = line.to_string(); + edit_file + .write_all(line.as_bytes()) + .expect("This write should not fail"); + }); - edit_file.write(HELP_STR.as_bytes())?; + edit_file.write_all(HELP_STR.as_bytes())?; edit_file.flush().context("Failed to flush edit file")?; let mut nvim = StdCmd::new("nvim"); @@ -64,7 +62,7 @@ fn main() -> Result<()> { let read_file = temp_file.reopen()?; fs::copy( temp_file.path(), - last_select().context("Failed to get persistent the selection file path")?, + last_select().context("Failed to get the persistent selection file path")?, ) .context("Failed to persist selection file")?; @@ -73,28 +71,14 @@ fn main() -> Result<()> { for line in reader.lines() { let line = line.context("Failed to read line")?; - if line.starts_with("#") { - // comment - continue; - } else if line.trim().len() == 0 { - // empty line - continue; - } - - let line = Line::from(line.as_str()); - match line.cmd { - LineCommand::Pick => (), - LineCommand::Drop => { - ytcc_drop(line.id).with_context(|| format!("Failed to drop: {}", line.id))? - } - LineCommand::Watch => watching.push(Downloadable { - id: Some(line.id), - url: line.url, - }), + if let Some(downloadable) = + filter_line(&line).with_context(|| format!("Failed to process line: '{}'", line))? + { + watching.push(downloadable); } } - if watching.len() == 0 { + if watching.is_empty() { return Ok(()); } diff --git a/sys/nixpkgs/pkgs/yt/src/bin/ytc/main.rs b/sys/nixpkgs/pkgs/yt/src/bin/ytc/main.rs index 437df803..3fa3148d 100644 --- a/sys/nixpkgs/pkgs/yt/src/bin/ytc/main.rs +++ b/sys/nixpkgs/pkgs/yt/src/bin/ytc/main.rs @@ -37,7 +37,7 @@ fn main() -> Result<()> { ) .context("Failed to deserialize json output")?; - if json.len() == 0 { + if json.is_empty() { bail!("Could not find a video with id: {}", id); } assert_eq!(json.len(), 1); diff --git a/sys/nixpkgs/pkgs/yt/src/bin/yts/main.rs b/sys/nixpkgs/pkgs/yt/src/bin/yts/main.rs index 788ecab2..7398db61 100644 --- a/sys/nixpkgs/pkgs/yt/src/bin/yts/main.rs +++ b/sys/nixpkgs/pkgs/yt/src/bin/yts/main.rs @@ -6,7 +6,7 @@ use std::{ process::Command as StdCmd, }; use tempfile::NamedTempFile; -use yt::{constants::HELP_STR, ytcc_drop, Line, LineCommand, YtccListData}; +use yt::{constants::HELP_STR, filter_line, YtccListData}; use crate::args::{Args, Command, OrderCommand}; @@ -49,26 +49,13 @@ fn main() -> Result<()> { let mut edit_file = NamedTempFile::new().context("Failed to get tempfile")?; - let file: String = json_map - .iter() - .map(|line| { - format!( - "pick {} \"{}\" <{}> [{}]\n", - line.id, - line.title, - line.playlists - .iter() - .map(|p| &p.name[..]) - .collect::>() - .join(", "), - line.duration.trim() - ) - }) - .collect(); + json_map.iter().for_each(|line| { + let line = line.to_string(); + edit_file + .write_all(line.as_bytes()) + .expect("This write should not fail"); + }); - for line in file.lines() { - writeln!(&edit_file, "{}", line)?; - } write!(&edit_file, "{}", HELP_STR)?; edit_file.flush().context("Failed to flush edit file")?; @@ -87,23 +74,18 @@ fn main() -> Result<()> { for line in reader.lines() { let line = line.context("Failed to read line")?; - if line.starts_with("#") { - continue; - } else if line.trim().len() == 0 { - // empty line - continue; - } - - let line = Line::from(line.as_str()); - match line.cmd { - LineCommand::Pick => (), - LineCommand::Drop => { - ytcc_drop(line.id).with_context(|| format!("Failed to drop: {}", line.id))? - } - LineCommand::Watch => watching.push(line.id), + if let Some(downloadable) = + filter_line(&line).with_context(|| format!("Failed to process line: '{}'", line))? + { + watching.push(downloadable); } } - dbg!(&watching); + let watching: String = watching + .iter() + .map(|d| d.to_string()) + .collect::>() + .join("\n"); + println!("{}", &watching); Ok(()) } diff --git a/sys/nixpkgs/pkgs/yt/src/constants.rs b/sys/nixpkgs/pkgs/yt/src/constants.rs index 5250820c..6385df54 100644 --- a/sys/nixpkgs/pkgs/yt/src/constants.rs +++ b/sys/nixpkgs/pkgs/yt/src/constants.rs @@ -1,6 +1,6 @@ use std::{env, fs, path::PathBuf}; -pub const HELP_STR: &'static str = include_str!("./help.str"); +pub const HELP_STR: &str = include_str!("./help.str"); pub const YT_DLP_FLAGS: [&str; 13] = [ // Ignore errors arising of unavailable sponsor block API @@ -24,26 +24,23 @@ pub const CONCURRENT: u32 = 5; pub const DOWNLOAD_DIR: &str = "/tmp/ytcc"; -const STATUS_PATH: &str = "ytcc/running"; -pub fn status_path() -> anyhow::Result { +fn get_runtime_path(component: &'static str) -> anyhow::Result { let out: PathBuf = format!( "{}/{}", env::var("XDG_RUNTIME_DIR").expect("This should always exist"), - STATUS_PATH + component ) .into(); - fs::create_dir_all(&out.parent().expect("Parent should exist"))?; + fs::create_dir_all(out.parent().expect("Parent should exist"))?; Ok(out) } +const STATUS_PATH: &str = "ytcc/running"; +pub fn status_path() -> anyhow::Result { + get_runtime_path(STATUS_PATH) +} + const LAST_SELECT: &str = "ytcc/selected.yts"; pub fn last_select() -> anyhow::Result { - let out: PathBuf = format!( - "{}/{}", - env::var("XDG_RUNTIME_DIR").expect("This should always exist"), - LAST_SELECT - ) - .into(); - fs::create_dir_all(&out.parent().expect("Parent should exist"))?; - Ok(out) + get_runtime_path(LAST_SELECT) } diff --git a/sys/nixpkgs/pkgs/yt/src/downloader.rs b/sys/nixpkgs/pkgs/yt/src/downloader.rs index 34627f70..b30c49a2 100644 --- a/sys/nixpkgs/pkgs/yt/src/downloader.rs +++ b/sys/nixpkgs/pkgs/yt/src/downloader.rs @@ -21,6 +21,17 @@ pub struct Downloadable { pub id: Option, } +impl std::fmt::Display for Downloadable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + write!( + f, + "{}|{}", + self.url.as_str().replace('|', ";"), + self.id.unwrap_or(0), + ) + } +} + pub struct Downloader { sent: usize, download_thread: JoinHandle>, @@ -34,8 +45,8 @@ impl Downloader { let (itx, irx): (Sender, Receiver) = mpsc::channel(); let (otx, orx) = mpsc::channel(); let jh = thread::spawn(move || -> Result<()> { - while let Some(pt) = irx.recv().ok() { - debug!("Got '{}|{}' to be downloaded", pt.url, pt.id.unwrap_or(0)); + while let Ok(pt) = irx.recv() { + debug!("Got '{}' to be downloaded", pt); let path = download_url(&pt.url) .with_context(|| format!("Failed to download url: '{}'", &pt.url))?; otx.send((path, pt.id)).expect("Should not be dropped"); diff --git a/sys/nixpkgs/pkgs/yt/src/help.str b/sys/nixpkgs/pkgs/yt/src/help.str index e5b21fce..130fe42a 100644 --- a/sys/nixpkgs/pkgs/yt/src/help.str +++ b/sys/nixpkgs/pkgs/yt/src/help.str @@ -1,7 +1,8 @@ # Commands: -# w, watch = watch id -# d, drop = mark id as watched -# p, pick = leave id as is; This is a noop +# w, watch = watch id +# d, drop = mark id as watched +# u, url = open the associated URL in the `timesinks.youtube` Firefox profile +# p, pick = leave id as is; This is a noop # # These lines can be re-ordered; they are executed from top to bottom. # vim: filetype=yts conceallevel=2 concealcursor=nc colorcolumn= diff --git a/sys/nixpkgs/pkgs/yt/src/lib.rs b/sys/nixpkgs/pkgs/yt/src/lib.rs index 2571b6b6..7fa090af 100644 --- a/sys/nixpkgs/pkgs/yt/src/lib.rs +++ b/sys/nixpkgs/pkgs/yt/src/lib.rs @@ -1,4 +1,5 @@ use anyhow::{bail, Context}; +use downloader::Downloadable; use serde::Deserialize; use url::Url; @@ -50,6 +51,7 @@ pub enum LineCommand { Pick, Drop, Watch, + Url, } impl std::str::FromStr for LineCommand { @@ -59,6 +61,7 @@ impl std::str::FromStr for LineCommand { "pick" | "p" => Ok(Self::Pick), "drop" | "d" => Ok(Self::Drop), "watch" | "w" => Ok(Self::Watch), + "url" | "u" => Ok(Self::Url), other => bail!("'{}' is not a recognized command!", other), } } @@ -115,7 +118,7 @@ impl std::fmt::Display for Duration { 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 base_sec = (self.time % HOUR) % MINUTE; let h = base_hour / HOUR; let m = base_min / MINUTE; @@ -154,3 +157,29 @@ pub fn ytcc_drop(id: u32) -> anyhow::Result<()> { } Ok(()) } + +pub fn filter_line(line: &str) -> anyhow::Result> { + // Filter out comments and empty lines + if line.starts_with('#') || line.trim().is_empty() { + return Ok(None); + } + + let line = Line::from(line); + match line.cmd { + LineCommand::Pick => Ok(None), + LineCommand::Drop => ytcc_drop(line.id) + .with_context(|| format!("Failed to drop: {}", line.id)) + .map(|_| None), + LineCommand::Watch => Ok(Some(Downloadable { + id: Some(line.id), + url: line.url, + })), + LineCommand::Url => { + let mut firefox = std::process::Command::new("firefox"); + firefox.args(["-P", "timesinks.youtube"]); + firefox.arg(line.url.as_str()); + let _handle = firefox.spawn().context("Failed to run firefox")?; + Ok(None) + } + } +} -- cgit 1.4.1