1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
use crate::{config::Cfg, modrinth::{projects, Project, versions, extract_current_version, Version}, get_current_list, db::{userlist_get_all_ids, mods_get_versions, userlist_get_applicable_versions, userlist_change_versions, lists_get_all_ids, lists_get, userlist_get_current_version, mods_change_versions}, List, input::Input, files::{delete_version, download_versions, disable_version, clean_list_dir}, error::{MLE, MLError, ErrorType}};
pub async fn update(config: Cfg, input: Input) -> MLE<()> {
let mut liststack: Vec<List> = vec![];
if input.all_lists {
let list_ids = lists_get_all_ids(config.clone())?;
for id in list_ids {
liststack.push(lists_get(config.clone(), id)?);
}
} else {
let current = get_current_list(config.clone())?;
println!("Check for updates of mods in list {}", current.id);
liststack.push(current)
}
cmd_update(config, liststack, input.clean, input.direct_download, input.delete_old).await
}
pub async fn cmd_update(config: Cfg, liststack: Vec<List>, clean: bool, direct_download: bool, delete_old: bool) -> MLE<()> {
for current_list in liststack {
let mods = userlist_get_all_ids(config.clone(), current_list.clone().id)?;
let mut current_versions: Vec<(String, String)> = vec![];
let mut versions = mods_get_versions(config.clone(), mods.clone())?;
versions.sort_by_key(|ver| ver.mod_id.clone());
let mut projects = projects(String::from(&config.apis.modrinth), mods).await;
projects.sort_by_key(|pro| pro.id.clone());
println!("Comparing mod versions:");
let mut updatestack: Vec<Version> = vec![];
for (index, project) in projects.into_iter().enumerate() {
//Get versions for project and check if they match up
let current_version = &versions[index];
let p_id = String::from(&project.id);
let v_id = ¤t_version.mod_id;
if &p_id != v_id { return Err(MLError::new(ErrorType::Other, "SORTING_ERROR")) };
println!("\t({}) Check for update", project.title);
//Getting current installed version for disable or delete
let disable_version = userlist_get_current_version(config.clone(), String::from(¤t_list.id), String::from(&project.id))?;
let version_db_string = project.versions.join("|");
//Adding to stack if not the same versions in the list OR if clean == true
if clean || (version_db_string != current_version.versions) {
updatestack.push(match specific_update(config.clone(), clean, current_list.clone(), project.clone()).await {
Ok(ver) => {
current_versions.push((disable_version, p_id));
ver
},
Err(e) => {
//Catch no update available
if e.to_string() == "Mod: NO_UPDATE_AVAILABLE" {
mods_change_versions(config.clone(), version_db_string, project.id)?;
println!("\t └No new version found for the specified minecraft version");
} else {
return Err(e);
};
continue;
},
});
} else {
println!("\t └No new version found");
};
};
//Linebreak readability
println!("");
if clean { clean_list_dir(¤t_list)? };
//Linebreak readability
println!("");
if direct_download {
download_versions(current_list.clone(), config.clone(), updatestack).await?;
//Disable old versions
if !clean {
for ver in current_versions {
if delete_old {
println!("Deleting version {} for mod {}", ver.0, ver.1);
delete_version(current_list.clone(), ver.0)?;
} else if ver.0 != "NONE" {
println!("Disabling version {} for mod {}", ver.0, ver.1);
disable_version(config.clone(), current_list.clone(), ver.0, ver.1)?;
};
}
}
};
}
Ok(())
}
async fn specific_update(config: Cfg, clean: bool, list: List, project: Project) -> MLE<Version> {
let applicable_versions = versions(String::from(&config.apis.modrinth), String::from(&project.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(&project.id))?) {
//get new versions
println!("\t └Get versions for specified minecraft versions");
let current_str = extract_current_version(applicable_versions.clone())?;
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 link = match current_ver.files.into_iter().find(|f| f.primary).ok_or("!no primary in links") {
Ok(p) => Ok(p),
Err(e) => Err(MLError::new(ErrorType::Other, e)),
}?.url;
userlist_change_versions(config, list.id, current_str, versions.join("|"), link, project.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::{Version, VersionFile, Hash, VersionType}, Modloader, List};
let current_list = List { id: String::from("..."), mc_version: String::from("..."), modloader: Modloader::Forge, download_folder: String::from("./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, versions).await.is_ok())
}
|