diff --git a/.gitignore b/.gitignore index f76f2bb..04623dc 100644 --- a/.gitignore +++ b/.gitignore @@ -134,4 +134,5 @@ ndist # test files *.zip -*.mrpack \ No newline at end of file +*.mrpack +instance/ \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 6691835..145e3a6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "adm-zip": "^0.5.16", "chalk": "^5.4.1", "cli-progress": "^3.12.0", + "dotenv": "^17.0.1", "fs-extra": "^11.3.0", "got": "^14.4.7", "inquirer": "^12.6.3", @@ -2524,6 +2525,18 @@ "node": ">=8" } }, + "node_modules/dotenv": { + "version": "17.0.1", + "resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-17.0.1.tgz", + "integrity": "sha512-GLjkduuAL7IMJg/ZnOPm9AnWKJ82mSE2tzXLaJ/6hD6DhwGfZaXG77oB8qbReyiczNxnbxQKyh0OE5mXq0bAHA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/download": { "version": "8.0.0", "resolved": "https://registry.npmmirror.com/download/-/download-8.0.0.tgz", diff --git a/package.json b/package.json index 7ea9892..5b05136 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "adm-zip": "^0.5.16", "chalk": "^5.4.1", "cli-progress": "^3.12.0", + "dotenv": "^17.0.1", "fs-extra": "^11.3.0", "got": "^14.4.7", "inquirer": "^12.6.3", diff --git a/src/main.ts b/src/main.ts index 845724f..3658dab 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,13 +1,26 @@ import inquirer from "inquirer"; import yauzl from "yauzl"; import process from "node:process"; -import { join, basename } from "node:path"; +import fse from "fs-extra"; +import { join, basename, dirname } from "node:path"; import { platform, what_platform } from "./platform/index.js"; -import { readzipentry } from "./utils/utils.js"; +import { isDevelopment, readzipentry } from "./utils/utils.js"; +import fabric from "./ml_install/fabric.js" +import forge from "./ml_install/forge.js" +import neoforge from "./ml_install/neoforge.js" +import { DeEarthMain } from "./utils/DeEarth.js"; +import { LOGGER } from "./utils/logger.js"; +import { fileURLToPath } from "node:url"; interface Answers { modpack_path: string | undefined; } -const unzip_path = "./instance"; +let unzip_path:string = "" +if(isDevelopment){ + unzip_path = join("./","instance") +}else{ + unzip_path = join(getCurrnetDir(),"instance") +} +let zipnamew: string = "" const argv = process.argv.slice(2)[0]; if (!argv) { @@ -15,16 +28,25 @@ if (!argv) { { type: "input", name: "modpack_path", message: "请输入整合包路径" }, ]); if (answer.modpack_path) { + initdir() await main(answer.modpack_path); } } else { + initdir() await main(argv); } +function initdir(){ + if(!fse.existsSync(unzip_path)){ + fse.ensureDirSync(join(unzip_path,"rubbish")) + } +} + async function main(modpack_path: string) { - const zipname = basename(modpack_path) + const zipname= basename(modpack_path) .replace(".zip", "") .replace(".mrpack", ""); + zipnamew=zipname let dud_files: Array = []; let pack_info: object; //unzip @@ -33,10 +55,15 @@ async function main(modpack_path: string) { zipfile.on("entry", async (entry) => { if (/\/$/.test(entry.fileName)) { } else if (entry.fileName.includes("overrides/")) { - /*zipfile.openReadStream(entry,(err,stream)=>{ //读取overrides文件夹下的所有文件和文件夹 - - })*/ + const zipfilex = join(unzip_path, zipname,entry.fileName.replace("overrides/","")) + if(!fse.existsSync(zipfilex)){ + zipfile.openReadStream(entry,(err,stream)=>{ //读取overrides文件夹下的所有文件和文件夹 + const dir = dirname(zipfilex) + fse.ensureDirSync(dir); + stream.pipe(fse.createWriteStream(zipfilex)) + }) //console.log(entry.fileName) + } } else { const name: string = entry.fileName; dud_files.push(name); @@ -45,15 +72,41 @@ async function main(modpack_path: string) { (await readzipentry(zipfile, entry)).toString() ); } - console.log(name); } zipfile.readEntry(); }); - zipfile.on("end", () => { + zipfile.on("end", async () => { //zip - platform(what_platform(dud_files)); - //console.log(dud_files) + const dirx = join(unzip_path,zipname) + const plat = platform(what_platform(dud_files)) + const info = await plat.getinfo(pack_info); + await plat.downloadfile(pack_info,dirx) + await install(info.loader,info.minecraft,info.loader_version,dirx) + await DeEarthMain(join(dirx,"mods"),join(unzip_path,"rubbish")) + LOGGER.info("DeEarthX已将服务端制作完成!"); zipfile.close(); }); }); } + +async function install(type: string,minecraft:string,loaderver:string,path:string){ +switch(type){ + case "fabric": + await fabric(minecraft,loaderver,path) + break; + case "fabric-loader": + await fabric(minecraft,loaderver,path) + break; + case "forge": + await forge(minecraft,loaderver,path) + break; + case "neoforge": + await neoforge(minecraft,loaderver,path) + break; +} +} + +function getCurrnetDir () { + const url = new URL(".", import.meta.url); + return fileURLToPath(url); +} \ No newline at end of file diff --git a/src/ml_install/forge.ts b/src/ml_install/forge.ts index 6f089ac..c221a15 100644 --- a/src/ml_install/forge.ts +++ b/src/ml_install/forge.ts @@ -27,6 +27,7 @@ export default async function install( .get(`version/${minecraftversion}/json`) .json()) as mcinfoX; //获取Minecraft版本JSON const forgepath = path; + console.log(loaderversion) const forgedata = ( await gotx.get( `forge/download?mcversion=${minecraftversion}&version=${loaderversion}&category=installer&format=jar` @@ -49,7 +50,7 @@ export default async function install( //下载依赖1 const t = fvdata[c].downloads.artifact; await xfastdownload( - `maven${new URL(t.url).pathname}`, + `https://bmclapi2.bangbang93.com/maven${new URL(t.url).pathname}`, `${forgepath}/libraries/${t.path}`, 16 ); @@ -61,7 +62,7 @@ export default async function install( //下载依赖2 const t = fvdata[c].downloads.artifact; await xfastdownload( - `maven${new URL(t.url).pathname}`, + `https://bmclapi2.bangbang93.com/maven${new URL(t.url).pathname}`, `${forgepath}/libraries/${t.path}`, 16 ); @@ -69,7 +70,7 @@ export default async function install( //下载MAPPING与MOJMAPS /*MOJMAPS*/ await xfastdownload( - new URL(mcinfo.downloads.server_mappings.url).pathname, + `https://bmclapi2.bangbang93.com${new URL(mcinfo.downloads.server_mappings.url).pathname}`, `${forgepath}/libraries/${mavenToUrl( json.data.MOJMAPS.server.replace(/[[\]]/g, ""), "" @@ -83,7 +84,7 @@ export default async function install( /['"]/g, "" )}.zip`; - await xfastdownload(`maven/${tmp}`, `${forgepath}/libraries/${tmp}`); + await xfastdownload(`https://bmclapi2.bangbang93.com/maven/${tmp}`, `${forgepath}/libraries/${tmp}`); LOGGER.info("下载MAPPING与MOJMAPS完成!"); } } @@ -91,14 +92,14 @@ export default async function install( for (let d = 0; d < mcinfo.libraries.length; d++) { const g = mcinfo.libraries[d].downloads.artifact; await xfastdownload( - `maven${new URL(g.url).pathname}`, + `https://bmclapi2.bangbang93.com/maven${new URL(g.url).pathname}`, `${forgepath}/libraries/${g.path}`, 16 ); } LOGGER.info(`下载Minecraft的Maven完成!`); await xfastdownload( - `version/${minecraftversion}/server`, + `https://bmclapi2.bangbang93.com/version/${minecraftversion}/server`, `${forgepath}/libraries/net/minecraft/server/${minecraftversion}/server-${minecraftversion}.jar`, 1 ); diff --git a/src/platform/curseforge.ts b/src/platform/curseforge.ts index 90e3215..29caaa7 100644 --- a/src/platform/curseforge.ts +++ b/src/platform/curseforge.ts @@ -1,11 +1,14 @@ -import { fastdownload } from "../utils/utils.js"; +import got from "got"; +import { fastdownload, usemirror } from "../utils/utils.js"; import { modpack_info, XPlatform } from "./index.js"; +const cf_url = (()=>{if(usemirror){return "https://mod.mcimirror.top/curseforge"}else{return "https://api.curseforge.com"}})() export interface CurseForgeManifest { minecraft: { version: string; modLoaders: Array<{ id: string }>; }; + files: Array<{ projectID: number; fileID: number }>; } export class CurseForge implements XPlatform { @@ -14,15 +17,39 @@ export class CurseForge implements XPlatform { const local_manifest = manifest as CurseForgeManifest; if (result && local_manifest) result.minecraft = local_manifest.minecraft.version; - const loader_all = local_manifest.minecraft.modLoaders[0].id.match( + const id = local_manifest.minecraft.modLoaders[0].id; + const loader_all = id.match( /(.*)-/ ) as RegExpMatchArray; result.loader = loader_all[1]; - result.loader_version = loader_all[0]; + result.loader_version = id.replace(loader_all[0],""); return result; } - async downloadfile(urls: [string, string]): Promise { - await fastdownload(urls); + async downloadfile(manifest: object,path:string): Promise { + const local_manifest = manifest as CurseForgeManifest; + const FileID = JSON.stringify({ + fileIds: local_manifest.files.map((file: { fileID: number; }) => file.fileID), + }); + let tmp: [string, string] | string[][] = []; + await got.post(cf_url+"/v1/mods/files",{ + body: FileID, + headers: { + "Content-Type": "application/json", + "x-api-key":"$2a$10$ydk0TLDG/Gc6uPMdz7mad.iisj2TaMDytVcIW4gcVP231VKngLBKy" + } + }).json().then((res:any)=>{ + res.data.forEach((e: { fileName: string; downloadUrl: null|string; }) => { + if (e.fileName.endsWith(".zip")||e.downloadUrl == null) { + return; + } + if (usemirror){ + tmp.push(["https://mod.mcimirror.top"+new URL(e.downloadUrl).pathname,path+"/mods/" + e.fileName]) + }else{ + tmp.push([e.downloadUrl,path+"/mods/" + e.fileName]) + } + }); + }) + await fastdownload(tmp as unknown as [string, string]) //下载文件 } } diff --git a/src/platform/index.ts b/src/platform/index.ts index 389f371..54755f5 100644 --- a/src/platform/index.ts +++ b/src/platform/index.ts @@ -4,9 +4,7 @@ import { Modrinth } from "./modrinth.js"; export interface XPlatform { getinfo(manifest: object): Promise; - downloadfile( - urls: [string, string] | [string, string, string] - ): Promise; + downloadfile(manifest: object,path:string): Promise; } export interface modpack_info { diff --git a/src/platform/modrinth.ts b/src/platform/modrinth.ts index 5d069fd..703dbb7 100644 --- a/src/platform/modrinth.ts +++ b/src/platform/modrinth.ts @@ -1,7 +1,9 @@ -import { mr_fastdownload } from "../utils/utils.js"; +import fs from "node:fs"; +import { mr_fastdownload, usemirror } from "../utils/utils.js"; import { modpack_info, XPlatform } from "./index.js"; interface ModrinthManifest { + files: Array<{ path: string; downloads: string[]; fileSize: number; }>; dependencies: { minecraft: string; forge: string; @@ -27,7 +29,19 @@ export class Modrinth implements XPlatform { } return result; } - async downloadfile(urls: [string, string, string]): Promise { - await mr_fastdownload(urls); + async downloadfile(manifest: object,path:string): Promise { + const index = manifest as ModrinthManifest; + let tmp: [string, string, string][] = [] + index.files.forEach(async (e: { path: string; downloads: string[]; fileSize: number;}) => { + if (e.path.endsWith(".zip")) { + return; + } + if (usemirror){ + tmp.push(["https://mod.mcimirror.top"+new URL(e.downloads[0]).pathname,path+e.path,String(e.fileSize)]) + }else{ + tmp.push([e.downloads[0],path + e.path,String(e.fileSize)]) + } + }); + await mr_fastdownload(tmp as unknown as [string, string, string]) } } diff --git a/src/utils/DeEarth.ts b/src/utils/DeEarth.ts index 4152b74..5e3683c 100644 --- a/src/utils/DeEarth.ts +++ b/src/utils/DeEarth.ts @@ -18,6 +18,8 @@ export async function DeEarthMain(modspath: string, movepath: any) { fs.mkdirSync(movepath) } LOGGER.info(`DeEarth V1.0.0`) + LOGGER.info(`如有无法筛选的mods,请前往 https://dearth.0771010.xyz/ 提交未成功筛选的模组的modid`) + LOGGER.info(`Probejs 7.0.0以上版本为非客户端mod,如rubbish中有请自行添加回去`) const resaddr = fs.readdirSync(modspath) LOGGER.info(`获取目录列表,一共${resaddr.length}个jar文件。`) const totalBar = multibar.create(resaddr.length, 0, { filename: '总文件数' }) diff --git a/src/utils/logger.ts b/src/utils/logger.ts index cdd97a3..c6afeac 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -32,7 +32,7 @@ function error(error: object | string) { console.log( `[${chalk.blue( new Date().toLocaleDateString() + " " + new Date().toLocaleTimeString() - )}](${process.pid})[${chalk.red("ERROR")}:${error.toString()}` + )}](${process.pid})[${chalk.red("ERROR")}:${JSON.stringify(error)}` ); } else { console.log( diff --git a/src/utils/utils.ts b/src/utils/utils.ts index c6c4501..1ba3a2f 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -3,7 +3,9 @@ import pRetry from "p-retry"; import fse from "fs-extra" import yauzl from "yauzl"; import got from "got"; +import env from "dotenv" import { MultiBar } from "cli-progress"; +import {URL, fileURLToPath } from "node:url"; import { LOGGER } from "./logger.js"; export async function readzipentry(zipfile: yauzl.ZipFile, entry: yauzl.Entry):Promise { @@ -119,4 +121,19 @@ export async function xfastdownload( concurrency: concurrency, } ); - } \ No newline at end of file + } + +export const usemirror = (()=>{ + env.config() + const mirror = process.env.MIRROR + if(mirror){ + return false + }else{ + return true + } +})() + +export const isDevelopment = (()=>{ + env.config() + return process.env.DEVELOPMENT +})() \ No newline at end of file