nixos-configs/apps/mc-mods/src/app.ts

147 lines
3.6 KiB
TypeScript

import { createWriteStream, mkdirSync, rmSync } from 'fs';
import { Readable } from 'stream';
interface Hashes {
sha1: string
sha512: string
}
interface File {
hashes: Hashes
url: string
filename: string
primary: boolean
size: number
file_type: string
}
interface Dependency {
version_id: string
project_id: string
file_name: string
dependency_type: string
}
interface ModVersion {
game_versions: string[]
loaders: string[]
id: string
project_id: string
author_id: string
featured: boolean
name: string
version_number: string
changelog: string
changelog_url: string
date_published: string
downloads: number
version_type: string
status: string
files: File[]
dependencies: Dependency[]
}
const LOADER = 'fabric';
const game_version = process.argv[2] ?? '';
const action = process.argv[3] ?? 'check';
const getVersions = async(slug: string): Promise<ModVersion[]> => {
const res = await fetch(`https://api.modrinth.com/v2/project/${slug}/version`);
return res.ok ?
await res.json() as ModVersion[] :
[];
};
const checkModCompat = async(slug: string): Promise<ModVersion | null> => {
const versions = await getVersions(slug);
const matching = versions.filter((ver) =>
ver.game_versions.includes(game_version) &&
ver.loaders.includes(LOADER));
if (matching.length === 0) {
return null;
}
const timeSorted = matching.sort((a, b) => {
const dateA = new Date(a.date_published);
const dateB = new Date(b.date_published);
return dateB.getTime() - dateA.getTime();
});
return timeSorted.some((v) => v.version_type === 'release') ?
timeSorted.filter((v) => v.version_type === 'release')[0] :
timeSorted[0];
};
const getDownloadUrls = (version: ModVersion): string[] => version.files.map((file) => file.url);
const showModDownloadUrls = async(modName: string): Promise<boolean> => {
const ver = await checkModCompat(modName);
if (ver) {
const urls = getDownloadUrls(ver);
console.log(`\n${modName}:`, urls);
return true;
}
else {
return false;
}
};
const download = async(url: string, path: string) => Readable
.fromWeb((await fetch(url)).body!).pipe(createWriteStream(path));
const main = () => {
const mods = [
'badpackets',
'c2me-fabric',
'cloth-config',
'clumps',
'fabric-api',
'ferrite-core',
'leaves-be-gone',
'lithium',
'modernfix',
'no-chat-reports',
'noisium',
'vmp-fabric',
'wthit',
];
if (action === 'check') {
mods.forEach(async(modName) => {
if (!(await showModDownloadUrls(modName))) {
console.error(`No matching releases of ${modName} were found for ${game_version}`);
}
});
}
else if (action === 'download') {
rmSync('./out', { force: true, recursive: true });
mkdirSync('./out');
mods.forEach(async(modName) => {
const ver = await checkModCompat(modName);
if (ver === null) {
console.error(`No matching releases of ${modName} were found for ${game_version}`);
return;
}
const fileName =
`${modName}-${ver.version_number}.jar`;
console.log(`Downloading ${fileName}`);
await download(
ver.files[0].url,
`./out/${fileName}`,
);
});
}
};
main();