From c740e0df0e83d45a881cc07d97bb98c7423a589a Mon Sep 17 00:00:00 2001 From: John Rogers Date: Sun, 17 Aug 2025 14:16:24 +0100 Subject: [PATCH] feat: load settings from a configuration file Co-authored-by: aider (gemini/gemini-2.5-pro-preview-05-06) --- Cargo.toml | 3 +++ src/main.rs | 54 +++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ad29e98..2be4c81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,5 +8,8 @@ edition = "2021" [dependencies] anyhow = "1.0.82" clap = { version = "4.5.4", features = ["derive"] } +config = "0.14.0" +dirs = "5.0.1" fs_extra = "1.3.0" +serde = { version = "1.0", features = ["derive"] } tempfile = "3.10.1" diff --git a/src/main.rs b/src/main.rs index c636a54..b37a47f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,18 @@ use anyhow::{Context, Result}; use clap::Parser; +use serde::Deserialize; use std::fs; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::process::Command; use tempfile::TempDir; -// ==== CONFIGURATION ==== -const NAS_HOST: &str = "(localaddress)"; -const NAS_USER: &str = "ssh_user"; -const NAS_PATH: &str = "/path/to/files/on/nas"; -const COOKIES_FILE: &str = "/location/of/apple-music-cookies-file.txt"; +#[derive(Debug, Deserialize)] +struct Settings { + nas_host: String, + nas_user: String, + nas_path: String, + cookies_file: String, +} #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] @@ -22,6 +25,22 @@ struct Args { fn main() -> Result<()> { let args = Args::parse(); + let config_path = dirs::config_dir() + .context("Could not find config directory")? + .join("jamdl/config.toml"); + + if !config_path.exists() { + anyhow::bail!( + "Config file not found. Please create it at: {}", + config_path.display() + ); + } + + let settings = config::Config::builder() + .add_source(config::File::from(config_path)) + .build()? + .try_deserialize::()?; + // Create temp directory let temp_dir = TempDir::new().context("Failed to create temporary directory")?; let temp_path = temp_dir.path(); @@ -30,26 +49,26 @@ fn main() -> Result<()> { temp_path.display() ); - download_media(&args.url, temp_path)?; - transfer_files(temp_path)?; + download_media(&args.url, temp_path, &settings)?; + transfer_files(temp_path, &settings)?; // Cleanup is handled by TempDir's Drop trait println!("[INFO] Cleaning up..."); Ok(()) } -fn download_media(video_url: &str, download_path: &Path) -> Result<()> { +fn download_media(video_url: &str, download_path: &Path, settings: &Settings) -> Result<()> { let mut cmd: Command; if video_url.contains("music.apple.com") { println!("[INFO] Apple Music link detected. Using gamdl..."); cmd = Command::new("gamdl"); - if Path::new(COOKIES_FILE).exists() { - cmd.args(["--cookies-path", COOKIES_FILE, video_url]); + if Path::new(&settings.cookies_file).exists() { + cmd.args(["--cookies-path", &settings.cookies_file, video_url]); } else { println!( "[WARN] cookies.txt not found at {} — running gamdl without it", - COOKIES_FILE + settings.cookies_file ); cmd.arg(video_url); } @@ -75,15 +94,15 @@ fn download_media(video_url: &str, download_path: &Path) -> Result<()> { Ok(()) } -fn transfer_files(source_path: &Path) -> Result<()> { +fn transfer_files(source_path: &Path, settings: &Settings) -> Result<()> { let is_empty = fs::read_dir(source_path)?.next().is_none(); if !is_empty { - if NAS_HOST == "localhost" { + if settings.nas_host == "localhost" { println!("[INFO] NAS_HOST is localhost, copying files locally..."); let mut options = fs_extra::dir::CopyOptions::new(); options.content_only = true; - fs_extra::dir::copy(source_path, NAS_PATH, &options) + fs_extra::dir::copy(source_path, &settings.nas_path, &options) .context("Failed to copy files locally")?; } else { println!("[INFO] Transferring files to NAS via scp..."); @@ -92,7 +111,10 @@ fn transfer_files(source_path: &Path) -> Result<()> { "{}/.", source_path.to_str().context("Invalid source path")? ); - let destination = format!("{}@{}:{}", NAS_USER, NAS_HOST, NAS_PATH); + let destination = format!( + "{}@{}:{}", + settings.nas_user, settings.nas_host, settings.nas_path + ); scp_cmd.args(["-r", &source, &destination]); let status = scp_cmd.status().context("Failed to execute scp")?;