diff --git a/README.md b/README.md index e9a6a64..b63638b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# mincecraft-mod-packager +# minecraft-mod-packager -A minecraft mod package manager \ No newline at end of file +A minecraft mod package manager diff --git a/src/curse.js b/src/curse.js new file mode 100644 index 0000000..6c4bf53 --- /dev/null +++ b/src/curse.js @@ -0,0 +1,113 @@ +const { http, https } = require('follow-redirects'); +const fs = require("fs"); +let downloadStarted = false; +let mods_lock; +let dep = new Map(); +try { + mods_lock = new Map(Object.entries(mods_lock)); +} catch { + mods_lock = new Map; +} +global.config.mods.curse.forEach(mod => { + getData(`search?categoryId=0&gameId=432&gameVersion=${encodeURI(global.config.gameVersion)}&index=0&pageSize=15&searchFilter=${encodeURI(mod)}§ionId=6&sort=2`, (result) => { // resolve projectID + resolveDep(result[0].id, downloadMods); + }); +}); + +var resolveDepRecursionCount = []; +function resolveDep(modId, callback, index) { + if(index === undefined) index = resolveDepRecursionCount.push(0) - 1; + ++resolveDepRecursionCount[index]; + getData(`${modId}/files`, (files) => { + let rightVersion; + for(let i = files.length - 1; i >= 0; --i) { + let versionArray = files[i].gameVersion; + if(versionMatch(versionArray, global.config.gameVersion) && (versionMatch(versionArray, global.config.modloader) || modloaderMatch(versionArray, global.config.modloader))) { + rightVersion = files[i]; + dep.set(modId, {fileId: rightVersion.id, url: rightVersion.downloadUrl}); + } + } + rightVersion.dependencies.forEach(mod => { + resolveDep(mod.addonId, callback, index); + }); + --resolveDepRecursionCount[index]; + if(resolveDepRecursionCount[index] == 0) callback(); + }); +} + +function getData(url, callback) { + https.get(`https://addons-ecs.forgesvc.net/api/v2/addon/${url}`, (resp) => { + let data = ''; + resp.on('data', (chunk) => { + data += chunk; + }); + resp.on("end", () => { + callback(JSON.parse(data)); + }); + }); +} + +function versionMatch(versionArray, gameVersion) { + let gameVersionMatch = false; + versionArray.forEach(version => { + gameVersionMatch = gameVersionMatch || version == gameVersion; + }); + return gameVersionMatch; +} + +function modloaderMatch(versionArray, modloaderVersion) { + versionArray.forEach(version => { + if(/^[a-zA-Z]+$/.test(version) && version != modloaderVersion) return false; + return true; + }); +} + +function downloadMods() { + if(!downloadStarted) { + downloadStarted = true; + save_mods_lock = Object.fromEntries(dep); + globCallback(); + dep.forEach((mod, modId) => { + getData(modId, (data) => { + let path = `mods/${data.name}.jar` + if(mods_lock.has(String(modId))) { + if(mods_lock.get(String(modId)).fileId === mod.fileId) return; + fs.unlink(path); + } + downloadFile(mod.url, path); + }); + }); + } +} + +function downloadFile(url, dest) { + let file = fs.createWriteStream(dest); + console.log(`downloading... ${url}`); + let request = https.get(url, (response) => { + // check if response is success + if (response.statusCode !== 200) { + throw response.statusCode; + } + + response.pipe(file); + }); + + // close() is async, call cb after close completes + file.on('finish', () => file.close()); + + // check for request error too + request.on('error', (err) => { + fs.unlink(dest); + throw err; + }); + + file.on('error', (err) => { // Handle errors + fs.unlink(dest); + throw err; + }); +} +module.exports = function(saved_mods_lock, mods_lock_p, callback) { + var save_mods_lock = saved_mods_lock; + var mods_lock = mods_lock_p; + globCallback = callback; +}; diff --git a/src/main.js b/src/main.js index d886290..52c0908 100644 --- a/src/main.js +++ b/src/main.js @@ -1,127 +1,25 @@ -const { http, https } = require('follow-redirects'); const jsonMinify = require("node-json-minify"); const fs = require("fs"); -let dep = new Map(); -let config; -let downloadStarted = false; switch(process.argv.length) { case 3: process.chdir(process.argv[2]); case 2: - config = JSON.parse(jsonMinify(fs.readFileSync("mods.json", "utf-8"))); + global.config = JSON.parse(jsonMinify(fs.readFileSync("mods.json", "utf-8"))); break; default: throw "unexpected argument"; } -config.mods.curse.forEach(mod => { - getData(`search?categoryId=0&gameId=432&gameVersion=${encodeURI(config.gameVersion)}&index=0&pageSize=15&searchFilter=${encodeURI(mod)}§ionId=6&sort=2`, (result) => { // resolve projectID - resolveDep(result[0].id, function(){ - for(const modFile of dep) { - if(mods_lock !== undefined) downloadMods(); - let waitModsLock = setInterval(function() { - if(mods_lock !== undefined) { - clearInterval(waitModsLock); - downloadMods(); - } - }, 1); - } - }); - }); -}); -let mods_lock; -fs.readFile("mods-lock.json", "utf-8", (err, data) => { - if(err) { - if(err.errno == -2) mods_lock = new Map(); - else throw err; - } - else mods_lock = new Map(Objects.entries(JSON.parse(data))); -}); +const modLockPath = "mods-lock.json"; +let save_mods_lock = {}; +let modsLock = JSON.parse(fs.readFileSync(modLockPath, "utf-8")); +const numberCallback = 2; +let callbackCounter = 0; +require("./curse.js")(save_mods_lock.curse, modsLock.curse, finnish); -var resolveDepRecursionCount = []; -function resolveDep(modId, callback, index) { - if(index === undefined) index = resolveDepRecursionCount.push(0) - 1; - ++resolveDepRecursionCount[index]; - getData(`${modId}/files`, (files) => { - let rightVersion; - for(let i = files.length - 1; i >= 0; --i) { - let versionArray = files[i].gameVersion; - if(versionMatch(versionArray, config.gameVersion) && (versionMatch(versionArray, config.modloader) || modloaderMatch(versionArray, config.modloader))) { - rightVersion = files[i]; - dep.set(modId, {fileId: rightVersion.id, url: rightVersion.downloadUrl}); - } - } - rightVersion.dependencies.forEach(mod => { - resolveDep(mod.addonId, callback, index); - }); - --resolveDepRecursionCount[index]; - if(resolveDepRecursionCount[index] == 0) callback(); - }); -} - -function getData(url, callback) { - https.get(`https://addons-ecs.forgesvc.net/api/v2/addon/${url}`, (resp) => { - let data = ''; - resp.on('data', (chunk) => { - data += chunk; - }); - resp.on("end", () => { - callback(JSON.parse(data)); - }); - }); -} - -function versionMatch(versionArray, gameVersion) { - let gameVersionMatch = false; - versionArray.forEach(version => { - gameVersionMatch = gameVersionMatch || version == gameVersion; - }); - return gameVersionMatch; -} - -function modloaderMatch(versionArray, modloaderVersion) { - versionArray.forEach(version => { - if(/^[a-zA-Z]+$/.test(version) && version != modloaderVersion) return false; - return true; - }); -} - -function downloadMods() { - if(!downloadStarted) { - downloadStarted = true; - dep.forEach((mod, modId) => { - if(mods_lock.has(modId)) { - console.log(3) - if(mods_lock.get(mod.fileId) === mod.fileId) return; - fs.unlink(modId + " " + mods_lock.get(mod.fileId + ".jar")); - } - downloadFile(mod.url, "mods/" + modId + " " + mod.fileId + ".jar"); +function finnish() { + if(++callbackCounter == numberCallback) { + fs.writeFile(modLockPath, JSON.stringify(save_mods_lock), (err) => { + if(err) throw err; }); } } - -function downloadFile(url, dest) { - let file = fs.createWriteStream(dest); - console.log(url); - let request = https.get(url, (response) => { - // check if response is success - if (response.statusCode !== 200) { - throw response.statusCode; - } - - response.pipe(file); - }); - - // close() is async, call cb after close completes - file.on('finish', () => file.close()); - - // check for request error too - request.on('error', (err) => { - fs.unlink(dest); - throw err; - }); - - file.on('error', (err) => { // Handle errors - fs.unlink(dest); - throw err; - }); -}