From 1debeb77f7986de1b659dcfdc442de6415e1d9f5 Mon Sep 17 00:00:00 2001 From: Benedikt Peetz Date: Wed, 21 Aug 2024 10:49:23 +0200 Subject: chore: Initial Commit This repository was migrated out of my nixos-config. --- src/storage/video_database/getters.rs | 339 ++++++++++++++++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 src/storage/video_database/getters.rs (limited to 'src/storage/video_database/getters.rs') diff --git a/src/storage/video_database/getters.rs b/src/storage/video_database/getters.rs new file mode 100644 index 0000000..ca4164d --- /dev/null +++ b/src/storage/video_database/getters.rs @@ -0,0 +1,339 @@ +// 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 . + +//! These functions interact with the storage db in a read-only way. They are added on-demaned (as +//! you could theoretically just could do everything with the `get_videos` function), as +//! performance or convince requires. +use std::{fs::File, path::PathBuf}; + +use anyhow::{bail, Context, Result}; +use blake3::Hash; +use log::debug; +use sqlx::{query, QueryBuilder, Row, Sqlite}; +use url::Url; +use yt_dlp::wrapper::info_json::InfoJson; + +use crate::{ + app::App, + storage::{ + subscriptions::Subscription, + video_database::{extractor_hash::ExtractorHash, Video}, + }, +}; + +use super::{MpvOptions, VideoOptions, VideoStatus, YtDlpOptions}; + +macro_rules! video_from_record { + ($record:expr) => { + let thumbnail_url = if let Some(url) = &$record.thumbnail_url { + Some(Url::parse(&url)?) + } else { + None + }; + + Ok(Video { + cache_path: $record.cache_path.as_ref().map(|val| PathBuf::from(val)), + description: $record.description.clone(), + duration: $record.duration, + extractor_hash: ExtractorHash::from_hash( + $record + .extractor_hash + .parse() + .expect("The db hash should be a valid blake3 hash"), + ), + last_status_change: $record.last_status_change, + parent_subscription_name: $record.parent_subscription_name.clone(), + publish_date: $record.publish_date, + status: VideoStatus::from_db_integer($record.status), + thumbnail_url, + title: $record.title.clone(), + url: Url::parse(&$record.url)?, + priority: $record.priority, + status_change: if $record.status_change == 1 { + true + } else { + assert_eq!($record.status_change, 0); + false + }, + }) + }; +} + +/// Get the lines to display at the selection file +/// [`changing` = true]: Means that we include *only* videos, that have the `status_changing` flag set +/// [`changing` = None]: Means that we include *both* videos, that have the `status_changing` flag set and not set +pub async fn get_videos( + app: &App, + allowed_states: &[VideoStatus], + changing: Option, +) -> Result> { + let mut qb: QueryBuilder = QueryBuilder::new( + "\ + SELECT * + FROM videos + WHERE status IN ", + ); + + qb.push("("); + allowed_states + .iter() + .enumerate() + .for_each(|(index, state)| { + qb.push("'"); + qb.push(state.as_db_integer()); + qb.push("'"); + + if index != allowed_states.len() - 1 { + qb.push(","); + } + }); + qb.push(")"); + + if let Some(val) = changing { + if val { + qb.push(" AND status_change = 1"); + } else { + qb.push(" AND status_change = 0"); + } + } + + qb.push("\n ORDER BY priority DESC;"); + + debug!("Will run: \"{}\"", qb.sql()); + + let videos = qb.build().fetch_all(&app.database).await.with_context(|| { + format!( + "Failed to query videos with states: '{}'", + allowed_states.iter().fold(String::new(), |mut acc, state| { + acc.push(' '); + acc.push_str(&state.as_str()); + acc + }), + ) + })?; + + let real_videos: Vec