about summary refs log tree commit diff stats
path: root/src/storage/video_database/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/storage/video_database/mod.rs')
-rw-r--r--src/storage/video_database/mod.rs170
1 files changed, 170 insertions, 0 deletions
diff --git a/src/storage/video_database/mod.rs b/src/storage/video_database/mod.rs
new file mode 100644
index 0000000..28263ca
--- /dev/null
+++ b/src/storage/video_database/mod.rs
@@ -0,0 +1,170 @@
+// 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::{fmt::Write, path::PathBuf};
+
+use url::Url;
+
+use crate::{
+    constants::{DEFAULT_MPV_PLAYBACK_SPEED, DEFAULT_SUBTITLE_LANGS},
+    storage::video_database::extractor_hash::ExtractorHash,
+};
+
+pub mod downloader;
+pub mod extractor_hash;
+pub mod getters;
+pub mod setters;
+
+#[derive(Debug)]
+pub struct Video {
+    pub cache_path: Option<PathBuf>,
+    pub description: Option<String>,
+    pub duration: Option<f64>,
+    pub extractor_hash: ExtractorHash,
+    pub last_status_change: i64,
+    /// The associated subscription this video was fetched from (null, when the video was `add`ed)
+    pub parent_subscription_name: Option<String>,
+    pub priority: i64,
+    pub publish_date: Option<i64>,
+    pub status: VideoStatus,
+    /// The video is currently changing its state (for example from being `SELECT` to being `CACHE`)
+    pub status_change: bool,
+    pub thumbnail_url: Option<Url>,
+    pub title: String,
+    pub url: Url,
+}
+
+#[derive(Debug)]
+pub struct VideoOptions {
+    pub yt_dlp: YtDlpOptions,
+    pub mpv: MpvOptions,
+}
+impl VideoOptions {
+    pub(crate) fn new(subtitle_langs: String, playback_speed: f64) -> Self {
+        let yt_dlp = YtDlpOptions { subtitle_langs };
+        let mpv = MpvOptions { playback_speed };
+        Self { yt_dlp, mpv }
+    }
+
+    /// This will write out the options that are different from the defaults.
+    /// Beware, that this does not set the priority.
+    pub fn to_cli_flags(self) -> String {
+        let mut f = String::new();
+
+        if self.mpv.playback_speed != DEFAULT_MPV_PLAYBACK_SPEED {
+            write!(f, " --speed '{}'", self.mpv.playback_speed).expect("Works");
+        }
+        if self.yt_dlp.subtitle_langs != DEFAULT_SUBTITLE_LANGS {
+            write!(f, " --subtitle-langs '{}'", self.yt_dlp.subtitle_langs).expect("Works");
+        }
+
+        f.trim().to_owned()
+    }
+}
+
+#[derive(Debug)]
+/// Additionally settings passed to mpv on watch
+pub struct MpvOptions {
+    /// The playback speed. (1 is 100%, 2.7 is 270%, and so on)
+    pub playback_speed: f64,
+}
+
+#[derive(Debug)]
+/// Additionally configuration options, passed to yt-dlp on download
+pub struct YtDlpOptions {
+    /// In the form of `lang1,lang2,lang3` (e.g. `en,de,sv`)
+    pub subtitle_langs: String,
+}
+
+/// # Video Lifetime (words in <brackets> are commands):
+///      <Pick>
+///     /    \
+/// <Watch>   <Drop> -> Dropped // yt select
+///     |
+/// Cache                       // yt cache
+///     |
+/// Watched                     // yt watch
+#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub enum VideoStatus {
+    #[default]
+    Pick,
+
+    /// The video has been select to be watched
+    Watch,
+    /// The video has been cached and is ready to be watched
+    Cached,
+    /// The video has been watched
+    Watched,
+
+    /// The video has been select to be dropped
+    Drop,
+    /// The video has been dropped
+    Dropped,
+}
+
+impl VideoStatus {
+    pub fn as_command(&self) -> &str {
+        // NOTE: Keep the serialize able variants synced with the main `select` function <2024-06-14>
+        match self {
+            VideoStatus::Pick => "pick",
+
+            VideoStatus::Watch => "watch",
+            VideoStatus::Cached => "watch",
+            VideoStatus::Watched => "watch",
+
+            VideoStatus::Drop => "drop",
+            VideoStatus::Dropped => "drop",
+        }
+    }
+
+    pub fn as_db_integer(&self) -> i64 {
+        // These numbers should not change their mapping!
+        // Oh, and keep them in sync with the SQLite check constraint.
+        match self {
+            VideoStatus::Pick => 0,
+
+            VideoStatus::Watch => 1,
+            VideoStatus::Cached => 2,
+            VideoStatus::Watched => 3,
+
+            VideoStatus::Drop => 4,
+            VideoStatus::Dropped => 5,
+        }
+    }
+    pub fn from_db_integer(num: i64) -> Self {
+        match num {
+            0 => Self::Pick,
+
+            1 => Self::Watch,
+            2 => Self::Cached,
+            3 => Self::Watched,
+
+            4 => Self::Drop,
+            5 => Self::Dropped,
+            other => unreachable!(
+                "The database returned a enum discriminator, unknown to us: '{}'",
+                other
+            ),
+        }
+    }
+
+    pub fn as_str(&self) -> &'static str {
+        match self {
+            VideoStatus::Pick => "Pick",
+
+            VideoStatus::Watch => "Watch",
+            VideoStatus::Cached => "Cache",
+            VideoStatus::Watched => "Watched",
+
+            VideoStatus::Drop => "Drop",
+            VideoStatus::Dropped => "Dropped",
+        }
+    }
+}