feat:基本最终完成
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -135,3 +135,4 @@ ndist
|
||||
# test files
|
||||
*.zip
|
||||
*.mrpack
|
||||
instance/
|
||||
13
package-lock.json
generated
13
package-lock.json
generated
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
75
src/main.ts
75
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<string> = [];
|
||||
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);
|
||||
}
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -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<void> {
|
||||
await fastdownload(urls);
|
||||
async downloadfile(manifest: object,path:string): Promise<void> {
|
||||
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]) //下载文件
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,7 @@ import { Modrinth } from "./modrinth.js";
|
||||
|
||||
export interface XPlatform {
|
||||
getinfo(manifest: object): Promise<modpack_info>;
|
||||
downloadfile(
|
||||
urls: [string, string] | [string, string, string]
|
||||
): Promise<void>;
|
||||
downloadfile(manifest: object,path:string): Promise<void>;
|
||||
}
|
||||
|
||||
export interface modpack_info {
|
||||
|
||||
@@ -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<void> {
|
||||
await mr_fastdownload(urls);
|
||||
async downloadfile(manifest: object,path:string): Promise<void> {
|
||||
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])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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: '总文件数' })
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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<string|Buffer> {
|
||||
@@ -120,3 +122,18 @@ export async function xfastdownload(
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
})()
|
||||
Reference in New Issue
Block a user