adjusted function input for getting latest mod version and adding chunking to not hit request limits

This commit is contained in:
O2theC authored and Danielv123 committed 2025-03-15 15:29:59 +01:00
1 parent 71c1cffcac
commit a2a3bcd4f8
1 file changed
+64 -89
+64 -89
View File
@@ -2,7 +2,7 @@ import fs from "fs-extra";
import path from "path";
import { Static, StringContentEncodingOption, Type } from "@sinclair/typebox";
import { logger } from "./logging";
import { ModInfo } from "./data";
import { integerModVersion, ModInfo } from "./data";
import * as libSchema from "./schema";
import TypedEventEmitter from "./TypedEventEmitter";
import { safeOutputFile } from "./file_ops";
@@ -12,56 +12,36 @@ export interface ModStoreEvents {
change: (mod: ModInfo) => void;
}
interface ModDownloadRequest {
name: string;
version?: string;
sha1?: string;
}
interface ModRelease {
download_url: string,
// /download/maraxsis/670de301df21001f6147fd1c -- append to mods.factorio.com to download file, auth required
file_name: string,
// maraxsis_1.8.0.zip -- the file name of the downloaded file ^^
info_json: {
dependencies?: Array<string>,
factorio_version: string;
};
released_at: string,
// 2024-10-15T03:35:29.892000Z -- (ISO 8601)
sha1: string,
// e227ee560d93485c7f215c9451eaa9cc38d81c98
version: string; // 1.8.0 -- just a normal version string
info_json: { factorio_version: string; },
releasted_at: string, // ISO 8601
version: string,
sha1: string;
}
interface ModImage {
id: string,
thumbnail: string,
url: string;
}
interface ModLicense {
description: string,
id: string,
name: string,
title: string,
url: string;
}
interface ModDetails {
category: string, // content -- what mod catogory is this apart of, a mod can only be apart of 1 category
download_count: number, // 3653 -- how many downloads does the mod have as a number
name: string, // maraxsis -- the name of the mod
owner: string, // notnotmelon -- the name of the author of the mod
releases: Array<ModRelease>, // an array of all releases and version of the mod
score: number, // 1054.8333333333333 -- it's prob used for sorting purposes
summary: string, // the mod description
thumbnail: string, // append path to assets-mods.factorio.com to get full url to thumbnail file
title: string, // the full title of the mod, shown on the mod page
changelog?: string,
created_at?: string,
description?: string,
homepage?: string,
images?: Array<ModImage>,
license?: ModLicense,
source_url?: string,
tags?: Array<string>,
updated_at?: string,
deprecated?: boolean;
name: string,
title: string,
owner: string,
summary: string,
downloads_count: number,
category: string,
score: number,
releases: Array<ModRelease>,
}
interface ModsInfoResponse {
pagination: any,
results: Array<ModDetails>,
}
export default class ModStore extends TypedEventEmitter<keyof ModStoreEvents, ModStoreEvents> {
@@ -188,54 +168,49 @@ export default class ModStore extends TypedEventEmitter<keyof ModStoreEvents, Mo
return new this(modsDirectory, files);
}
// gets the latest version of the mod provided as a string
static async fetchLatestVersionString(modName: string): Promise<string> {
const modDetails: ModDetails = await (
await fetch(`https://mods.factorio.com/api/mods/${modName}`)
).json() as ModDetails;
return modDetails.releases[modDetails.releases.length].version;
static getLatestVersionFromReleases(releases: Array<ModRelease>): string | undefined {
let latestVersion = "0.0.0";
releases.forEach((release) => {
if (integerModVersion(latestVersion) < integerModVersion(release.version)) {
latestVersion = release.version;
}
});
if (latestVersion === "0.0.0") {
return undefined;
}
return latestVersion;
}
// gets the latest version of the mod provided as a string
static async fetchLatestVersionModInfo(modName: string): Promise<ModInfo> {
const modDetails: ModDetails = await (
await fetch(`https://mods.factorio.com/api/mods/${modName}/full`)
).json() as ModDetails;
const latestRelease: ModRelease = modDetails.releases[modDetails.releases.length];
let modInfo = new ModInfo();
const info_json = latestRelease.info_json;
// info.json fields
if (modDetails.name) { modInfo.name = modDetails.name; }
if (latestRelease.version) { modInfo.version = latestRelease.version; }
if (modDetails.title) { modInfo.title = modDetails.title; }
if (modDetails.owner) { modInfo.author = modDetails.owner; }
if (modDetails.homepage) { modInfo.homepage = modDetails.homepage; }
if (modDetails.description) { modInfo.description = modDetails.description; }
if (info_json.factorio_version) { modInfo.factorioVersion = info_json.factorio_version; }
if (info_json.dependencies) { modInfo.dependencies = info_json.dependencies; }
const infoJsonSchema = Type.Object({
"name": Type.String(),
"version": Type.String(),
"title": Type.String(),
"author": Type.String(),
"contact": Type.Optional(Type.String()),
"homepage": Type.Optional(Type.String()),
"description": Type.Optional(Type.String()),
"factorio_version": Type.Optional(Type.String()),
"dependencies": Type.Optional(Type.Array(Type.String())),
static async getLatestVersionsChunk(modNames: Array<string>): Promise<{ [key: string]: string | undefined; }> {
const url = new URL("https://mods.factorio.com/api/mods");
url.searchParams.set("page_size", "max");
const response = await fetch(url, {
method: "POST",
body: new URLSearchParams({ namelist: modNames }),
});
if (response.status !== 200) {
throw Error(`Fetch: ${url} returned ${response.status} ${response.statusText}`);
}
const mods = (await response.json() as ModsInfoResponse).results;
const versions: { [key: string]: string | undefined; } = {};
mods.forEach((mod) => {
const modName = mod.name;
let latestVersion = ModStore.getLatestVersionFromReleases(mod.releases);
versions[modName] = latestVersion;
});
const validateInfo = libSchema.compile<Static<typeof infoJsonSchema>>(infoJsonSchema as any);
const valid = validateInfo(modInfo);
if (valid) {
return modInfo;
}
return modInfo;
return versions;
}
static async getLatestVersions(modNames: Array<string>): Promise<{ [key: string]: string | undefined; }> {
const chunkSize = 500;
const chunks: Array<{ [key: string]: string | undefined; }> = [];
for (let i = 0; i < modNames.length; i += chunkSize) {
chunks.push(await ModStore.getLatestVersionsChunk(modNames.slice(i, i + chunkSize)));
}
const versions = chunks.reduce((acc, curr) => ({ ...acc, ...curr }), {});
return versions;
}
}