Skip to content
This repository was archived by the owner on Sep 9, 2023. It is now read-only.

Commit b0944a6

Browse files
Allow profile mods update + override
1 parent f8ba394 commit b0944a6

3 files changed

Lines changed: 152 additions & 3 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Written in Java. Designed for all platform and portable use.
1919
- `delete <name>` Delete a profile. The name parameter is the name of the profile.
2020
- `add <profile> <ID>` Add a mod to the profile. ID is the ID of the mod on CurseForge.
2121
- `remove <profile> <ID>` Remove a mod from the profile. Works similarly to `add`.
22+
- `update <profile> [ID]` Update mods of a profile. Omit ID to check for updates.
2223
- `export` Export the profile as an uploadable modpack format.
2324
- `mod` Commands for mods.
2425
- `search <keywords>` Search for mods with keywords. Will also export results to file for easier adding to profile.

src/ml/northwestwind/Main.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package ml.northwestwind;
2+
3+
import org.fusesource.jansi.AnsiConsole;
4+
5+
import java.util.Arrays;
6+
7+
import static org.fusesource.jansi.Ansi.*;
8+
import static org.fusesource.jansi.Ansi.Color.*;
9+
10+
public class Main {
11+
public static void main(String[] args) {
12+
if (!AnsiConsole.isInstalled()) AnsiConsole.systemInstall();
13+
Config.load();
14+
int index = Arrays.asList(args).indexOf("--args");
15+
if (index < 0) {
16+
printHelp();
17+
return;
18+
}
19+
args = Arrays.stream(args).skip(index + 1).toArray(String[]::new);
20+
if (args.length < 1 || args[0].equalsIgnoreCase("help")) printHelp();
21+
else if (args[0].equalsIgnoreCase("mod")) Mod.run(args);
22+
else if (args[0].equalsIgnoreCase("modpack")) Modpack.run(args);
23+
else if (args[0].equalsIgnoreCase("profile")) Profile.run(args);
24+
else if (args[0].equalsIgnoreCase("config")) Config.run(args);
25+
}
26+
27+
private static void printHelp() {
28+
System.out.println(ansi().fg(YELLOW).a(
29+
" ________ ________ ________ ___ ___ \n" +
30+
"|\\ ____\\|\\ _____\\ |\\ ____\\|\\ \\ |\\ \\ \n" +
31+
"\\ \\ \\___|\\ \\ \\__/ \\ \\ \\___|\\ \\ \\ \\ \\ \\ \n" +
32+
" \\ \\ \\ \\ \\ __\\ \\ \\ \\ \\ \\ \\ \\ \\ \\ \n" +
33+
" \\ \\ \\____\\ \\ \\_| \\ \\ \\____\\ \\ \\____\\ \\ \\ \n" +
34+
" \\ \\_______\\ \\__\\ \\ \\_______\\ \\_______\\ \\__\\\n" +
35+
" \\|_______|\\|__| \\|_______|\\|_______|\\|__|"
36+
).reset());
37+
System.out.println(ansi().fg(GREEN.fgBright()).a("Made by NorthWestWind").reset());
38+
System.out.println();
39+
System.out.println("\"curseforge\", or \"./curseforge\" if you are running terminal in this directory.");
40+
System.out.println("\thelp: Display this message.");
41+
Config.printHelp("\t");
42+
Modpack.printHelp("\t");
43+
Profile.printHelp("\t");
44+
Mod.printHelp("\t");
45+
}
46+
}

src/ml/northwestwind/Profile.java

