package io.gitlab.jfronny.resclone.fetchers; import io.gitlab.jfronny.commons.HttpUtils; import io.gitlab.jfronny.resclone.Resclone; import io.gitlab.jfronny.resclone.data.curseforge.GetModFilesResponse; import io.gitlab.jfronny.resclone.data.curseforge.GetModResponse; import net.minecraft.MinecraftVersion; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URISyntaxException; import java.util.Date; import java.util.Random; public class CurseforgeFetcher extends BasePackFetcher { // So you found the API key. // Please be aware that CurseForge requires you to change this if you make any kind of derivative work // Creating your own API key is relatively simple, so please don't abuse this private static final String API_KEY = new String(unsalt(new byte[] { -30, 50, -60, -121, 62, -31, 35, 17, 16, -53, -53, -88, 21, -21, 15, -105, -115, -108, 114, -50, -49, -4, 56, -65, -70, 108, -65, -3, -55, -4, 36, -86, -40, 116, 71, -5, 75, -9, -43, 4, 91, -91, -29, 40, 66, 87, -80, -74, 71, 41, 76, -96, 108, -61, -113, 118, 7, -39, -116, -120 }, 1024)); @Override public String getSourceTypeName() { return "curseforge"; } @Override public String getDownloadUrl(String baseUrl) throws Exception { try { GetModResponse response = GET(baseUrl, GetModResponse.class); if (!response.data.allowModDistribution) throw new Exception("The author of " + baseUrl + " disabled access to this pack outside of the curseforge launcher"); String version = MinecraftVersion.CURRENT.getName(); GetModFilesResponse.Data latest = null; Date latestDate = null; boolean foundMatchingVersion = false; for (GetModFilesResponse.Data addon : GET(baseUrl + "/files", GetModFilesResponse.class).data) { if (foundMatchingVersion && !addon.gameVersions.contains(version)) continue; if (!foundMatchingVersion && addon.gameVersions.contains(version)) { foundMatchingVersion = true; latest = null; } if (latest == null || addon.fileDate.after(latestDate)) { latest = addon; latestDate = addon.fileDate; } } if (latest == null) throw new FileNotFoundException("Could not identify valid version"); if (!foundMatchingVersion) Resclone.LOGGER.error("Could not find matching version of " + baseUrl + ", using latest"); return latest.downloadUrl; } catch (Throwable e) { throw new IOException("Could not get CurseForge download for " + baseUrl, e); } } private static T GET(String suffix, Class klazz) throws URISyntaxException, IOException { return HttpUtils.get("https://api.curseforge.com/v1/mods/" + suffix).header("x-api-key", API_KEY).sendSerialized(klazz); } private static byte[] unsalt(byte[] data, int salt) { byte[] result = new byte[data.length]; new Random(salt).nextBytes(result); for (int i = 0; i < data.length; i++) { result[i] ^= data[i]; } return result; } }