refactor
This commit is contained in:
parent
222bf160dc
commit
75bd4f49c1
8 changed files with 150 additions and 127 deletions
|
@ -2,24 +2,24 @@ use std::path::PathBuf;
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::yt_dlp::YtDlpConfig;
|
use crate::yt_dlp::config::YtDlpConfig;
|
||||||
|
|
||||||
/// General settings for hoard
|
/// General settings for hoard
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct HoardConfig {
|
pub struct HoardConfig {
|
||||||
// Top level data download directory
|
/// Top level data download directory
|
||||||
pub data_dir: PathBuf,
|
pub data_dir: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Top level global config
|
/// Top level global config
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct GlobalConfig {
|
pub struct GlobalConfig {
|
||||||
// Hoard Configuration
|
/// Hoard Configuration
|
||||||
pub hoard: HoardConfig,
|
pub hoard: HoardConfig,
|
||||||
// Configuration for the YouTube Module
|
/// Configuration for the `YouTube` Module
|
||||||
pub youtube: Option<crate::youtube::YouTubeConfig>,
|
pub youtube: Option<crate::youtube::YouTubeConfig>,
|
||||||
// Configuration for the SoundCloud Module
|
/// Configuration for the `SoundCloud` Module
|
||||||
pub soundcloud: Option<crate::soundcloud::SoundCloudConfig>,
|
pub soundcloud: Option<crate::soundcloud::SoundCloudConfig>,
|
||||||
// Custom instances of yt-dlp
|
/// Custom instances of `yt-dlp`
|
||||||
pub yt_dlp: Option<Vec<YtDlpConfig>>,
|
pub yt_dlp: Option<Vec<YtDlpConfig>>,
|
||||||
}
|
}
|
||||||
|
|
16
src/db.rs
16
src/db.rs
|
@ -123,10 +123,24 @@ impl Database {
|
||||||
Self { conn }
|
Self { conn }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Insert a URL into the database as already downloaded
|
||||||
pub fn insert_url(&self, url: &str) {
|
pub fn insert_url(&self, url: &str) {
|
||||||
self.conn.send(Query::InsertUrl(url.to_string()));
|
self.conn.send(Query::InsertUrl(url.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if a URL is already in the database
|
||||||
|
///
|
||||||
|
/// # Return
|
||||||
|
/// Returns `true` if already present, `false` otherwise
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// You could use this function like that:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// if !db.check_for_url(some_url) {
|
||||||
|
/// // do download
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn check_for_url(&self, url: &str) -> bool {
|
pub fn check_for_url(&self, url: &str) -> bool {
|
||||||
match self.conn.send(Query::CheckForUrl(url.to_string())) {
|
match self.conn.send(Query::CheckForUrl(url.to_string())) {
|
||||||
Out::Ok => false,
|
Out::Ok => false,
|
||||||
|
@ -134,6 +148,8 @@ impl Database {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Keep a record on when download happen.
|
||||||
|
/// This takes a `module`, `name` and `url` and saves a timestamp to the db.
|
||||||
pub fn update_new_downloads(&self, module: &str, name: &str, url: &str) {
|
pub fn update_new_downloads(&self, module: &str, name: &str, url: &str) {
|
||||||
self.conn.send(Query::UpdateNewDownloads(
|
self.conn.send(Query::UpdateNewDownloads(
|
||||||
module.to_string(),
|
module.to_string(),
|
||||||
|
|
24
src/lib.rs
Normal file
24
src/lib.rs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
pub mod config;
|
||||||
|
pub mod db;
|
||||||
|
pub mod soundcloud;
|
||||||
|
pub mod youtube;
|
||||||
|
pub mod yt_dlp;
|
||||||
|
|
||||||
|
pub fn ensure_dir_exists(dir_path: &PathBuf) {
|
||||||
|
let path = std::path::Path::new(dir_path);
|
||||||
|
if !path.exists() {
|
||||||
|
std::fs::create_dir_all(path).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generic module implementation
|
||||||
|
///
|
||||||
|
/// Each module gets it's own thread to work for itself.
|
||||||
|
pub trait Module: Send {
|
||||||
|
/// friendly name for module
|
||||||
|
fn name(&self) -> String;
|
||||||
|
/// module main loop
|
||||||
|
fn run(&self);
|
||||||
|
}
|
45
src/main.rs
45
src/main.rs
|
@ -1,30 +1,9 @@
|
||||||
use std::path::PathBuf;
|
use hoard::config::GlobalConfig;
|
||||||
|
use hoard::{ensure_dir_exists, Module};
|
||||||
mod config;
|
|
||||||
mod db;
|
|
||||||
mod soundcloud;
|
|
||||||
mod youtube;
|
|
||||||
mod yt_dlp;
|
|
||||||
|
|
||||||
use config::GlobalConfig;
|
|
||||||
|
|
||||||
use crate::yt_dlp::YtDlpModule;
|
|
||||||
|
|
||||||
// todo : migrate to async code?
|
// todo : migrate to async code?
|
||||||
// todo : better log options
|
// todo : better log options
|
||||||
|
|
||||||
pub fn ensure_dir_exists(dir_path: &PathBuf) {
|
|
||||||
let path = std::path::Path::new(dir_path);
|
|
||||||
if !path.exists() {
|
|
||||||
std::fs::create_dir_all(path).unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait Module: Send {
|
|
||||||
fn name(&self) -> String;
|
|
||||||
fn run(&self);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
|
@ -42,19 +21,23 @@ fn main() {
|
||||||
|
|
||||||
log::info!("Starting hoard");
|
log::info!("Starting hoard");
|
||||||
|
|
||||||
let db = db::DatabaseBackend::new("data/download.db");
|
let db = hoard::db::DatabaseBackend::new("data/download.db");
|
||||||
let config: GlobalConfig =
|
let config: GlobalConfig =
|
||||||
toml::from_str(&std::fs::read_to_string("config.toml").unwrap()).unwrap();
|
toml::from_str(&std::fs::read_to_string("config.toml").unwrap()).unwrap();
|
||||||
ensure_dir_exists(&config.hoard.data_dir);
|
ensure_dir_exists(&config.hoard.data_dir);
|
||||||
|
|
||||||
let mut modules: Vec<Box<dyn Module>> = vec![Box::new(youtube::YouTubeModule::new(
|
let mut modules: Vec<Box<dyn Module>> = vec![];
|
||||||
config.youtube.unwrap(),
|
|
||||||
db.take_db(),
|
if let Some(yt_config) = config.youtube {
|
||||||
config.hoard.data_dir.join("youtube"),
|
modules.push(Box::new(hoard::youtube::YouTubeModule::new(
|
||||||
))];
|
yt_config,
|
||||||
|
db.take_db(),
|
||||||
|
config.hoard.data_dir.join("youtube"),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(sc_config) = config.soundcloud {
|
if let Some(sc_config) = config.soundcloud {
|
||||||
modules.push(Box::new(soundcloud::SoundCloudModule::new(
|
modules.push(Box::new(hoard::soundcloud::SoundCloudModule::new(
|
||||||
sc_config,
|
sc_config,
|
||||||
db.take_db(),
|
db.take_db(),
|
||||||
config.hoard.data_dir.join("soundcloud"),
|
config.hoard.data_dir.join("soundcloud"),
|
||||||
|
@ -66,7 +49,7 @@ fn main() {
|
||||||
.name
|
.name
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| "yt_dlp".to_string());
|
.unwrap_or_else(|| "yt_dlp".to_string());
|
||||||
modules.push(Box::new(YtDlpModule::new(
|
modules.push(Box::new(hoard::yt_dlp::YtDlpModule::new(
|
||||||
yt_dlp_mod,
|
yt_dlp_mod,
|
||||||
db.take_db(),
|
db.take_db(),
|
||||||
config.hoard.data_dir.join(mod_name),
|
config.hoard.data_dir.join(mod_name),
|
||||||
|
|
|
@ -3,46 +3,46 @@ use std::{collections::HashMap, path::PathBuf};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
yt_dlp::{YtDlpConfig, YtDlpModule},
|
yt_dlp::{config::YtDlpConfig, YtDlpModule},
|
||||||
Module,
|
Module,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Configuration for the `SoundCloud` Module
|
/// Configuration for the `SoundCloud` Module
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct SoundCloudConfig {
|
pub struct SoundCloudConfig {
|
||||||
// Interval in minutes between checks
|
/// Interval in minutes between checks
|
||||||
pub interval: u64,
|
pub interval: u64,
|
||||||
/// Amount of items to query
|
/// Amount of items to query
|
||||||
pub limit: Option<u64>,
|
pub limit: Option<u64>,
|
||||||
// Items to check
|
/// Items to check
|
||||||
pub artists: HashMap<String, toml::Value>,
|
pub artists: HashMap<String, toml::Value>,
|
||||||
// Output Template for yt-dlp
|
/// Output Template for yt-dlp
|
||||||
pub output_format: Option<String>,
|
pub output_format: Option<String>,
|
||||||
// Download comments
|
/// Download comments
|
||||||
pub write_comments: Option<bool>,
|
pub write_comments: Option<bool>,
|
||||||
// Download description
|
/// Download description
|
||||||
pub write_description: Option<bool>,
|
pub write_description: Option<bool>,
|
||||||
// Download cover
|
/// Download cover
|
||||||
pub write_cover: Option<bool>,
|
pub write_cover: Option<bool>,
|
||||||
// Download subtitles
|
/// Download subtitles
|
||||||
pub write_subs: Option<bool>,
|
pub write_subs: Option<bool>,
|
||||||
// Audio Format
|
/// Audio Format
|
||||||
pub audio_format: Option<String>,
|
pub audio_format: Option<String>,
|
||||||
// Embed thumbnail
|
/// Embed thumbnail
|
||||||
pub embed_thumbnail: Option<bool>,
|
pub embed_thumbnail: Option<bool>,
|
||||||
// Embed metadata
|
/// Embed metadata
|
||||||
pub embed_metadata: Option<bool>,
|
pub embed_metadata: Option<bool>,
|
||||||
// Embed chapters
|
/// Embed chapters
|
||||||
pub embed_chapters: Option<bool>,
|
pub embed_chapters: Option<bool>,
|
||||||
// Embed info.json
|
/// Embed info.json
|
||||||
pub embed_info_json: Option<bool>,
|
pub embed_info_json: Option<bool>,
|
||||||
// Split by chapter
|
/// Split by chapter
|
||||||
pub split_chapters: Option<bool>,
|
pub split_chapters: Option<bool>,
|
||||||
// Format Selection
|
/// Format Selection
|
||||||
pub format: Option<String>,
|
pub format: Option<String>,
|
||||||
// Cookie File
|
/// Cookie File
|
||||||
pub cookie: Option<String>,
|
pub cookie: Option<String>,
|
||||||
// Webhooks for notifications
|
/// Webhooks for notifications
|
||||||
pub webhooks: Option<Vec<String>>,
|
pub webhooks: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,51 +2,48 @@ use std::{collections::HashMap, path::PathBuf};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{yt_dlp::config::YtDlpConfig, yt_dlp::YtDlpModule, Module};
|
||||||
yt_dlp::{YtDlpConfig, YtDlpModule},
|
|
||||||
Module,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Configuration for the `YouTube` Module
|
/// Configuration for the `YouTube` Module
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct YouTubeConfig {
|
pub struct YouTubeConfig {
|
||||||
// Interval in minutes between checks
|
/// Interval in minutes between checks
|
||||||
interval: u64,
|
interval: u64,
|
||||||
/// Amount of videos to query
|
/// Amount of videos to query
|
||||||
limit: Option<u64>,
|
limit: Option<u64>,
|
||||||
// Channels to check
|
/// Channels to check
|
||||||
channels: HashMap<String, toml::Value>,
|
channels: HashMap<String, toml::Value>,
|
||||||
// Format of the Thumbnail
|
/// Format of the Thumbnail
|
||||||
thumbnail_format: Option<String>,
|
thumbnail_format: Option<String>,
|
||||||
// Output Template for yt-dlp
|
/// Output Template for yt-dlp
|
||||||
output_format: Option<String>,
|
output_format: Option<String>,
|
||||||
// Download description
|
/// Download description
|
||||||
pub write_description: Option<bool>,
|
pub write_description: Option<bool>,
|
||||||
// Download info.json
|
/// Download info.json
|
||||||
pub write_info_json: Option<bool>,
|
pub write_info_json: Option<bool>,
|
||||||
// Download comments
|
/// Download comments
|
||||||
pub write_comments: Option<bool>,
|
pub write_comments: Option<bool>,
|
||||||
// Download thumbnail
|
/// Download thumbnail
|
||||||
pub write_thumbnail: Option<bool>,
|
pub write_thumbnail: Option<bool>,
|
||||||
// Download subtitles
|
/// Download subtitles
|
||||||
pub write_subs: Option<bool>,
|
pub write_subs: Option<bool>,
|
||||||
// Embed subtitles
|
/// Embed subtitles
|
||||||
pub embed_subs: Option<bool>,
|
pub embed_subs: Option<bool>,
|
||||||
// Embed thumbnail
|
/// Embed thumbnail
|
||||||
pub embed_thumbnail: Option<bool>,
|
pub embed_thumbnail: Option<bool>,
|
||||||
// Embed metadata
|
/// Embed metadata
|
||||||
pub embed_metadata: Option<bool>,
|
pub embed_metadata: Option<bool>,
|
||||||
// Embed chapters
|
/// Embed chapters
|
||||||
embed_chapters: Option<bool>,
|
embed_chapters: Option<bool>,
|
||||||
// Embed info.json
|
/// Embed info.json
|
||||||
pub embed_info_json: Option<bool>,
|
pub embed_info_json: Option<bool>,
|
||||||
// Split by chapter
|
/// Split by chapter
|
||||||
pub split_chapters: Option<bool>,
|
pub split_chapters: Option<bool>,
|
||||||
// Format Selection
|
/// Format Selection
|
||||||
pub format: Option<String>,
|
pub format: Option<String>,
|
||||||
// Cookie File
|
/// Cookie File
|
||||||
pub cookie: Option<String>,
|
pub cookie: Option<String>,
|
||||||
// Webhooks for notifications
|
/// Webhooks for notifications
|
||||||
pub webhooks: Option<Vec<String>>,
|
pub webhooks: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
52
src/yt_dlp/config.rs
Normal file
52
src/yt_dlp/config.rs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// Configuration for the `YouTube` Module
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct YtDlpConfig {
|
||||||
|
/// Module Name
|
||||||
|
pub name: Option<String>,
|
||||||
|
/// Interval in minutes between checks
|
||||||
|
pub interval: u64,
|
||||||
|
/// Amount of items to query
|
||||||
|
pub limit: Option<u64>,
|
||||||
|
/// Items to check
|
||||||
|
pub items: HashMap<String, toml::Value>,
|
||||||
|
/// Format of the Thumbnail
|
||||||
|
pub thumbnail_format: Option<String>,
|
||||||
|
/// Output Template for yt-dlp
|
||||||
|
pub output_format: Option<String>,
|
||||||
|
/// Download description
|
||||||
|
pub write_description: Option<bool>,
|
||||||
|
/// Download info.json
|
||||||
|
pub write_info_json: Option<bool>,
|
||||||
|
/// Download comments
|
||||||
|
pub write_comments: Option<bool>,
|
||||||
|
/// Download thumbnail
|
||||||
|
pub write_thumbnail: Option<bool>,
|
||||||
|
/// Download subtitles
|
||||||
|
pub write_subs: Option<bool>,
|
||||||
|
/// Extract audio
|
||||||
|
pub audio_only: Option<bool>,
|
||||||
|
/// Audio Format
|
||||||
|
pub audio_format: Option<String>,
|
||||||
|
/// Embed subtitles
|
||||||
|
pub embed_subs: Option<bool>,
|
||||||
|
/// Embed thumbnail
|
||||||
|
pub embed_thumbnail: Option<bool>,
|
||||||
|
/// Embed metadata
|
||||||
|
pub embed_metadata: Option<bool>,
|
||||||
|
/// Embed chapters
|
||||||
|
pub embed_chapters: Option<bool>,
|
||||||
|
/// Embed info.json
|
||||||
|
pub embed_info_json: Option<bool>,
|
||||||
|
/// Split by chapter
|
||||||
|
pub split_chapters: Option<bool>,
|
||||||
|
/// Format Selection
|
||||||
|
pub format: Option<String>,
|
||||||
|
/// Cookie File
|
||||||
|
pub cookie: Option<String>,
|
||||||
|
/// Webhooks for notifications
|
||||||
|
pub webhooks: Option<Vec<String>>,
|
||||||
|
}
|
|
@ -1,63 +1,14 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
|
||||||
io::{BufRead, BufReader},
|
io::{BufRead, BufReader},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
process::Command,
|
process::Command,
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
pub mod config;
|
||||||
|
use config::YtDlpConfig;
|
||||||
|
|
||||||
use crate::{ensure_dir_exists, Module};
|
use crate::{ensure_dir_exists, Module};
|
||||||
|
|
||||||
/// Configuration for the `YouTube` Module
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
||||||
pub struct YtDlpConfig {
|
|
||||||
// Module Name
|
|
||||||
pub name: Option<String>,
|
|
||||||
// Interval in minutes between checks
|
|
||||||
pub interval: u64,
|
|
||||||
/// Amount of items to query
|
|
||||||
pub limit: Option<u64>,
|
|
||||||
// Items to check
|
|
||||||
pub items: HashMap<String, toml::Value>,
|
|
||||||
// Format of the Thumbnail
|
|
||||||
pub thumbnail_format: Option<String>,
|
|
||||||
// Output Template for yt-dlp
|
|
||||||
pub output_format: Option<String>,
|
|
||||||
// Download description
|
|
||||||
pub write_description: Option<bool>,
|
|
||||||
// Download info.json
|
|
||||||
pub write_info_json: Option<bool>,
|
|
||||||
// Download comments
|
|
||||||
pub write_comments: Option<bool>,
|
|
||||||
// Download thumbnail
|
|
||||||
pub write_thumbnail: Option<bool>,
|
|
||||||
// Download subtitles
|
|
||||||
pub write_subs: Option<bool>,
|
|
||||||
// Extract audio
|
|
||||||
pub audio_only: Option<bool>,
|
|
||||||
// Audio Format
|
|
||||||
pub audio_format: Option<String>,
|
|
||||||
// Embed subtitles
|
|
||||||
pub embed_subs: Option<bool>,
|
|
||||||
// Embed thumbnail
|
|
||||||
pub embed_thumbnail: Option<bool>,
|
|
||||||
// Embed metadata
|
|
||||||
pub embed_metadata: Option<bool>,
|
|
||||||
// Embed chapters
|
|
||||||
pub embed_chapters: Option<bool>,
|
|
||||||
// Embed info.json
|
|
||||||
pub embed_info_json: Option<bool>,
|
|
||||||
// Split by chapter
|
|
||||||
pub split_chapters: Option<bool>,
|
|
||||||
// Format Selection
|
|
||||||
pub format: Option<String>,
|
|
||||||
// Cookie File
|
|
||||||
pub cookie: Option<String>,
|
|
||||||
// Webhooks for notifications
|
|
||||||
pub webhooks: Option<Vec<String>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct YtDlpModule {
|
pub struct YtDlpModule {
|
||||||
config: YtDlpConfig,
|
config: YtDlpConfig,
|
||||||
|
|
Loading…
Add table
Reference in a new issue