mirror of
https://git.bits.team/Bits/mod-manager.git
synced 2024-11-14 10:28:21 -05:00
Added Cursefoge Source
This commit is contained in:
parent
fdc880e7fc
commit
7d6d49ec19
@ -7,14 +7,22 @@ import ModManager from "../mod-manager.js";
|
||||
|
||||
export default class FileDownloader {
|
||||
static downloadMod(version: Version): void {
|
||||
https.get(version.url, res => {
|
||||
const filePath = path.join(ModManager.FilePaths.MODS_FOLDER_PATH, version.fileName);
|
||||
const writeStream = createWriteStream(filePath);
|
||||
res.pipe(writeStream);
|
||||
writeStream.on("finish", () => writeStream.close());
|
||||
writeStream.on('error', () => {
|
||||
throw new DownloadError(`Failed to download ${version.fileName} from ${version.url}`)
|
||||
try {
|
||||
if (version.url == null) {
|
||||
throw new Error("URL was null");
|
||||
}
|
||||
|
||||
https.get(version.url, res => {
|
||||
const filePath = path.join(ModManager.FilePaths.MODS_FOLDER_PATH, version.fileName);
|
||||
const writeStream = createWriteStream(filePath);
|
||||
res.pipe(writeStream);
|
||||
writeStream.on("finish", () => writeStream.close());
|
||||
writeStream.on('error', () => {
|
||||
throw new Error("Error while writing file during download")
|
||||
})
|
||||
})
|
||||
})
|
||||
} catch (e) {
|
||||
throw new DownloadError(`Failed to download ${version.fileName} from ${version.url}`)
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ import MigratePossibleCommand from "./commands/migrate_possible.js";
|
||||
import MigrateCommand from "./commands/migrate_command.js";
|
||||
import ModrinthSource from "./mods/sources/modrinth_source.js";
|
||||
import Mods from "./mods/mods.js";
|
||||
import {CurseforgeSource} from "./mods/sources/curseforge_source.js";
|
||||
|
||||
export default class ModManager {
|
||||
public static logger: Logger | null = null;
|
||||
@ -42,7 +43,7 @@ export default class ModManager {
|
||||
public static readonly MODS_FOLDER_PATH = path.join("mods")
|
||||
}
|
||||
|
||||
static async init() {
|
||||
static init() {
|
||||
if (Initialiser.isInitialised()) {
|
||||
this.logger = ModManager.createLogger();
|
||||
}
|
||||
@ -55,11 +56,8 @@ export default class ModManager {
|
||||
command.registerCommand(this.program);
|
||||
}
|
||||
|
||||
/* const source = new CurseforgeSource();
|
||||
console.log(await source.search("lithium"))*/
|
||||
|
||||
Mods.registerSource(new ModrinthSource())
|
||||
//Mods.registerSource(new CurseforgeSource(), "CURSEFORGE_API_KEY")
|
||||
Mods.registerSource(new CurseforgeSource(), "CURSEFORGE_API_KEY")
|
||||
|
||||
this.program.showSuggestionAfterError();
|
||||
this.program.showHelpAfterError();
|
||||
|
@ -37,7 +37,7 @@ export default class Mods {
|
||||
id = await source.search(mod);
|
||||
} catch (e) {
|
||||
if (e instanceof ModNotFoundError) {
|
||||
spinner.stop(`Mod not found on ${source.getSourceName()}`)
|
||||
spinner.stop(`Mod ${mod} not found on ${source.getSourceName()}`)
|
||||
} else {
|
||||
spinner.error(`An error occurred searching for ${mod} on ${source.getSourceName()}. Skipping ${source.getSourceName()}`)
|
||||
// Try the next source
|
||||
|
@ -1,31 +1,95 @@
|
||||
/*import ModSource from "./mod_source.js";
|
||||
import ModSource from "./mod_source.js";
|
||||
import axios from "axios";
|
||||
import MinecraftUtils from "../../util/minecraft_utils.js";
|
||||
import ModNotFoundError from "../../errors/mod_not_found_error.js";
|
||||
import Util from "../../util/util.js";
|
||||
import {format} from "util";
|
||||
import Mods from "../mods.js";
|
||||
import FileDownloader from "../../io/file_downloder.js";
|
||||
import DownloadError from "../../errors/download_error.js";
|
||||
|
||||
export class CurseforgeSource implements ModSource {
|
||||
private static readonly BASE_URL: string = "https://api.curseforge.com";
|
||||
private static readonly SEARCH_URL: string = `${CurseforgeSource.BASE_URL}/v1/mods/search`;
|
||||
private static readonly BASE_URL: string = "https://api.curseforge.com/v1";
|
||||
private static readonly SEARCH_URL: string = `${CurseforgeSource.BASE_URL}/mods/search`;
|
||||
private static readonly GET_MOD_URL: string = `${CurseforgeSource.BASE_URL}/mods/%s`
|
||||
private static readonly GET_FILE_URL: string = `${CurseforgeSource.BASE_URL}/mods/%s/files/%s`
|
||||
private static readonly DOWNLOAD_CDN_URL: string = "https://edge.forgecdn.net/files/%s/%s/%s";
|
||||
|
||||
private static readonly MINECRAFT_ID: number = 432;
|
||||
private static readonly FABRIC_TYPE: number = 4;
|
||||
|
||||
getLatestVersion(id: string, mcVersion: string): Promise<Version> {
|
||||
const response = await
|
||||
async getLatestVersion(id: string, mcVersion: string): Promise<Version> {
|
||||
const modResponse = await this.makeRequest(format(CurseforgeSource.GET_MOD_URL, id));
|
||||
const latestFiles: Array<any> = modResponse.data.latestFilesIndexes;
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
const latestFilesArr = latestFiles.filter(file => file.gameVersion === mcVersion);
|
||||
if (Util.isArrayEmpty(latestFilesArr)) {
|
||||
throw new ModNotFoundError(`Mod with id ${id} has no available versions on ${this.getSourceName()} for Minecraft version ${mcVersion}`)
|
||||
}
|
||||
|
||||
const fileId = latestFilesArr[0].fileId;
|
||||
const fileResponse = await this.makeRequest(format(CurseforgeSource.GET_FILE_URL, id, fileId))
|
||||
const fileObj = fileResponse.data;
|
||||
|
||||
const dependencies = [];
|
||||
if (!Util.isArrayEmpty(fileObj.dependencies)) {
|
||||
for (let dependency of fileObj.dependencies) {
|
||||
// If dependency is required
|
||||
if (dependency.relationType == 3) {
|
||||
dependencies.push(await this.getLatestVersion(dependency.modId, mcVersion));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const downloadUrl = fileObj.downloadUrl != null ? fileObj.downloadUrl : this.constructDownloadUrl(id, fileObj.fileName);
|
||||
|
||||
return {
|
||||
modId: id.toString(),
|
||||
fileName: fileObj.fileName,
|
||||
url: downloadUrl,
|
||||
versionNumber: fileObj.displayName,
|
||||
dependencies: dependencies
|
||||
}
|
||||
}
|
||||
|
||||
getProjectName(id: string): Promise<string> {
|
||||
return Promise.resolve("");
|
||||
async getProjectName(id: string): Promise<string> {
|
||||
const response = await this.makeRequest(format(CurseforgeSource.GET_MOD_URL, id))
|
||||
return response.data.name;
|
||||
}
|
||||
|
||||
getSourceName(): string {
|
||||
return "Curseforge";
|
||||
}
|
||||
|
||||
install(version: Version, essential: boolean): Promise<Mod> {
|
||||
return Promise.resolve(undefined);
|
||||
async install(version: Version, essential: boolean): Promise<void> {
|
||||
try {
|
||||
if (Mods.isModInstalled(version.modId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dependencies = [];
|
||||
if (!Util.isArrayEmpty(version.dependencies)) {
|
||||
for (let dependency of version.dependencies) {
|
||||
await this.install(dependency, essential);
|
||||
dependencies.push(dependency.modId)
|
||||
}
|
||||
}
|
||||
FileDownloader.downloadMod(version)
|
||||
|
||||
const mod = {
|
||||
name: await this.getProjectName(version.modId),
|
||||
id: version.modId,
|
||||
fileName: version.fileName,
|
||||
version: version.versionNumber,
|
||||
source: this.getSourceName(),
|
||||
essential: essential,
|
||||
dependencies: dependencies
|
||||
}
|
||||
|
||||
Mods.trackMod(mod);
|
||||
} catch (e) {
|
||||
throw new DownloadError(`An error occurred downloading mod with id ${version.modId} from ${this.getSourceName()}`)
|
||||
}
|
||||
}
|
||||
|
||||
async search(query: string): Promise<string> {
|
||||
@ -40,21 +104,24 @@ export class CurseforgeSource implements ModSource {
|
||||
}
|
||||
|
||||
const response = await this.makeRequest(CurseforgeSource.SEARCH_URL, params);
|
||||
const results = response.data;
|
||||
|
||||
const id = response.data[0].id;
|
||||
|
||||
if (id == undefined) {
|
||||
if (Util.isArrayEmpty(results)) {
|
||||
throw new ModNotFoundError(`Mod ${query} could not be found on ${this.getSourceName()}`);
|
||||
}
|
||||
|
||||
return id;
|
||||
return results[0].id;
|
||||
}
|
||||
|
||||
private async makeRequest(url: string, params: object) {
|
||||
private async makeRequest(url: string, params?: object) {
|
||||
if (process.env.CURSEFORGE_API_KEY == undefined) {
|
||||
throw new Error("Attempted Curseforge api calls with undefined api key environment variable (CURSEFORGE_API_KEY)")
|
||||
}
|
||||
|
||||
if (params == undefined) {
|
||||
params = {}
|
||||
}
|
||||
|
||||
const response = await axios.get(url, {
|
||||
headers: {
|
||||
"x-api-key": process.env.CURSEFORGE_API_KEY
|
||||
@ -64,5 +131,18 @@ export class CurseforgeSource implements ModSource {
|
||||
return await response.data;
|
||||
}
|
||||
|
||||
private constructDownloadUrl(id: string, fileName: string) {
|
||||
// Some mods have a null download link. Download links follow a pattern such that we can
|
||||
// create the URL ourselves in those rare cases. If download link is invalid, download
|
||||
// will gracefully fail
|
||||
const first = id.toString().substring(0, 4);
|
||||
let last = id.toString().substring(4);
|
||||
|
||||
if (last.charAt(0) == '0') {
|
||||
last = last.replace("0", "");
|
||||
}
|
||||
|
||||
return format(CurseforgeSource.DOWNLOAD_CDN_URL, first, last, fileName);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user