Add mod tracking

This commit is contained in:
Kallum Jones 2022-08-03 19:52:34 +01:00
parent dbe0ae9a48
commit 1241795b7d
No known key found for this signature in database
GPG Key ID: D7F4589C4D7F81A9
4 changed files with 56 additions and 12 deletions

10
src/mods/mod.ts Normal file
View File

@ -0,0 +1,10 @@
declare global {
type Mod = {
id: string
name: string
fileName: string,
source: string,
}
}
export {}

View File

@ -4,6 +4,7 @@ import PrintUtils from "../util/print_utils.js";
import ModrinthSource from "./sources/modrinth_source.js"; import ModrinthSource from "./sources/modrinth_source.js";
import ModSource from "./sources/mod_source.js"; import ModSource from "./sources/mod_source.js";
import ModNotFoundError from "../errors/mod_not_found_error.js"; import ModNotFoundError from "../errors/mod_not_found_error.js";
import {readFileSync, writeFileSync} from "fs";
export default class Mods { export default class Mods {
@ -28,9 +29,9 @@ export default class Mods {
id = await source.search(mod); id = await source.search(mod);
} catch (e) { } catch (e) {
if (e instanceof ModNotFoundError) { if (e instanceof ModNotFoundError) {
spinner.updateText(`Mod not found on ${source.getName()}`) spinner.updateText(`Mod not found on ${source.getSourceName()}`)
} else { } else {
spinner.error(`An error occurred searching for ${mod} on ${source.getName()}. Skipping ${source.getName()}`) spinner.error(`An error occurred searching for ${mod} on ${source.getSourceName()}. Skipping ${source.getSourceName()}`)
// Try the next source // Try the next source
continue; continue;
} }
@ -40,7 +41,9 @@ export default class Mods {
if (id != undefined) { if (id != undefined) {
spinner.updateText(`Installing ${mod}...`) spinner.updateText(`Installing ${mod}...`)
try { try {
await source.install(id); const modObj: Mod = await source.install(id);
this.trackMod(modObj);
spinner.succeed(`Successfully installed ${mod}`); spinner.succeed(`Successfully installed ${mod}`);
success = true; success = true;
} catch (e) { } catch (e) {
@ -55,4 +58,16 @@ export default class Mods {
public static getModFilePath(): string { public static getModFilePath(): string {
return path.join(Initialiser.getModManagerFolderPath(), this.MOD_FILE); return path.join(Initialiser.getModManagerFolderPath(), this.MOD_FILE);
} }
private static trackMod(mod: Mod): void {
// Parse current file
const file = readFileSync(this.getModFilePath(), "utf-8");
const json: Array<Mod> = JSON.parse(file);
// Add mod
json.push(mod);
// Write list back to file
writeFileSync(this.getModFilePath(), JSON.stringify(json, null, 4));
}
} }

View File

@ -1,7 +1,9 @@
export default interface ModSource { export default interface ModSource {
search(query: string): Promise<string>; search(query: string): Promise<string>;
install(id: string): Promise<void>; install(id: string): Promise<Mod>;
getName(): string; getSourceName(): string;
getProjectName(id: string): Promise<string>;
} }

View File

@ -12,6 +12,7 @@ export default class ModrinthSource implements ModSource {
private static readonly BASE_URL: string = "https://api.modrinth.com/v2"; private static readonly BASE_URL: string = "https://api.modrinth.com/v2";
private static readonly SEARCH_URL: string = ModrinthSource.BASE_URL + "/search"; private static readonly SEARCH_URL: string = ModrinthSource.BASE_URL + "/search";
private static readonly INSTALL_URL: string = ModrinthSource.BASE_URL + "/project/%s/version"; private static readonly INSTALL_URL: string = ModrinthSource.BASE_URL + "/project/%s/version";
private static readonly PROJECT_URL: string = ModrinthSource.BASE_URL + "/project/%s";
/** /**
* Searches Modrinth for the specified query * Searches Modrinth for the specified query
@ -79,7 +80,7 @@ export default class ModrinthSource implements ModSource {
const results = await response.data.hits; const results = await response.data.hits;
if (Util.isArrayEmpty(results)) { if (Util.isArrayEmpty(results)) {
throw new ModNotFoundError(`Mod ${query} could not be found on ${this.getName()}`); throw new ModNotFoundError(`Mod ${query} could not be found on ${this.getSourceName()}`);
} }
return results[0].project_id; return results[0].project_id;
@ -126,7 +127,7 @@ export default class ModrinthSource implements ModSource {
* @throws DownloadError if an error occurs when downloading * @throws DownloadError if an error occurs when downloading
* @throws ModNotFoundError if there are no versions available for the current Minecraft Version * @throws ModNotFoundError if there are no versions available for the current Minecraft Version
*/ */
async install(id: string): Promise<void> { async install(id: string): Promise<Mod> {
const mcVersion = await MinecraftUtils.getCurrentMinecraftVersion(); const mcVersion = await MinecraftUtils.getCurrentMinecraftVersion();
const params = { const params = {
@ -138,26 +139,42 @@ export default class ModrinthSource implements ModSource {
const results = await response.data; const results = await response.data;
if (Util.isArrayEmpty(results)) { if (Util.isArrayEmpty(results)) {
throw new ModNotFoundError(`Mod with id ${id} has no available versions on ${this.getName()} for Minecraft version ${mcVersion}`); throw new ModNotFoundError(`Mod with id ${id} has no available versions on ${this.getSourceName()} for Minecraft version ${mcVersion}`);
} }
const latestFile = results[0].files[0]; const latestFile = results[0].files[0];
const fileName = latestFile.filename;
const url = latestFile.url;
const task: DownloadTask = { const task: DownloadTask = {
fileName: latestFile.filename, fileName: fileName,
url: latestFile.url url: url
} }
try { try {
FileDownloader.downloadMod(task) FileDownloader.downloadMod(task)
return {
name: await this.getProjectName(id),
id: id,
fileName: fileName,
source: this.getSourceName()
};
} catch (e) { } catch (e) {
throw new DownloadError(`An error occurred downloading mod with id ${id} from ${this.getName()}`) throw new DownloadError(`An error occurred downloading mod with id ${id} from ${this.getSourceName()}`)
} }
} }
getName(): string { getSourceName(): string {
return "Modrinth"; return "Modrinth";
} }
async getProjectName(id: string): Promise<string> {
const response = await axios.get(format(ModrinthSource.PROJECT_URL, id));
return await response.data.title;
}
} }