diff options
author | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2024-08-23 18:20:26 +0200 |
---|---|---|
committer | Benedikt Peetz <benedikt.peetz@b-peetz.de> | 2024-08-23 18:20:26 +0200 |
commit | d5c2fcc184f764f9d4bb5846a1182c6014316bdc (patch) | |
tree | f4c3241b4a8b64aa30de39a7c057bf1ec9b99dbe | |
parent | fix(config/from_filesystem): Only create the parent of config paths (diff) | |
download | yt-d5c2fcc184f764f9d4bb5846a1182c6014316bdc.tar.gz yt-d5c2fcc184f764f9d4bb5846a1182c6014316bdc.zip |
feat(videos): Init
-rw-r--r-- | Cargo.lock | 11 | ||||
-rw-r--r-- | Cargo.toml | 1 | ||||
-rw-r--r-- | src/cli.rs | 23 | ||||
-rw-r--r-- | src/main.rs | 16 | ||||
-rw-r--r-- | src/videos/mod.rs | 57 |
5 files changed, 107 insertions, 1 deletions
diff --git a/Cargo.lock b/Cargo.lock index 7d69dbf..927cc05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -970,6 +970,16 @@ dependencies = [ ] [[package]] +name = "nucleo-matcher" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf33f538733d1a5a3494b836ba913207f14d9d4a1d3cd67030c5061bdd2cac85" +dependencies = [ + "memchr", + "unicode-segmentation", +] + +[[package]] name = "num-bigint-dig" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2356,6 +2366,7 @@ dependencies = [ "futures", "libmpv2", "log", + "nucleo-matcher", "regex", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 1670b2a..17f8e48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ libmpv2 = { path = "./crates/libmpv2" } bytes = { path = "./crates/bytes" } trinitry = { version = "0.2.2" } toml = "0.8.19" +nucleo-matcher = "0.3.1" [[bin]] name = "yt" diff --git a/src/cli.rs b/src/cli.rs index d3ec262..72ec877 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -61,6 +61,12 @@ pub enum Command { max_cache_size: Option<u64>, }, + /// Work with single videos + Videos { + #[command(subcommand)] + cmd: VideosCommand, + }, + /// Watch the already cached (and selected) videos Watch {}, @@ -126,6 +132,23 @@ impl Default for Command { } #[derive(Subcommand, Clone, Debug)] +pub enum VideosCommand { + /// List the videos in the database + #[command(visible_alias = "ls")] + List { + /// An optional search query to limit the results + #[arg(action = ArgAction::Append)] + search_query: Option<String>, + }, + + /// Get detailed information about a video + Info { + /// The short hash of the video + hash: LazyExtractorHash, + }, +} + +#[derive(Subcommand, Clone, Debug)] pub enum SubscriptionCommand { /// Subscribe to an URL Add { diff --git a/src/main.rs b/src/main.rs index 94c0f71..28a0b38 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,10 +14,11 @@ use anyhow::{bail, Context, Result}; use app::App; use cache::invalidate; use clap::Parser; -use cli::{CacheCommand, CheckCommand, SelectCommand, SubscriptionCommand}; +use cli::{CacheCommand, CheckCommand, SelectCommand, SubscriptionCommand, VideosCommand}; use config::Config; use log::info; use select::cmds::handle_select_cmd; +use storage::video_database::getters::get_video_by_hash; use tokio::{ fs::File, io::{stdin, BufReader}, @@ -40,6 +41,7 @@ pub mod status; pub mod storage; pub mod subscribe; pub mod update; +pub mod videos; pub mod watch; #[tokio::main] @@ -99,6 +101,18 @@ async fn main() -> Result<()> { _ => handle_select_cmd(&app, cmd, None).await?, } } + Command::Videos { cmd } => match cmd { + VideosCommand::List { search_query } => { + videos::query(&app, search_query) + .await + .context("Failed to query videos")?; + } + VideosCommand::Info { hash } => { + let video = get_video_by_hash(&app, &hash.realize(&app).await?).await?; + dbg!(video); + } + }, + Command::Update { max_backlog, subscriptions, diff --git a/src/videos/mod.rs b/src/videos/mod.rs new file mode 100644 index 0000000..5bf34e3 --- /dev/null +++ b/src/videos/mod.rs @@ -0,0 +1,57 @@ +// 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>. + +use anyhow::Result; +use futures::{stream::FuturesUnordered, TryStreamExt}; +use nucleo_matcher::{ + pattern::{CaseMatching, Normalization, Pattern}, + Matcher, +}; + +use crate::{ + app::App, + storage::video_database::{getters::get_videos, VideoStatus}, +}; + +pub async fn query(app: &App, search_query: Option<String>) -> Result<()> { + let all_videos = get_videos(app, &VideoStatus::ALL, None).await?; + + // turn one video to a color display, to pre-warm the hash shrinking cache + if let Some(val) = all_videos.get(0) { + val.to_color_display(app).await?; + } + + let all_video_strings: Vec<String> = all_videos + .into_iter() + .map(|vid| vid.to_color_display_owned(app)) + .collect::<FuturesUnordered<_>>() + .try_collect() + .await?; + + if let Some(query) = search_query { + let mut matcher = Matcher::new(nucleo_matcher::Config::DEFAULT.match_paths()); + + let matches = Pattern::parse( + &query.replace(' ', "\\ "), + CaseMatching::Ignore, + Normalization::Smart, + ) + .match_list(all_video_strings, &mut matcher); + + matches + .iter() + .rev() + .for_each(|(val, key)| println!("{} ({})", val, key)); + } else { + println!("{}", all_video_strings.join("\n")) + } + + Ok(()) +} |