Lines changed: 105 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public static void run(String[] args) {
2626
args = Arrays.stream(args).skip(2).toArray(String[]::new);
2727
if (cmd.equalsIgnoreCase("add")) add(args);
2828
else if (cmd.equalsIgnoreCase("remove")) remove(args);
29+
else if (cmd.equalsIgnoreCase("update")) update(args);
2930
else if (cmd.equalsIgnoreCase("export")) export(args);
3031
else if (cmd.equalsIgnoreCase("edit")) edit(args[0]);
3132
else if (cmd.equalsIgnoreCase("delete")) delete(args);
@@ -219,14 +220,14 @@ private static void add(String[] ids) {
219220
JSONObject json = (JSONObject) Utils.readJsonFromUrl(Constants.CURSEFORGE_API + id);
220221
if (json == null || ((long) ((JSONObject) json.get("categorySection")).get("gameCategoryId")) != 6) throw new Exception("The ID "+id+" does not represent a mod.");
221222
JSONArray files = (JSONArray) Utils.readJsonFromUrl(Constants.CURSEFORGE_API + id + "/files");
222-
files.sort((a, b) -> (int) ((long) ((JSONObject) b).get("id") - (long) ((JSONObject) a).get("id")));
223223
List f = (List) files.stream().filter(o -> {
224224
JSONArray versions = (JSONArray) ((JSONObject) o).get("gameVersion");
225225
return versions.get(0).equals(config.get("mcVer")) && ((String) versions.get(1)).equalsIgnoreCase((String) config.get("launcher"));
226226
}).collect(Collectors.toList());
227+
f.sort((a, b) -> (int) ((long) ((JSONObject) b).get("id") - (long) ((JSONObject) a).get("id")));
227228
if (f.size() < 1) throw new Exception("No available file of " + id + " found for this profile.");
228-
JSONObject bestFile = (JSONObject) Utils.getLast(f);
229-
String downloadUrl = ((String) bestFile.get("downloadUrl")).replaceFirst("edge", "media");
229+
JSONObject bestFile = (JSONObject) f.get(0);
230+
String downloadUrl = (String) bestFile.get("downloadUrl");
230231
if (mods.containsKey(Integer.parseInt(id))) new File(modsFolder.getPath() + File.separator + mods.get(Integer.parseInt(id)).getValue() + "_" + id + "_" + mods.get(Integer.parseInt(id)).getKey() + ".jar").delete();
231232
String loc = Utils.downloadFile(downloadUrl, modsFolder.getPath(), ((String) bestFile.get("fileName")).replace(".jar", "_" + id + "_" + bestFile.get("id") + ".jar"));
232233
System.out.println(Ansi.ansi().fg(Ansi.Color.GREEN).a("Downloaded " + loc));
@@ -312,6 +313,14 @@ private static void export(String[] args) {
312313
e.printStackTrace();
313314
return;
314315
}
316+
File modsFolder = new File(Config.profileDir.getPath() + File.separator + profile + File.separator + "mods");
317+
File modsCopy = new File(modsFolder.getParent() + File.separator + "mods_copy");
318+
try {
319+
FileUtils.copyDirectory(modsFolder, modsCopy);
320+
} catch (Exception e) {
321+
e.printStackTrace();
322+
return;
323+
}
315324
Map<Integer, Map.Entry<Integer, String>> mods = Config.loadMods(profile);
316325
JSONArray files = new JSONArray();
317326
for (Map.Entry<Integer, Map.Entry<Integer, String>> mod : mods.entrySet()) {
@@ -320,6 +329,7 @@ private static void export(String[] args) {
320329
jo.put("fileID", mod.getValue().getKey());
321330
jo.put("required", true);
322331
files.add(jo);
332+
new File(modsCopy.getPath() + File.separator + mod.getValue().getValue() + "_" + mod.getKey() + "_" + mod.getValue().getKey() + ".jar").delete();
323333
}
324334
System.out.println("What is the version of this export?");
325335
Scanner scanner = new Scanner(System.in);
@@ -369,6 +379,11 @@ private static void export(String[] args) {
369379
try {
370380
for (String dir : overridesDir) FileUtils.copyDirectoryToDirectory(new File(dir), overridesFolder);
371381
for (String file : overridesFile) FileUtils.copyFileToDirectory(new File(file), overridesFolder);
382+
if (modsCopy.listFiles().length > 0) {
383+
File overrideMods = new File(overridesFolder.getPath() + File.separator + "mods");
384+
if (!overrideMods.exists() || !overrideMods.isDirectory()) overrideMods.mkdir();
385+
FileUtils.copyDirectory(modsCopy, overrideMods);
386+
}
372387
} catch (Exception e) {
373388
System.out.println(Ansi.ansi().fg(Ansi.Color.RED).a("Failed to copy files to overrides."));
374389
e.printStackTrace();
@@ -398,6 +413,90 @@ private static void export(String[] args) {
398413
System.out.println(Ansi.ansi().fg(Ansi.Color.GREEN).a("Exported profile " + profile + " to " + zipName));
399414
}
400415

416+
private static void update(String[] args) {
417+
String profile = args[0];
418+
if (!Config.loadProfiles().contains(profile)) {
419+
System.out.println(Ansi.ansi().fg(Ansi.Color.RED).a("Profile " + profile + " does not exist."));
420+
return;
421+
}
422+
File profileConfig = new File(Config.profileDir.getPath() + File.separator + profile + File.separator + "profile.json");
423+
if (!profileConfig.exists() || !profileConfig.isFile()) {
424+
System.err.println(Ansi.ansi().fg(Ansi.Color.RED).a("Profile config is missing!"));
425+
return;
426+
}
427+
JSONObject config;
428+
try {
429+
config = (JSONObject) parser.parse(new FileReader(profileConfig));
430+
} catch (ParseException | IOException e) {
431+
e.printStackTrace();
432+
return;
433+
}
434+
Map<Integer, Map.Entry<Integer, String>> mods = Config.loadMods(profile);
435+
if (args.length - 1 < 1) {
436+
System.out.println(Ansi.ansi().fg(Ansi.Color.CYAN).a("Mods with update available:"));
437+
Map<Integer, String> updatables = new HashMap<>();
438+
for (Map.Entry<Integer, Map.Entry<Integer, String>> entry : mods.entrySet()) {
439+
try {
440+
JSONObject json = (JSONObject) Utils.readJsonFromUrl(Constants.CURSEFORGE_API + entry.getKey());
441+
if (json == null || ((long) ((JSONObject) json.get("categorySection")).get("gameCategoryId")) != 6) throw new Exception("The ID "+entry.getKey()+" does not represent a mod.");
442+
JSONArray files = (JSONArray) Utils.readJsonFromUrl(Constants.CURSEFORGE_API + entry.getKey() + "/files");
443+
List f = (List) files.stream().filter(o -> {
444+
JSONArray versions = (JSONArray) ((JSONObject) o).get("gameVersion");
445+
return versions.get(0).equals(config.get("mcVer")) && ((String) versions.get(1)).equalsIgnoreCase((String) config.get("launcher"));
446+
}).collect(Collectors.toList());
447+
f.sort((a, b) -> (int) ((long) ((JSONObject) b).get("id") - (long) ((JSONObject) a).get("id")));
448+
if (f.size() < 1) throw new Exception("No available file of " + entry.getKey() + " found for this profile.");
449+
JSONObject fjson = (JSONObject) f.get(0);
450+
if (((long) fjson.get("id")) > entry.getValue().getKey()) {
451+
System.out.println(Ansi.ansi().fg(Ansi.Color.YELLOW).a(entry.getValue().getValue()).reset().a(" | ").fg(Ansi.Color.MAGENTA).a(entry.getKey()));
452+
updatables.put(entry.getKey(), entry.getValue().getValue());
453+
}
454+
} catch (Exception e) {
455+
e.printStackTrace();
456+
}
457+
}
458+
try {
459+
PrintWriter pw = new PrintWriter(profileConfig.getParent() + File.separator + "mod_updates.txt");
460+
for (Map.Entry<Integer, String> entry : updatables.entrySet()) pw.println(entry.getValue() + " = " + entry.getKey());
461+
pw.println();
462+
pw.println("You can update these mods of a profile with the following command: ");
463+
String cmd = "curseforge profile add <profile> " + mods.keySet().stream().map(String::valueOf).collect(Collectors.joining(" "));
464+
pw.println(cmd);
465+
pw.close();
466+
System.out.println(Ansi.ansi().fg(Ansi.Color.GREEN).a("Exported mods with update available to search.txt"));
467+
} catch (Exception e) {
468+
e.printStackTrace();
469+
}
470+
return;
471+
}
472+
473+
for (String id : Arrays.stream(args).skip(1).toArray(String[]::new)) {
474+
try {
475+
if (!Utils.isInteger(id)) throw new Exception("Mod ID is invalid: "+id);
476+
JSONObject json = (JSONObject) Utils.readJsonFromUrl(Constants.CURSEFORGE_API + id);
477+
if (json == null || ((long) ((JSONObject) json.get("categorySection")).get("gameCategoryId")) != 6) throw new Exception("The ID "+id+" does not represent a mod.");
478+
JSONArray files = (JSONArray) Utils.readJsonFromUrl(Constants.CURSEFORGE_API + id + "/files");
479+
List f = (List) files.stream().filter(o -> {
480+
JSONArray versions = (JSONArray) ((JSONObject) o).get("gameVersion");
481+
return versions.get(0).equals(config.get("mcVer")) && ((String) versions.get(1)).equalsIgnoreCase((String) config.get("launcher"));
482+
}).collect(Collectors.toList());
483+
f.sort((a, b) -> (int) ((long) ((JSONObject) b).get("id") - (long) ((JSONObject) a).get("id")));
484+
if (f.size() < 1) throw new Exception("No available file of " + id + " found for this profile.");
485+
JSONObject bestFile = (JSONObject) f.get(0);
486+
Map.Entry<Integer, String> entry = mods.get(Integer.parseInt(id));
487+
if (((long) bestFile.get("id")) > entry.getKey()) {
488+
System.out.println(Ansi.ansi().fg(Ansi.Color.YELLOW).a(entry.getValue()).reset().a(" | ").fg(Ansi.Color.MAGENTA).a(entry.getKey()));
489+
String downloadUrl = ((String) bestFile.get("downloadUrl")).replaceFirst("edge", "media");
490+
if (mods.containsKey(Integer.parseInt(id))) new File(profileConfig.getParent() + File.separator + "mods" + File.separator + entry.getValue() + "_" + id + "_" + entry.getKey() + ".jar").delete();
491+
String loc = Utils.downloadFile(downloadUrl, profileConfig.getParent() + File.separator + "mods", ((String) bestFile.get("fileName")).replace(".jar", "_" + id + "_" + bestFile.get("id") + ".jar"));
492+
System.out.println(Ansi.ansi().fg(Ansi.Color.GREEN).a("Downloaded " + loc));
493+
}
494+
} catch (Exception e) {
495+
e.printStackTrace();
496+
}
497+
}
498+
}
499+
401500
public static void printHelp(String prefix) {
402501
System.out.println(prefix + "profile: Commands for custom profiles.");
403502
System.out.println(prefix + "\tcreate: Create a profile.");
@@ -414,5 +513,8 @@ public static void printHelp(String prefix) {
414513
System.out.println(prefix + "\tremove: Remove a mod from the profile.");
415514
System.out.println(prefix + "\t\targ <profile>: Name of the profile to target.");
416515
System.out.println(prefix + "\t\targ <ID>: The ID of the mod.");
516+
System.out.println(prefix + "\tupdate: Update mods in the profile.");
517+
System.out.println(prefix + "\t\targ <profile>: Name of the profile to target.");
518+
System.out.println(prefix + "\t\targ [ID]: The ID of mods. Omit to check for updates.");
417519
}
418520
}

0 commit comments

Comments
 (0)