From cb2520be03a1098db7a02b6761e1bd643665a627 Mon Sep 17 00:00:00 2001 From: MrDulfin Date: Tue, 12 Nov 2024 11:13:08 -0500 Subject: [PATCH] Added download function and default download directory to the config --- confetti-cli/src/main.rs | 140 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 130 insertions(+), 10 deletions(-) diff --git a/confetti-cli/src/main.rs b/confetti-cli/src/main.rs index 05691ac..a9757b2 100644 --- a/confetti-cli/src/main.rs +++ b/confetti-cli/src/main.rs @@ -7,7 +7,7 @@ use owo_colors::OwoColorize as _; use reqwest::Client; use serde::{Deserialize, Serialize}; use thiserror::Error; -use tokio::{fs::File, io::AsyncReadExt, task::JoinSet}; +use tokio::{fs::{create_dir, File}, io::{AsyncReadExt, AsyncWriteExt}, task::JoinSet}; use uuid::Uuid; use clap::{arg, builder::{styling::RgbColor, Styles}, Parser, Subcommand}; use anyhow::{anyhow, bail, Context as _, Result}; @@ -20,6 +20,7 @@ const CLAP_STYLE: Styles = Styles::styled() .error(RgbColor::on_default(RgbColor(181,66,127)).underline()); const DEBUG_CONFIG: &str = "test/config.toml"; +const DEBUG_DOWNLOAD_DIR: &str = "test/downloads/"; #[derive(Parser)] #[command(name = "confetti_cli")] @@ -55,15 +56,22 @@ enum Commands { /// Set the URL of the server to connect to #[arg(long, required = false)] url: Option, + /// Set the directory to download into by default + #[arg(value_name="directory", short_alias='d', long, required = false)] + dl_dir: Option, }, /// Get server information manually Info, /// Download files + #[command(visible_alias="d")] Download { /// MMID to download - mmid: String, + #[arg(value_name = "mmid(s)", required = true)] + mmids: Vec, + #[arg(short, long, value_name = "out", required = false)] + out_directory: Option }, } @@ -137,15 +145,99 @@ async fn main() -> Result<()> { ); } } - Commands::Download { mmid } => { - todo!(); + Commands::Download { mmids, out_directory } => { + let out_directory = if let Some(dir) = out_directory { + dir + } else { + let ddir = &config.download_directory; + if ddir.as_os_str().is_empty() { + exit_error( + "Default download directory is empty".into(), + Some(format!("Please set it using the {} command", "set".truecolor(246,199,219).bold())), + None, + ); + } else if !ddir.exists() { + exit_error( + format!("Default download directory {} does not exist", ddir.display()), + Some(format!("Please set it using the {} command", "set".truecolor(246,199,219).bold())), + None, + ) + } else { + ddir + } + }; + + let url = &config.url; + for mmid in mmids { + let mmid = if mmid.len() != 8 { + if mmid.contains(format!("{url}/f/").as_str()) { + let mmid = mmid.replace(format!("{url}/f/").as_str(), ""); + if mmid.len() != 8 { + exit_error("{mmid} is not a valid MMID".into(), Some("MMID must be 8 characters long".into()), None) + } else { + mmid + } + } else { + exit_error("{mmid} is not a valid MMID".into(), Some("MMID must be 8 characters long".into()), None) + } + } else { + unimplemented!(); + }; + + let client = Client::new(); + + let info = if let Ok(file) = if let Some(login) = &config.login { + client.get(format!("{}/info/{mmid}", url)) + .basic_auth(&login.user, Some(&login.pass)) + } else { + client.get(format!("{}/info/{mmid}", url)) + } + .send() + .await + .unwrap() + .json::() + .await { + file + } else { + exit_error(format!("File with MMID {mmid} was not found"), None, None) + }; + + let mut file_res = if let Some(login) = &config.login { + client.get(format!("{}/f/{mmid}", config.url)) + .basic_auth(&login.user, Some(&login.pass)) + } else { + client.get(format!("{}/f/{mmid}", config.url)) + } + .send() + .await + .unwrap(); + + let out_directory = out_directory.join(info.name); + let mut out_file: File = tokio::fs::OpenOptions::new() + .create(true) + .append(true) + .read(true) + .open(&out_directory).await + .unwrap(); + + while let Some(next) = file_res.chunk().await.unwrap() { + out_file.write(&next).await.unwrap(); + } + + println!("Downloaded to {}", out_directory.display()); + } } - Commands::Set { username, password, url } => { - if username.is_none() && password.is_none() && url.is_none() { + Commands::Set { + username, + password, + url, + dl_dir + } => { + if username.is_none() && password.is_none() && url.is_none() && dl_dir.is_none() { exit_error( format!("Please provide an option to set"), Some(format!("Allowed options:")), - Some(vec!["--username".into(), "--password".into(), "--url".into()]), + Some(vec!["--username".into(), "--password".into(), "--url".into(), "--dl-dir".into()]), ); } @@ -164,7 +256,7 @@ async fn main() -> Result<()> { } config.save().unwrap(); - println!("Set username to \"{u}\"") + println!("Username set to \"{u}\"") } if let Some(p) = password { if p.is_empty() { @@ -181,7 +273,7 @@ async fn main() -> Result<()> { } config.save().unwrap(); - println!("Set password") + println!("Password set") } if let Some(url) = url { if url.is_empty() { @@ -196,7 +288,32 @@ async fn main() -> Result<()> { config.url = url.to_string(); config.save().unwrap(); - println!("Set URL to \"{url}\""); + println!("URL set to \"{url}\""); + } + if let Some(mut dir) = dl_dir.clone() { + if dir.is_empty() { + exit_error(format!("Download directory cannot be blank"), None, None); + } + if dir.as_str() == "default" { + dir = directories::UserDirs::new() + .unwrap() + .download_dir() + .unwrap_or_else(|| exit_error("No Default directory available".into(), None, None)) + .to_string_lossy() + .to_string(); + } + if dir.chars().last() != Some('/') { + dir.push('/'); + } + + let _dir = PathBuf::from(dir.clone()); + if !_dir.exists() { + exit_error(format!("Directory {dir} does not exist"), None, None) + } + + config.download_directory = _dir; + config.save().unwrap(); + println!("Download directory set to \"{dir}\""); } } Commands::Info => { @@ -460,6 +577,7 @@ struct Config { /// The time when the info was last fetched info_fetch: Option>, info: Option, + download_directory: PathBuf, } impl Config { @@ -473,6 +591,7 @@ impl Config { login: None, info_fetch: None, info: None, + download_directory: PathBuf::from(DEBUG_DOWNLOAD_DIR) }; c.save().unwrap(); return Ok(c); @@ -505,6 +624,7 @@ impl Config { login: None, info: None, info_fetch: None, + download_directory: PathBuf::from(directories::UserDirs::new().unwrap().download_dir().unwrap_or(Path::new(""))) }; c.save().unwrap();