use indicatif::{ProgressBar, ProgressStyle, MultiProgress};
use crate::{
config::Cfg,
db::{
mods_get_info, userlist_change_versions, userlist_get_all_ids,
userlist_get_applicable_versions, userlist_get_current_version, userlist_get_set_version,
},
error::{ErrorType, MLError, MLE},
files::{clean_list_dir, delete_version, disable_version, download_versions},
modrinth::{extract_current_version, versions, Version},
List,
};
const PROGRESS_CHARS: &str = "#>-";
pub async fn update(
config: Cfg,
liststack: Vec<List>,
clean: bool,
direct_download: bool,
delete_old: bool,
) -> MLE<()> {
let mp = MultiProgress::new();
let update_p = mp.add(ProgressBar::new(liststack.len().try_into().unwrap()));
let bar_style = ProgressStyle::with_template("{spinner:.green}{wide_msg}{pos}/{len} [{bar:.green/lime}]").unwrap().progress_chars(PROGRESS_CHARS);
let spinner_style = ProgressStyle::with_template("{spinner:.green}{msg}").unwrap();
update_p.set_style(bar_style.clone());
update_p.set_message("Update");
for current_list in liststack {
// println!("Update mods in {}", current_list.id);
let mods = userlist_get_all_ids(config.clone(), ¤t_list.id)?;
let list_p = mp.insert_before(&update_p, ProgressBar::new(mods.len().try_into().unwrap()));
list_p.set_style(bar_style.clone());
list_p.set_message(format!("Update {}", current_list.id));
let mut current_versions: Vec<(String, String)> = vec![];
let mut updatestack: Vec<Version> = vec![];
for id in mods {
let mod_p = mp.insert_before(&list_p, ProgressBar::new(1));
mod_p.set_style(spinner_style.clone());
let info = mods_get_info(&config, &id)?;
mod_p.set_message(format!("Update {}", info.title));
// println!(" ├{}", info.title);
if userlist_get_set_version(config.clone(), ¤t_list.id, &id)? {
// println!(" │ └Set version, skipping update");
list_p.inc(1);
continue;
}
//Getting current installed version for disable or delete
let disable_version =
userlist_get_current_version(config.clone(), ¤t_list.id, &id)?;
mod_p.inc(1);
updatestack.push(
match specific_update(
config.clone(),
clean,
current_list.clone(),
String::from(&id),
&mod_p
)
.await
{
Ok(ver) => {
current_versions.push((disable_version, id));
ver
}
Err(e) => {
if e.to_string() == "Mod: NO_UPDATE_AVAILABLE" {
// println!(
// " │ └No new version found for the specified minecraft version"
// );
} else {
return Err(e);
};
list_p.inc(1);
continue;
}
},
);
list_p.inc(1);
}
list_p.finish_with_message(format!("Updated {}", current_list.id));
if clean {
update_p.set_message("Cleaning");
update_p.inc(1);
clean_list_dir(¤t_list)?;
};
if direct_download && !updatestack.is_empty() {
download_versions(current_list.clone(), config.clone(), updatestack).await?;
//Disable old versions
if !clean {
for ver in current_versions {
if delete_old {
println!(" └Delete version {}", ver.0);
delete_version(current_list.clone(), ver.0)?;
} else if ver.0 != "NONE" {
println!(" └Disable version {}", ver.0);
disable_version(config.clone(), current_list.clone(), ver.0, ver.1)?;
};
}
}
};
update_p.inc(1);
}
update_p.finish_with_message("Updated all lists");
Ok(())
}
async fn specific_update(config: Cfg, clean: bool, list: List, id: String, progress: &ProgressBar) -> MLE<Version> {
let applicable_versions =
versions(&config.apis.modrinth, String::from(&id), list.clone()).await;
let mut versions: Vec<String> = vec![];
if !applicable_versions.is_empty() {
for ver in &applicable_versions {
versions.push(String::from(&ver.id));
}
} else {
versions.push(String::from("NONE"));
}
let mut current: Vec<Version> = vec![];
if clean
|| (versions.join("|")
!= userlist_get_applicable_versions(
config.clone(),
String::from(&list.id),
String::from(&id),
)?)
{
let current_str = extract_current_version(applicable_versions.clone())?;
if clean {
// println!("\t └Add version to downloadstack");
} else {
progress.println(format!("Found new version for {}", mods_get_info(&config, &id).unwrap().title));
// println!("\t └Get versions for specified minecraft versions");
// println!("\t └New current version: {}", current_str);
};
//get new versions
let current_ver = match applicable_versions
.into_iter()
.find(|ver| ver.id == current_str)
.ok_or("!no current version in applicable_versions")
{
Ok(v) => Ok(v),
Err(e) => Err(MLError::new(ErrorType::Other, e)),
}?;
current.push(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)?;
}
if current.is_empty() {
return Err(MLError::new(ErrorType::ModError, "NO_UPDATE_AVAILABLE"));
};
//println!(" └✔️");
Ok(current[0].clone())
}
// #[tokio::test]
// async fn download_updates_test() {
// use crate::{
// modrinth::{Hash, Version, VersionFile, VersionType},
// List, Modloader,
// };
//
// let config = Cfg::init().unwrap();
// let current_list = List {
// id: String::from("..."),
// mc_version: String::from("..."),
// modloader: Modloader::Fabric,
// download_folder: String::from("./dev/tests/dl"),
// };
//
// let versions = vec![Version {
// id: "dEqtGnT9".to_string(),
// project_id: "kYuIpRLv".to_string(),
// author_id: "Qnt13hO8".to_string(),
// featured: true,
// name: "1.2.2-1.19 - Fabric".to_string(),
// version_number: "1.2.2-1.19".to_string(),
// changelog: None,
// date_published: "2022-11-02T17:41:43.072267Z".to_string(),
// downloads: 58,
// version_type: VersionType::release,
// files: vec![VersionFile {
// hashes: Hash {
// sha1: "fdc6dc39427fc92cc1d7ad8b275b5b83325e712b".to_string(),
// sha512: "5b372f00d6e5d6a5ef225c3897826b9f6a2be5506905f7f71b9e939779765b41be6f2a9b029cfc752ad0751d0d2d5f8bb4544408df1363eebdde15641e99a849".to_string()
// },
// url: "https://cdn.modrinth.com/data/kYuIpRLv/versions/dEqtGnT9/waveycapes-fabric-1.2.2-mc1.19.2.jar".to_string(),
// filename: "waveycapes-fabric-1.2.2-mc1.19.2.jar".to_string(),
// primary: true,
// size: 323176
// }],
// game_versions: vec![
// "1.19".to_string(),
// "1.19.1".to_string(),
// "1.19.2".to_string()
// ],
// loaders: vec![
// "fabric".to_string()
// ]
// }];
// assert!(download_versions(current_list, config, versions)
// .await
// .is_ok())
// }