From c8fdf0bc23606cbaf9f0369e184c4899992dca26 Mon Sep 17 00:00:00 2001 From: Niklas Kapelle Date: Thu, 12 Mar 2026 00:09:21 +0100 Subject: [PATCH] unpack and add downloaded mod --- src/main.rs | 21 ++++++++++++++++++--- src/nexus/api.rs | 40 ++++++++++++++++++++++++++++++++++++++-- src/nexus/downloader.rs | 10 +++++++--- 3 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3f43296..5278ec3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -92,7 +92,7 @@ fn command_order(root_config: &RootConfig, instance_id: &str) -> anyhow::Result< Ok(()) } -fn command_download(root_config: &RootConfig, nxm_url: &str) -> anyhow::Result<()> { +fn command_download(root_config: &mut RootConfig, nxm_url: &str) -> anyhow::Result<()> { let Some(dl_location) = root_config.download_location() else { return Err(anyhow!("No download location set")); }; @@ -101,7 +101,22 @@ fn command_download(root_config: &RootConfig, nxm_url: &str) -> anyhow::Result<( return Err(anyhow!("No API key provided")); }; - download_nxm(api_key, nxm_url, dl_location)?; + let (dl_file, mod_info) = download_nxm(api_key, nxm_url, dl_location)?; + + let mod_id = mod_info.generate_id(); + if root_config.game_by_id(&mod_id).is_some() { + error!( + "Generated mod id already exists. Pleas install downloaded mod manually. Downloaded at {}", + &dl_file.to_string_lossy() + ); + return Err(anyhow!("Mod with generated already exists")); + } + + let new_mod = unpack(root_config, &mod_id, dl_file)?; + + root_config.add_mod(&new_mod); + + root_config.save_to_file()?; Ok(()) } @@ -156,7 +171,7 @@ fn main() -> Result<(), Box> { api.validate_key()?; } cli::Commands::Download { url } => { - command_download(&root_config, &url)?; + command_download(&mut root_config, &url)?; } cli::Commands::Unpack { id, path } => { command_unpack(&mut root_config, &id, path)?; diff --git a/src/nexus/api.rs b/src/nexus/api.rs index f784fce..e633e20 100644 --- a/src/nexus/api.rs +++ b/src/nexus/api.rs @@ -101,8 +101,8 @@ pub struct ModInfo { // pub endorsement_count: u64, // pub created_timestamp: u64, // pub created_time: String, - pub updated_timestamp: u64, - pub updated_time: String, + // pub updated_timestamp: u64, + // pub updated_time: String, // pub author: String, // pub uploaded_by: String, // pub uploaded_users_profile_url: String, @@ -112,3 +112,39 @@ pub struct ModInfo { // pub user: String /* Complex struct */, // pub endorsement: String /* Complex struct*/ , } + +impl ModInfo { + /// Try to generate a id for a mod based on name, mod_id and version + pub fn generate_id(&self) -> String { + const MAX_CHARS: usize = 16; + const MIN_CHARS: usize = 8; + + let mut short_name = String::new(); + + for word in self.name.split_whitespace() { + let cleaned: String = word.chars().filter(|c| !c.is_ascii_punctuation()).collect(); + + if cleaned.is_empty() { + continue; + } + + if short_name.is_empty() { + short_name.push_str(&cleaned); + } else { + short_name.push('_'); + short_name.push_str(&cleaned); + } + + // Ensure at least two words, then stop when >= 8 chars + let words = short_name.matches('_').count() + 1; + if words >= 2 && short_name.len() >= MIN_CHARS { + break; + } + } + + if short_name.len() > MAX_CHARS { + short_name.truncate(MAX_CHARS); + } + format!("{}-{}-{}", short_name, self.mod_id, self.version) + } +} diff --git a/src/nexus/downloader.rs b/src/nexus/downloader.rs index 8b26963..e350148 100644 --- a/src/nexus/downloader.rs +++ b/src/nexus/downloader.rs @@ -12,7 +12,11 @@ use crate::nexus::{ api::{DownloadLocation, ModInfo}, }; -pub fn download_nxm(api_key: &str, link: &str, target_dir: impl AsRef) -> anyhow::Result<()> { +pub fn download_nxm( + api_key: &str, + link: &str, + target_dir: impl AsRef, +) -> anyhow::Result<(PathBuf, ModInfo)> { let api = NexusAPI::new(api_key); let Some(parsed_url) = NXMUrl::parse_url(link) else { return Err(anyhow!("Failed to parse url")); @@ -30,9 +34,9 @@ pub fn download_nxm(api_key: &str, link: &str, target_dir: impl AsRef) -> create_dir_all(parent)?; } - download_mod(selected_mirror, download_path)?; + download_mod(selected_mirror, &download_path)?; - Ok(()) + Ok((download_path, mod_info)) } fn download_mod(mod_dl_link: &DownloadLocation, target: impl AsRef) -> anyhow::Result<()> {