use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; use crate::{ apis::modrinth::{extract_current_version, versions, Version}, config::Cfg, data::list::List, db::{ mods_get_info, userlist_change_versions, userlist_get_all_ids, userlist_get_applicable_versions, userlist_get_current_version, userlist_get_set_version, }, errors::{Error, MLE}, files::{ clean_list_dir, delete_version, disable_version, download_versions, }, PROGRESS_CHARS, STYLE_BAR_POS, STYLE_OPERATION, }; /// # Errors pub async fn update( config: &Cfg, liststack: Vec, clean: bool, direct_download: bool, delete_old: bool, ) -> MLE<()> { let mp = MultiProgress::new(); let update_p = mp.add(ProgressBar::new(liststack.len().try_into()?)); update_p.set_style( ProgressStyle::with_template(STYLE_BAR_POS)? .progress_chars(PROGRESS_CHARS), ); for current_list in liststack { update_p.set_message(format!("Update {}", current_list.id)); let list_p = mp.insert_before(&update_p, ProgressBar::new(2)); list_p.set_style(ProgressStyle::with_template(STYLE_OPERATION)?); list_p.set_message("Update mods"); let mods = userlist_get_all_ids(config, ¤t_list.id)?; let list_u_p = mp.insert_before(&list_p, ProgressBar::new(mods.len().try_into()?)); list_u_p.set_style( ProgressStyle::with_template(STYLE_BAR_POS)? .progress_chars(PROGRESS_CHARS), ); let mut current_versions: Vec<(String, String)> = vec![]; let mut updatestack: Vec = vec![]; for id in mods { update_mod( config, id, list_u_p.clone(), ¤t_list, &mut updatestack, &mut current_versions, clean, ) .await?; } list_u_p.finish_with_message(format!( "Updated mods in {}", current_list.id )); if clean { list_p.set_message("Cleaning"); clean_list_dir(¤t_list)?; }; if direct_download && !updatestack.is_empty() { download_versions( current_list.clone(), config.clone(), updatestack, &mp, &list_p, ) .await?; //Disable old versions if !clean { let d_p = mp.insert_before( &list_p, ProgressBar::new( current_versions.len().try_into()?, ), ); d_p.set_style( ProgressStyle::with_template(STYLE_BAR_POS)? .progress_chars(PROGRESS_CHARS), ); for ver in current_versions { if delete_old { d_p.set_message(format!("Delete version {}", ver.0)); d_p.inc(1); delete_version(¤t_list, &ver.0)?; } else if ver.0 != "NONE" { d_p.set_message(format!("Disable version {}", ver.0)); d_p.inc(1); disable_version(config, ¤t_list, ver.0, ver.1)?; }; } let del_msg = if delete_old { "Deleted all old versions" } else { "Disabled all old versions" }; d_p.finish_with_message(del_msg); } }; list_p.finish_with_message(format!("Updated {}", current_list.id)); update_p.inc(1); } update_p.finish_with_message("Updated all lists"); Ok(()) } async fn update_mod( config: &Cfg, id: String, list_u_p: ProgressBar, current_list: &List, updatestack: &mut Vec, current_versions: &mut Vec<(String, String)>, clean: bool, ) -> MLE<()> { let info = mods_get_info(config, &id)?; list_u_p.set_message(format!("Update {}", info.title)); //Skip check if version is set if userlist_get_set_version(config, ¤t_list.id, &id)? { list_u_p.inc(1); return Ok(()); } //Getting current installed version for disable or delete let disable_version = userlist_get_current_version(config, ¤t_list.id, &id)?; let version = specific_update( config, clean, current_list.clone(), &id, &list_u_p, ).await?; if let Some(v) = version { updatestack.push(v); current_versions.push((disable_version, id.to_string())); } list_u_p.inc(1); Ok(()) } async fn specific_update( config: &Cfg, clean: bool, list: List, id: &str, progress: &ProgressBar, ) -> MLE> { let applicable_versions = versions(&config.apis.modrinth, String::from(id), list.clone()).await?; let mut versions: Vec = vec![]; if applicable_versions.is_empty() { versions.push(String::from("NONE")); } else { for ver in &applicable_versions { versions.push(String::from(&ver.id)); } } let mut current: Option = None; if clean || (versions.join("|") != userlist_get_applicable_versions( config, &list.id, String::from(id), )?) { let current_str = extract_current_version(applicable_versions.clone())?; if !clean { progress.println(format!( "Found new version for {}", mods_get_info(config, id).unwrap().title )); } //get new versions let Some(current_ver) = applicable_versions.into_iter().find(|ver| ver.id == current_str) else { return Err(Error::NoCurrentVersion); }; current = Some(current_ver.clone()); let files = ¤t_ver.files; let link = match files.clone().into_iter().find(|f| f.primary) { Some(f) => f, None => files[0].clone(), } .url; userlist_change_versions( config, &list.id, current_str, versions.join("|"), link, id.to_string(), )?; }; if current.is_none() { // No Update Available Ok(None) } else { Ok(current) } }