about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-08-23 18:20:26 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-08-23 18:20:26 +0200
commitd5c2fcc184f764f9d4bb5846a1182c6014316bdc (patch)
treef4c3241b4a8b64aa30de39a7c057bf1ec9b99dbe
parentfix(config/from_filesystem): Only create the parent of config paths (diff)
downloadyt-d5c2fcc184f764f9d4bb5846a1182c6014316bdc.tar.gz
yt-d5c2fcc184f764f9d4bb5846a1182c6014316bdc.zip
feat(videos): Init
-rw-r--r--Cargo.lock11
-rw-r--r--Cargo.toml1
-rw-r--r--src/cli.rs23
-rw-r--r--src/main.rs16
-rw-r--r--src/videos/mod.rs57
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(())
+}