about summary refs log tree commit diff stats
path: root/src/cli.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/cli.rs')
-rw-r--r--src/cli.rs244
1 files changed, 244 insertions, 0 deletions
diff --git a/src/cli.rs b/src/cli.rs
new file mode 100644
index 0000000..4835fc4
--- /dev/null
+++ b/src/cli.rs
@@ -0,0 +1,244 @@
+// 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 std::path::PathBuf;
+
+use chrono::NaiveDate;
+use clap::{ArgAction, Args, Parser, Subcommand};
+use url::Url;
+
+use crate::{
+    constants, select::selection_file::duration::Duration,
+    storage::video_database::extractor_hash::LazyExtractorHash,
+};
+
+#[derive(Parser, Debug)]
+#[clap(author, version, about, long_about = None)]
+/// An command line interface to select, download and watch videos
+pub struct CliArgs {
+    #[command(subcommand)]
+    /// The subcommand to execute [default: select]
+    pub command: Option<Command>,
+
+    /// Increase message verbosity
+    #[arg(long="verbose", short = 'v', action = ArgAction::Count)]
+    pub verbosity: u8,
+
+    /// Silence all output
+    #[arg(long, short = 'q')]
+    pub quiet: bool,
+}
+
+#[derive(Subcommand, Debug)]
+pub enum Command {
+    /// Download and cache URLs
+    Download {
+        /// Forcefully re-download all cached videos (i.e. delete the cache path, then download).
+        #[arg(short, long)]
+        force: bool,
+    },
+
+    /// Watch the already cached (and selected) videos
+    Watch {},
+
+    /// Show, which videos have been selected to be watched (and their cache status)
+    Status {},
+
+    /// Perform various tests
+    Check {
+        #[command(subcommand)]
+        command: CheckCommand,
+    },
+
+    /// Display the comments of the currently playing video
+    Comments {},
+    /// Display the description of the currently playing video
+    Description {},
+
+    /// Manipulate the video cache in the database
+    #[command(visible_alias = "db")]
+    Database {
+        #[command(subcommand)]
+        command: CacheCommand,
+    },
+
+    /// Change the state of videos in the database (the default)
+    Select {
+        #[command(subcommand)]
+        cmd: Option<SelectCommand>,
+    },
+
+    /// Update the video database
+    Update {
+        #[arg(short, long, default_value = "20")]
+        /// The number of videos to updating
+        max_backlog: u32,
+
+        #[arg(short, long)]
+        /// The subscriptions to update (can be given multiple times)
+        subscriptions: Vec<String>,
+
+        #[arg(short, long, default_value = "6")]
+        /// How many processes to spawn at the same time
+        concurrent_processes: usize,
+    },
+
+    /// Manipulate subscription
+    #[command(visible_alias = "subs")]
+    Subscriptions {
+        #[command(subcommand)]
+        cmd: SubscriptionCommand,
+    },
+}
+
+impl Default for Command {
+    fn default() -> Self {
+        Self::Select {
+            cmd: Some(SelectCommand::default()),
+        }
+    }
+}
+
+#[derive(Subcommand, Clone, Debug)]
+pub enum SubscriptionCommand {
+    /// Subscribe to an URL
+    Add {
+        #[arg(short, long)]
+        /// The human readable name of the subscription
+        name: Option<String>,
+
+        /// The URL to listen to
+        url: Url,
+    },
+
+    /// Unsubscribe from an URL
+    Remove {
+        /// The human readable name of the subscription
+        name: String,
+    },
+
+    /// Import a bunch of URLs as subscriptions.
+    Import {
+        /// The file containing the URLs. Will use Stdin otherwise.
+        file: Option<PathBuf>,
+
+        /// Remove any previous subscriptions
+        #[arg(short, long)]
+        force: bool
+    },
+
+    /// List all subscriptions
+    List {
+        /// Only show the URLs
+        #[arg(short, long)]
+        url: bool,
+    },
+}
+
+#[derive(Clone, Debug, Args)]
+#[command(infer_subcommands = true)]
+/// Mark the video given by the hash to be watched
+pub struct SharedSelectionCommandArgs {
+    /// The short extractor hash
+    pub hash: LazyExtractorHash,
+
+    pub title: String,
+
+    pub date: NaiveDate,
+
+    pub publisher: String,
+
+    pub duration: Duration,
+
+    pub url: Url,
+}
+
+#[derive(Subcommand, Clone, Debug)]
+#[command(infer_subcommands = true)]
+// NOTE: Keep this in sync with the [`constants::HELP_STR`] constant. <2024-08-20>
+pub enum SelectCommand {
+    /// Open a `git rebase` like file to select the videos to watch (the default)
+    File {
+        /// Include done (watched, dropped) videos
+        #[arg(long, short)]
+        done: bool,
+    },
+
+    Watch {
+        #[command(flatten)]
+        shared: SharedSelectionCommandArgs,
+
+        /// The ordering priority (higher means more at the top)
+        #[arg(short, long)]
+        priority: Option<i64>,
+
+        /// The subtitles to download (e.g. 'en,de,sv')
+        #[arg(short = 'l', long, default_value = constants::DEFAULT_SUBTITLE_LANGS)]
+        subtitle_langs: String,
+
+        /// The speed to set mpv to
+        #[arg(short, long, default_value = "2.7")]
+        speed: f64,
+    },
+
+    /// Mark the video given by the hash to be dropped
+    Drop {
+        #[command(flatten)]
+        shared: SharedSelectionCommandArgs,
+    },
+
+    /// Open the video URL in Firefox's `timesinks.youtube` profile
+    Url {
+        #[command(flatten)]
+        shared: SharedSelectionCommandArgs,
+    },
+
+    /// Reset the videos status to 'Pick'
+    Pick {
+        #[command(flatten)]
+        shared: SharedSelectionCommandArgs,
+    },
+}
+impl Default for SelectCommand {
+    fn default() -> Self {
+        Self::File { done: false }
+    }
+}
+
+#[derive(Subcommand, Clone, Debug)]
+pub enum CheckCommand {
+    /// Check if the given info.json is deserializable
+    InfoJson { path: PathBuf },
+
+    /// Check if the given update info.json is deserializable
+    UpdateInfoJson { path: PathBuf },
+}
+
+#[derive(Subcommand, Clone, Copy, Debug)]
+pub enum CacheCommand {
+    /// Invalidate all cache entries
+    Invalidate {
+        /// Also delete the cache path
+        #[arg(short, long)]
+        hard: bool,
+    },
+
+    /// Perform basic maintenance operations on the database.
+    /// This helps recovering from invalid db states after a crash (or force exit via CTRL+C).
+    ///
+    /// 1. Check every path for validity (removing all invalid cache entries)
+    /// 2. Reset all `status_change` bits of videos to false.
+    #[command(verbatim_doc_comment)]
+    Maintain {
+        /// Check every video (otherwise only the videos to be watched are checked)
+        #[arg(short, long)]
+        all: bool,
+    },
+}