added launching, patching, and ui override
This commit is contained in:
20
src/util/executeUtil.js
Normal file
20
src/util/executeUtil.js
Normal file
@@ -0,0 +1,20 @@
|
||||
const childProcess = require("child_process");
|
||||
|
||||
const runFile = (folder, file, args, onExit) => {
|
||||
childProcess.execFile(file, args, {
|
||||
cwd: folder
|
||||
}, (_err, _stdout, _stdin) => {
|
||||
if (onExit) onExit();
|
||||
})
|
||||
}
|
||||
|
||||
const runFileDetached = (folder, file, args) => {
|
||||
const subProcess = childProcess.spawn(file + (args ? " " + args : ''), {
|
||||
cwd: folder,
|
||||
detached: true,
|
||||
stdio: 'ignore'
|
||||
});
|
||||
subProcess.unref();
|
||||
}
|
||||
|
||||
module.exports = { runFile, runFileDetached };
|
13
src/util/formattingUtil.js
Normal file
13
src/util/formattingUtil.js
Normal file
@@ -0,0 +1,13 @@
|
||||
function formatBytes(bytes, decimals = 2) {
|
||||
if (!+bytes) return '0 Bytes'
|
||||
|
||||
const k = 1024
|
||||
const dm = decimals < 0 ? 0 : decimals
|
||||
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
||||
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
||||
|
||||
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))}${sizes[i]}`
|
||||
}
|
||||
|
||||
module.exports = { formatBytes };
|
@@ -1,3 +1,3 @@
|
||||
export const clamp = (val: number, min: number, max: number) => {
|
||||
return Math.max(min, Math.min(val, max));
|
||||
};
|
||||
};
|
@@ -1,5 +1,9 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const crypto = require("crypto");
|
||||
const EventEmitter = require("events");
|
||||
const { default: axios } = require("axios");
|
||||
const { runFile } = require("./executeUtil");
|
||||
|
||||
const checkUpdateURL =
|
||||
"https://osu.ppy.sh/web/check-updates.php?action=check&stream=";
|
||||
@@ -30,6 +34,27 @@ const osuEntities = [
|
||||
"scores.db",
|
||||
];
|
||||
|
||||
const patcherFiles = [
|
||||
{
|
||||
name: "patcher.exe",
|
||||
url_download: "https://ez-pp.farm/assets/patcher.exe",
|
||||
url_hash: "https://ez-pp.farm/assets/patcher.md5"
|
||||
},
|
||||
{
|
||||
name: "patch.hook.dll",
|
||||
url_download: "https://ez-pp.farm/assets/patch.hook.dll",
|
||||
url_hash: "https://ez-pp.farm/assets/patch.hook.md5"
|
||||
}
|
||||
]
|
||||
|
||||
const uiFiles = [
|
||||
{
|
||||
name: "ezpp!ui.dll",
|
||||
url_download: "https://ez-pp.farm/assets/ezpp!ui.dll",
|
||||
url_hash: "https://ez-pp.farm/assets/ezpp!ui.md5"
|
||||
}
|
||||
]
|
||||
|
||||
async function isValidOsuFolder(path) {
|
||||
const allFiles = await fs.promises.readdir(path);
|
||||
let matches = 0;
|
||||
@@ -39,10 +64,71 @@ async function isValidOsuFolder(path) {
|
||||
return (Math.round((matches / osuEntities.length) * 100) >= 60);
|
||||
}
|
||||
|
||||
async function getUserConfig(osuPath) {
|
||||
function getGlobalConfig(osuPath) {
|
||||
const configFileInfo = {
|
||||
name: "",
|
||||
path: "",
|
||||
get: async (key) => {
|
||||
if (!configFileInfo.path) {
|
||||
console.log("config file not loaded");
|
||||
return "";
|
||||
}
|
||||
const fileStream = await fs.promises.readFile(
|
||||
configFileInfo.path,
|
||||
"utf-8",
|
||||
);
|
||||
const lines = fileStream.split(/\r?\n/);
|
||||
for (const line of lines) {
|
||||
if (line.includes(" = ")) {
|
||||
const argsPair = line.split(" = ", 2);
|
||||
const keyname = argsPair[0];
|
||||
const value = argsPair[1];
|
||||
if (keyname == key) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
const globalOsuConfig = path.join(osuPath, "osu!.cfg");
|
||||
if (fs.existsSync(globalOsuConfig)) {
|
||||
configFileInfo.name = "osu!.cfg";
|
||||
configFileInfo.path = globalOsuConfig;
|
||||
}
|
||||
return configFileInfo;
|
||||
}
|
||||
|
||||
function getUserConfig(osuPath) {
|
||||
const configFileInfo = {
|
||||
name: "",
|
||||
path: "",
|
||||
set: async (key, newValue) => {
|
||||
if (!configFileInfo.path) {
|
||||
return "";
|
||||
}
|
||||
const fileContents = [];
|
||||
const fileStream = await fs.promises.readFile(
|
||||
configFileInfo.path,
|
||||
"utf-8",
|
||||
);
|
||||
const lines = fileStream.split(/\r?\n/);
|
||||
for (const line of lines) {
|
||||
if (line.includes(" = ")) {
|
||||
const argsPair = line.split(" = ", 2);
|
||||
const keyname = argsPair[0];
|
||||
if (keyname == key) {
|
||||
fileContents.push(`${key} = ${newValue}`);
|
||||
} else {
|
||||
fileContents.push(line);
|
||||
}
|
||||
} else {
|
||||
fileContents.push(line);
|
||||
}
|
||||
}
|
||||
await fs.promises.writeFile(configFileInfo.path, fileContents.join("\n"));
|
||||
|
||||
return true;
|
||||
},
|
||||
get: async (key) => {
|
||||
if (!configFileInfo.path) {
|
||||
return "";
|
||||
@@ -80,4 +166,194 @@ async function getUpdateFiles(releaseStream) {
|
||||
return releaseData.ok ? await releaseData.json() : undefined;
|
||||
}
|
||||
|
||||
module.exports = { isValidOsuFolder, getUserConfig, getUpdateFiles };
|
||||
async function getFilesThatNeedUpdate(osuPath, releaseStreamFiles) {
|
||||
const updateFiles = [];
|
||||
for (const updatePatch of releaseStreamFiles) {
|
||||
const fileName = updatePatch.filename;
|
||||
const fileHash = updatePatch.file_hash;
|
||||
|
||||
const fileOnDisk = path.join(osuPath, fileName);
|
||||
if (fs.existsSync(fileOnDisk)) {
|
||||
if (ignoredOsuEntities.includes(fileName)) continue;
|
||||
const fileHashOnDisk = crypto.createHash("md5").update(fs.readFileSync(fileOnDisk)).digest("hex");
|
||||
if (fileHashOnDisk.trim().toLowerCase() != fileHash.trim().toLowerCase()) {
|
||||
console.log({
|
||||
fileOnDisk,
|
||||
fileHashOnDisk,
|
||||
fileHash
|
||||
})
|
||||
updateFiles.push(updatePatch);
|
||||
}
|
||||
} else updateFiles.push(updatePatch);
|
||||
}
|
||||
|
||||
return updateFiles;
|
||||
}
|
||||
|
||||
function downloadUpdateFiles(osuPath, updateFiles) {
|
||||
const eventEmitter = new EventEmitter();
|
||||
|
||||
const startDownload = async () => {
|
||||
for (const updatePatch of updateFiles) {
|
||||
const fileName = updatePatch.filename;
|
||||
const fileSize = updatePatch.filesize;
|
||||
const fileURL = updatePatch.url_full;
|
||||
|
||||
const axiosDownloadWithProgress = await axios.get(fileURL, {
|
||||
responseType: "stream",
|
||||
onDownloadProgress: (progressEvent) => {
|
||||
const { loaded, total } = progressEvent;
|
||||
eventEmitter.emit("data", {
|
||||
fileName,
|
||||
loaded,
|
||||
total,
|
||||
progress: Math.floor((loaded / total) * 100)
|
||||
});
|
||||
},
|
||||
});
|
||||
axiosDownloadWithProgress.data.on("end", () => {
|
||||
eventEmitter.emit("data", {
|
||||
fileName,
|
||||
loaded: fileSize,
|
||||
total: fileSize,
|
||||
progress: 100
|
||||
});
|
||||
})
|
||||
await fs.promises.writeFile(path.join(osuPath, fileName), axiosDownloadWithProgress.data);
|
||||
}
|
||||
|
||||
// wait until all files are downloaded
|
||||
return true;
|
||||
}
|
||||
|
||||
return {
|
||||
eventEmitter,
|
||||
startDownload,
|
||||
}
|
||||
}
|
||||
|
||||
function runOsuWithDevServer(osuPath, serverDomain, onExit) {
|
||||
const osuExecuteable = path.join(osuPath, "osu!.exe");
|
||||
runFile(osuPath, osuExecuteable, ["-devserver", serverDomain], onExit);
|
||||
}
|
||||
|
||||
async function getPatcherUpdates(osuPath) {
|
||||
|
||||
const filesToDownload = [];
|
||||
|
||||
const patcherDir = path.join(osuPath, "EZPPLauncher");
|
||||
if (!fs.existsSync(patcherDir)) fs.mkdirSync(patcherDir);
|
||||
|
||||
for (const patcherFile of patcherFiles) {
|
||||
if (fs.existsSync(path.join(patcherDir, patcherFile.name))) {
|
||||
const latestPatchFileHash = await (await fetch(patcherFile.url_hash)).text();
|
||||
const localPatchFileHash = crypto.createHash("md5").update(fs.readFileSync(path.join(patcherDir, patcherFile.name))).digest("hex");
|
||||
if (latestPatchFileHash.trim().toLowerCase() != localPatchFileHash.trim().toLowerCase()) filesToDownload.push(patcherFile);
|
||||
} else filesToDownload.push(patcherFile);
|
||||
}
|
||||
|
||||
return filesToDownload;
|
||||
}
|
||||
|
||||
function downloadPatcherUpdates(osuPath, patcherUpdates) {
|
||||
const eventEmitter = new EventEmitter();
|
||||
|
||||
const startDownload = async () => {
|
||||
|
||||
const patcherDir = path.join(osuPath, "EZPPLauncher");
|
||||
if (!fs.existsSync(patcherDir)) fs.mkdirSync(patcherDir);
|
||||
|
||||
for (const patcherFile of patcherUpdates) {
|
||||
const fileName = patcherFile.name;
|
||||
const fileURL = patcherFile.url_download;
|
||||
const axiosDownloadWithProgress = await axios.get(fileURL, {
|
||||
responseType: "stream",
|
||||
onDownloadProgress: (progressEvent) => {
|
||||
const { loaded, total } = progressEvent;
|
||||
eventEmitter.emit("data", {
|
||||
fileName,
|
||||
loaded,
|
||||
total,
|
||||
progress: Math.floor((loaded / total) * 100)
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
await fs.promises.writeFile(path.join(osuPath, "EZPPLauncher", fileName), axiosDownloadWithProgress.data);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
eventEmitter,
|
||||
startDownload,
|
||||
}
|
||||
}
|
||||
|
||||
async function getUIFiles(osuPath) {
|
||||
|
||||
const filesToDownload = [];
|
||||
|
||||
const ezppLauncherDir = path.join(osuPath, "EZPPLauncher");
|
||||
if (!fs.existsSync(ezppLauncherDir)) fs.mkdirSync(ezppLauncherDir);
|
||||
|
||||
for (const uiFile of uiFiles) {
|
||||
if (fs.existsSync(path.join(ezppLauncherDir, uiFile.name))) {
|
||||
const latestPatchFileHash = await (await fetch(uiFile.url_hash)).text();
|
||||
const localPatchFileHash = crypto.createHash("md5").update(fs.readFileSync(path.join(ezppLauncherDir, uiFile.name))).digest("hex");
|
||||
if (latestPatchFileHash.trim().toLowerCase() != localPatchFileHash.trim().toLowerCase()) filesToDownload.push(uiFile);
|
||||
} else filesToDownload.push(uiFile);
|
||||
}
|
||||
|
||||
return filesToDownload;
|
||||
}
|
||||
|
||||
function downloadUIFiles(osuPath, uiFiles) {
|
||||
const eventEmitter = new EventEmitter();
|
||||
|
||||
const startDownload = async () => {
|
||||
|
||||
const ezpplauncherDir = path.join(osuPath, "EZPPLauncher");
|
||||
if (!fs.existsSync(ezpplauncherDir)) fs.mkdirSync(ezpplauncherDir);
|
||||
|
||||
for (const uiFile of uiFiles) {
|
||||
const fileName = uiFile.name;
|
||||
const fileURL = uiFile.url_download;
|
||||
const axiosDownloadWithProgress = await axios.get(fileURL, {
|
||||
responseType: "stream",
|
||||
onDownloadProgress: (progressEvent) => {
|
||||
const { loaded, total } = progressEvent;
|
||||
eventEmitter.emit("data", {
|
||||
fileName,
|
||||
loaded,
|
||||
total,
|
||||
progress: Math.floor((loaded / total) * 100)
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
await fs.promises.writeFile(path.join(osuPath, "EZPPLauncher", fileName), axiosDownloadWithProgress.data);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
eventEmitter,
|
||||
startDownload,
|
||||
}
|
||||
}
|
||||
|
||||
async function replaceUIFile(osuPath, revert) {
|
||||
if (!revert) {
|
||||
const ezppUIFile = path.join(osuPath, "EZPPLauncher", "ezpp!ui.dll");
|
||||
const oldOsuUIFile = path.join(osuPath, "osu!ui.dll");
|
||||
await fs.promises.rename(oldOsuUIFile, path.join(osuPath, "osu!ui.dll.bak"));
|
||||
await fs.promises.rename(ezppUIFile, oldOsuUIFile);
|
||||
} else {
|
||||
const oldOsuUIFile = path.join(osuPath, "osu!ui.dll");
|
||||
const ezppUIFile = path.join(osuPath, "EZPPLauncher", "ezpp!ui.dll");
|
||||
await fs.promises.rename(oldOsuUIFile, ezppUIFile);
|
||||
await fs.promises.rename(path.join(osuPath, "osu!ui.dll.bak"), oldOsuUIFile);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = { isValidOsuFolder, getUserConfig, getGlobalConfig, getUpdateFiles, getFilesThatNeedUpdate, downloadUpdateFiles, runOsuWithDevServer, getPatcherUpdates, downloadPatcherUpdates, downloadUIFiles, getUIFiles, replaceUIFile };
|
||||
|
Reference in New Issue
Block a user