about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--yt/src/select/cmds/add.rs38
1 files changed, 36 insertions, 2 deletions
diff --git a/yt/src/select/cmds/add.rs b/yt/src/select/cmds/add.rs
index 7d6da0f..89d50c0 100644
--- a/yt/src/select/cmds/add.rs
+++ b/yt/src/select/cmds/add.rs
@@ -1,7 +1,9 @@
 use crate::{
     app::App,
     download::download_options::download_opts,
-    storage::video_database::{self, setters::add_video},
+    storage::video_database::{
+        self, extractor_hash::ExtractorHash, getters::get_all_hashes, setters::add_video,
+    },
     unreachable::Unreachable,
     update::video_entry_to_video,
     videos::display::format_video::FormatVideo,
@@ -13,6 +15,7 @@ use serde_json::{Map, Value};
 use url::Url;
 use yt_dlp::wrapper::info_json::InfoType;
 
+#[allow(clippy::too_many_lines)]
 pub(super) async fn add(
     app: &App,
     urls: Vec<Url>,
@@ -39,6 +42,37 @@ pub(super) async fn add(
         }
 
         async fn add_entry(app: &App, entry: yt_dlp::wrapper::info_json::InfoJson) -> Result<()> {
+            // We have to re-fetch all hashes every time, because a user could try to add the same
+            // URL twice (for whatever reason.)
+            let hashes = get_all_hashes(app)
+                .await
+                .context("Failed to fetch all video hashes")?;
+            let extractor_hash = blake3::hash(
+                entry
+                    .id
+                    .as_ref()
+                    .expect("This should be some at this point")
+                    .as_bytes(),
+            );
+            if hashes.contains(&extractor_hash) {
+                error!(
+                    "Video '{}'{} is already in the database. Skipped adding it",
+                    ExtractorHash::from_hash(extractor_hash)
+                        .into_short_hash(app)
+                        .await
+                        .with_context(|| format!(
+                            "Failed to format hash of video '{}' as short hash",
+                            entry
+                                .url
+                                .map_or("<Unknown video Url>".to_owned(), |url| url.to_string())
+                        ))?,
+                    entry
+                        .title
+                        .map_or(String::new(), |title| format!(" ('{title}')"))
+                );
+                return Ok(());
+            }
+
             let video = video_entry_to_video(entry, None)?;
             add_video(app, video.clone()).await?;
 
@@ -63,7 +97,7 @@ pub(super) async fn add(
                 add_entry(app, entry).await?;
                 if start.is_some() || stop.is_some() {
                     warn!(
-                        "You added `start` and `stop` markers for a single /video/! These will be ignored."
+                        "You added `start` and/or `stop` markers for a single *video*! These will be ignored."
                     );
                 }
             }