// yt - A fully featured command line YouTube client // // Copyright (C) 2024 Benedikt Peetz // 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 . //! 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 { 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); 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 { let raw_subs = query!( " SELECT * FROM subscriptions; " ) .fetch_all(&app.database) .await?; let subscriptions: HashMap = 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(()) }