about summary refs log tree commit diff stats
path: root/yt/src/storage/subscriptions.rs
diff options
context:
space:
mode:
Diffstat (limited to 'yt/src/storage/subscriptions.rs')
-rw-r--r--yt/src/storage/subscriptions.rs140
1 files changed, 140 insertions, 0 deletions
diff --git a/yt/src/storage/subscriptions.rs b/yt/src/storage/subscriptions.rs
new file mode 100644
index 0000000..22edd08
--- /dev/null
+++ b/yt/src/storage/subscriptions.rs
@@ -0,0 +1,140 @@
+// 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>.
+
+//! Handle subscriptions
+
+use std::collections::HashMap;
+
+use anyhow::Result;
+use log::debug;
+use serde_json::{json, Value};
+use sqlx::query;
+use url::Url;
+use yt_dlp::wrapper::info_json::InfoType;
+
+use crate::app::App;
+
+#[derive(Clone, Debug)]
+pub struct Subscription {
+    /// The human readable name of this subscription
+    pub name: String,
+
+    /// The URL this subscription subscribes to
+    pub url: Url,
+}
+
+impl Subscription {
+    pub fn new(name: String, url: Url) -> Self {
+        Self { name, url }
+    }
+}
+
+/// Check whether an URL could be used as a subscription URL
+pub async fn check_url(url: &Url) -> Result<bool> {
+    let yt_opts = match json!( {
+        "playliststart": 1,
+        "playlistend": 10,
+        "noplaylist": false,
+        "extract_flat": "in_playlist",
+    }) {
+        Value::Object(map) => map,
+        _ => unreachable!("This is hardcoded"),
+    };
+
+    let info = yt_dlp::extract_info(&yt_opts, url, false, false).await?;
+
+    debug!("{:#?}", info);
+
+    Ok(info._type == Some(InfoType::Playlist))
+}
+
+#[derive(Default)]
+pub struct Subscriptions(pub(crate) HashMap<String, Subscription>);
+
+pub async fn remove_all_subscriptions(app: &App) -> Result<()> {
+    query!(
+        "
+        DELETE FROM subscriptions;
+    ",
+    )
+    .execute(&app.database)
+    .await?;
+
+    Ok(())
+}
+
+/// Get a list of subscriptions
+pub async fn get_subscriptions(app: &App) -> Result<Subscriptions> {
+    let raw_subs = query!(
+        "
+        SELECT *
+        FROM subscriptions;
+    "
+    )
+    .fetch_all(&app.database)
+    .await?;
+
+    let subscriptions: HashMap<String, Subscription> = raw_subs
+        .into_iter()
+        .map(|sub| {
+            (
+                sub.name.clone(),
+                Subscription::new(
+                    sub.name,
+                    Url::parse(&sub.url).expect("This should be valid"),
+                ),
+            )
+        })
+        .collect();
+
+    Ok(Subscriptions(subscriptions))
+}
+
+pub async fn add_subscription(app: &App, sub: &Subscription) -> Result<()> {
+    let url = sub.url.to_string();
+
+    query!(
+        "
+        INSERT INTO subscriptions (
+            name,
+            url
+        ) VALUES (?, ?);
+    ",
+        sub.name,
+        url
+    )
+    .execute(&app.database)
+    .await?;
+
+    println!("Subscribed to '{}' at '{}'", sub.name, sub.url);
+    Ok(())
+}
+
+pub async fn remove_subscription(app: &App, sub: &Subscription) -> Result<()> {
+    let output = query!(
+        "
+        DELETE FROM subscriptions
+        WHERE name = ?
+    ",
+        sub.name,
+    )
+    .execute(&app.database)
+    .await?;
+
+    assert_eq!(
+        output.rows_affected(),
+        1,
+        "The remove subscriptino query did effect more (or less) than one row. This is a bug."
+    );
+
+    println!("Unsubscribed from '{}' at '{}'", sub.name, sub.url);
+
+    Ok(())
+}