diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..be5b04c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "jamdl" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.82" +clap = { version = "4.5.4", features = ["derive"] } +tempfile = "3.10.1" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..e4f408b --- /dev/null +++ b/src/main.rs @@ -0,0 +1,100 @@ +use anyhow::{Context, Result}; +use clap::Parser; +use std::fs; +use std::path::Path; +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(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + /// The URL of the video/music to download + #[arg(name = "URL")] + url: String, +} + +fn main() -> Result<()> { + let args = Args::parse(); + + // Create temp directory + let temp_dir = TempDir::new().context("Failed to create temporary directory")?; + let temp_path = temp_dir.path(); + println!( + "[INFO] Created temporary directory at: {}", + temp_path.display() + ); + + download_media(&args.url, temp_path)?; + transfer_files(temp_path)?; + + // Cleanup is handled by TempDir's Drop trait + println!("[INFO] Cleaning up..."); + Ok(()) +} + +fn download_media(video_url: &str, download_path: &Path) -> 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]); + } else { + println!( + "[WARN] cookies.txt not found at {} — running gamdl without it", + COOKIES_FILE + ); + cmd.arg(video_url); + } + } else if video_url.contains("soundcloud.com") { + println!("[INFO] Soundcloud link detected. Using scdl..."); + cmd = Command::new("scdl"); + cmd.args(["-l", video_url]); + } else { + println!("[INFO] Non-Apple Music link. Using yt-dlp..."); + cmd = Command::new("yt-dlp"); + cmd.args(["-o", "%(title)s.%(ext)s", video_url]); + } + + cmd.current_dir(download_path); + let status = cmd + .status() + .with_context(|| format!("Failed to execute command: {:?}", cmd))?; + + if !status.success() { + anyhow::bail!("Download command failed with status: {}", status); + } + + Ok(()) +} + +fn transfer_files(source_path: &Path) -> Result<()> { + let is_empty = fs::read_dir(source_path)?.next().is_none(); + + if !is_empty { + println!("[INFO] Transferring files to NAS..."); + let mut scp_cmd = Command::new("scp"); + let source = format!( + "{}/.", + source_path.to_str().context("Invalid source path")? + ); + let destination = format!("{}@{}:{}", NAS_USER, NAS_HOST, NAS_PATH); + scp_cmd.args(["-r", &source, &destination]); + + let status = scp_cmd.status().context("Failed to execute scp")?; + if !status.success() { + anyhow::bail!("scp failed with status: {}", status); + } + } else { + println!("[WARN] No files found to transfer."); + } + + Ok(()) +}