Merge pull request 'add optional logging, cleanup fixes' (#15) from dev into master
Reviewed-on: #15
This commit is contained in:
commit
ecf329dd69
|
@ -1,4 +1,4 @@
|
||||||
const appName = "EZPPLauncher";
|
const appName = "EZPPLauncher";
|
||||||
const appVersion = "2.1.4";
|
const appVersion = "2.1.5";
|
||||||
|
|
||||||
module.exports = { appName, appVersion };
|
module.exports = { appName, appVersion };
|
||||||
|
|
|
@ -2,19 +2,19 @@ const childProcess = require("child_process");
|
||||||
|
|
||||||
const runFile = (folder, file, args, onExit) => {
|
const runFile = (folder, file, args, onExit) => {
|
||||||
childProcess.execFile(file, args, {
|
childProcess.execFile(file, args, {
|
||||||
cwd: folder
|
cwd: folder,
|
||||||
}, (_err, _stdout, _stdin) => {
|
}, (_err, _stdout, _stdin) => {
|
||||||
if (onExit) onExit();
|
if (onExit) onExit();
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const runFileDetached = (folder, file, args) => {
|
const runFileDetached = (folder, file, args) => {
|
||||||
const subProcess = childProcess.spawn(file + (args ? " " + args : ''), {
|
const subProcess = childProcess.spawn(file + (args ? " " + args : ""), {
|
||||||
cwd: folder,
|
cwd: folder,
|
||||||
detached: true,
|
detached: true,
|
||||||
stdio: 'ignore'
|
stdio: "ignore",
|
||||||
});
|
});
|
||||||
subProcess.unref();
|
subProcess.unref();
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = { runFile, runFileDetached };
|
module.exports = { runFile, runFileDetached };
|
15
electron/fileUtil.js
Normal file
15
electron/fileUtil.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
function isWritable(filePath) {
|
||||||
|
let fileAccess = false;
|
||||||
|
try {
|
||||||
|
fs.closeSync(fs.openSync(filePath, "r+"));
|
||||||
|
fileAccess = true;
|
||||||
|
} catch {
|
||||||
|
}
|
||||||
|
return fileAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
isWritable,
|
||||||
|
};
|
|
@ -1,13 +1,13 @@
|
||||||
function formatBytes(bytes, decimals = 2) {
|
function formatBytes(bytes, decimals = 2) {
|
||||||
if (!+bytes) return '0 Bytes'
|
if (!+bytes) return "0 B";
|
||||||
|
|
||||||
const k = 1024
|
const k = 1024;
|
||||||
const dm = decimals < 0 ? 0 : decimals
|
const dm = decimals < 0 ? 0 : decimals;
|
||||||
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||||
|
|
||||||
const i = Math.floor(Math.log(bytes) / Math.log(k))
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
|
|
||||||
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))}${sizes[i]}`
|
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))}${sizes[i]}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { formatBytes };
|
module.exports = { formatBytes };
|
44
electron/logging.js
Normal file
44
electron/logging.js
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
class Logger {
|
||||||
|
constructor(directory) {
|
||||||
|
this.directory = directory;
|
||||||
|
this.enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
const filename = `${new Date().toISOString().replace(/:/g, "-")}.log`;
|
||||||
|
this.logPath = path.join(this.directory, filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
async log(message) {
|
||||||
|
if (this.logPath === undefined || this.enabled == false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(this.logPath)) {
|
||||||
|
await fs.promises.mkdir(this.directory, { recursive: true });
|
||||||
|
await fs.promises.writeFile(this.logPath, "");
|
||||||
|
}
|
||||||
|
const logMessage = `[${new Date().toISOString()}] LOG: ${message}`;
|
||||||
|
await fs.promises.appendFile(this.logPath, `${logMessage}\n`);
|
||||||
|
console.log(logMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
async error(message, error) {
|
||||||
|
if (this.logPath === undefined || this.enabled == false) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(this.logPath)) {
|
||||||
|
await fs.promises.mkdir(this.directory, { recursive: true });
|
||||||
|
await fs.promises.writeFile(this.logPath, "");
|
||||||
|
}
|
||||||
|
const errorMessage = `[${
|
||||||
|
new Date().toISOString()
|
||||||
|
}] ERROR: ${message}\n${error.stack}`;
|
||||||
|
await fs.promises.appendFile(this.logPath, `${errorMessage}\n`);
|
||||||
|
console.error(errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Logger;
|
|
@ -1,8 +1,8 @@
|
||||||
const { exec } = require("child_process");
|
const { exec } = require("child_process");
|
||||||
|
|
||||||
async function isNet8Installed() {
|
async function isNet8Installed() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve) => {
|
||||||
exec("dotnet --version", (error, stdout, stderr) => {
|
exec("dotnet --list-runtimes", (error, stdout, stderr) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
resolve(false);
|
resolve(false);
|
||||||
return;
|
return;
|
||||||
|
@ -12,7 +12,13 @@ async function isNet8Installed() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const version = stdout.trim();
|
const version = stdout.trim();
|
||||||
resolve(version.startsWith("8."));
|
for (const line of version.split('\n')) {
|
||||||
|
if (line.startsWith("Microsoft.WindowsDesktop.App 8.")) {
|
||||||
|
resolve(true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resolve(false);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,8 @@ const gamemodes = {
|
||||||
4: "osu!(rx)",
|
4: "osu!(rx)",
|
||||||
5: "taiko(rx)",
|
5: "taiko(rx)",
|
||||||
6: "catch(rx)",
|
6: "catch(rx)",
|
||||||
8: "osu!(ap)"
|
8: "osu!(ap)",
|
||||||
}
|
};
|
||||||
const osuEntities = [
|
const osuEntities = [
|
||||||
"avcodec-51.dll",
|
"avcodec-51.dll",
|
||||||
"avformat-52.dll",
|
"avformat-52.dll",
|
||||||
|
@ -44,7 +44,7 @@ const osuEntities = [
|
||||||
"scores.db",
|
"scores.db",
|
||||||
];
|
];
|
||||||
|
|
||||||
const ezppLauncherUpdateList = "https://ez-pp.farm/ezpplauncher"
|
const ezppLauncherUpdateList = "https://ez-pp.farm/ezpplauncher";
|
||||||
|
|
||||||
async function isValidOsuFolder(path) {
|
async function isValidOsuFolder(path) {
|
||||||
const allFiles = await fs.promises.readdir(path);
|
const allFiles = await fs.promises.readdir(path);
|
||||||
|
@ -184,6 +184,7 @@ function downloadUpdateFiles(osuPath, updateFiles) {
|
||||||
|
|
||||||
const startDownload = async () => {
|
const startDownload = async () => {
|
||||||
for (const updatePatch of updateFiles) {
|
for (const updatePatch of updateFiles) {
|
||||||
|
try {
|
||||||
const fileName = updatePatch.filename;
|
const fileName = updatePatch.filename;
|
||||||
const fileSize = updatePatch.filesize;
|
const fileSize = updatePatch.filesize;
|
||||||
const fileURL = updatePatch.url_full;
|
const fileURL = updatePatch.url_full;
|
||||||
|
@ -200,15 +201,7 @@ function downloadUpdateFiles(osuPath, updateFiles) {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
axiosDownloadWithProgress.data.on("end", () => {
|
|
||||||
eventEmitter.emit("data", {
|
|
||||||
fileName,
|
|
||||||
loaded: fileSize,
|
|
||||||
total: fileSize,
|
|
||||||
progress: 100,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
if (fs.existsSync(path.join(osuPath, fileName))) {
|
if (fs.existsSync(path.join(osuPath, fileName))) {
|
||||||
await fs.promises.rm(path.join(osuPath, fileName), {
|
await fs.promises.rm(path.join(osuPath, fileName), {
|
||||||
force: true,
|
force: true,
|
||||||
|
@ -222,6 +215,7 @@ function downloadUpdateFiles(osuPath, updateFiles) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
eventEmitter.emit("error", {
|
eventEmitter.emit("error", {
|
||||||
fileName,
|
fileName,
|
||||||
|
error: err,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,10 +242,16 @@ function runOsuWithDevServer(osuPath, serverDomain, onExit) {
|
||||||
|
|
||||||
async function getEZPPLauncherUpdateFiles(osuPath) {
|
async function getEZPPLauncherUpdateFiles(osuPath) {
|
||||||
const filesToDownload = [];
|
const filesToDownload = [];
|
||||||
const updateFilesRequest = await fetch(ezppLauncherUpdateList, { method: "PATCH" });
|
const updateFilesRequest = await fetch(ezppLauncherUpdateList, {
|
||||||
|
method: "PATCH",
|
||||||
|
});
|
||||||
const updateFiles = await updateFilesRequest.json();
|
const updateFiles = await updateFilesRequest.json();
|
||||||
for (const updateFile of updateFiles) {
|
for (const updateFile of updateFiles) {
|
||||||
const filePath = path.join(osuPath, ...updateFile.folder.split("/"), updateFile.name);
|
const filePath = path.join(
|
||||||
|
osuPath,
|
||||||
|
...updateFile.folder.split("/"),
|
||||||
|
updateFile.name,
|
||||||
|
);
|
||||||
if (fs.existsSync(filePath)) {
|
if (fs.existsSync(filePath)) {
|
||||||
const fileHash = updateFile.md5.toLowerCase();
|
const fileHash = updateFile.md5.toLowerCase();
|
||||||
const localFileHash = crypto.createHash("md5").update(
|
const localFileHash = crypto.createHash("md5").update(
|
||||||
|
@ -272,22 +272,30 @@ async function downloadEZPPLauncherUpdateFiles(osuPath, updateFiles) {
|
||||||
|
|
||||||
const startDownload = async () => {
|
const startDownload = async () => {
|
||||||
for (const updateFile of updateFiles) {
|
for (const updateFile of updateFiles) {
|
||||||
const filePath = path.join(osuPath, ...updateFile.folder.split("/"), updateFile.name);
|
try {
|
||||||
|
const filePath = path.join(
|
||||||
|
osuPath,
|
||||||
|
...updateFile.folder.split("/"),
|
||||||
|
updateFile.name,
|
||||||
|
);
|
||||||
const folder = path.dirname(filePath);
|
const folder = path.dirname(filePath);
|
||||||
if (!fs.existsSync(folder)) await fs.promises.mkdir(folder, { recursive: true });
|
if (!fs.existsSync(folder)) {
|
||||||
|
await fs.promises.mkdir(folder, { recursive: true });
|
||||||
|
}
|
||||||
const axiosDownloadWithProgress = await axios.get(updateFile.url, {
|
const axiosDownloadWithProgress = await axios.get(updateFile.url, {
|
||||||
responseType: "stream",
|
responseType: "stream",
|
||||||
onDownloadProgress: (progressEvent) => {
|
onDownloadProgress: (progressEvent) => {
|
||||||
const { loaded, total } = progressEvent;
|
const fileSize = updateFile.size;
|
||||||
|
const { loaded } = progressEvent;
|
||||||
eventEmitter.emit("data", {
|
eventEmitter.emit("data", {
|
||||||
fileName: path.basename(filePath),
|
fileName: path.basename(filePath),
|
||||||
loaded,
|
loaded,
|
||||||
total,
|
total: fileSize,
|
||||||
progress: Math.floor((loaded / total) * 100),
|
progress: Math.floor((loaded / fileSize) * 100),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
try {
|
|
||||||
if (fs.existsSync(filePath)) {
|
if (fs.existsSync(filePath)) {
|
||||||
await fs.promises.rm(filePath, {
|
await fs.promises.rm(filePath, {
|
||||||
force: true,
|
force: true,
|
||||||
|
@ -301,10 +309,11 @@ async function downloadEZPPLauncherUpdateFiles(osuPath, updateFiles) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
eventEmitter.emit("error", {
|
eventEmitter.emit("error", {
|
||||||
fileName: path.basename(filePath),
|
fileName: path.basename(filePath),
|
||||||
|
error: err,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
eventEmitter,
|
eventEmitter,
|
||||||
|
@ -316,7 +325,11 @@ async function replaceUIFiles(osuPath, revert) {
|
||||||
if (!revert) {
|
if (!revert) {
|
||||||
const ezppUIFile = path.join(osuPath, "EZPPLauncher", "ezpp!ui.dll");
|
const ezppUIFile = path.join(osuPath, "EZPPLauncher", "ezpp!ui.dll");
|
||||||
const oldOsuUIFile = path.join(osuPath, "osu!ui.dll");
|
const oldOsuUIFile = path.join(osuPath, "osu!ui.dll");
|
||||||
const ezppGameplayFile = path.join(osuPath, "EZPPLauncher", "ezpp!gameplay.dll");
|
const ezppGameplayFile = path.join(
|
||||||
|
osuPath,
|
||||||
|
"EZPPLauncher",
|
||||||
|
"ezpp!gameplay.dll",
|
||||||
|
);
|
||||||
const oldOsuGameplayFile = path.join(osuPath, "osu!gameplay.dll");
|
const oldOsuGameplayFile = path.join(osuPath, "osu!gameplay.dll");
|
||||||
|
|
||||||
await fs.promises.rename(
|
await fs.promises.rename(
|
||||||
|
@ -334,7 +347,11 @@ async function replaceUIFiles(osuPath, revert) {
|
||||||
const oldOsuUIFile = path.join(osuPath, "osu!ui.dll");
|
const oldOsuUIFile = path.join(osuPath, "osu!ui.dll");
|
||||||
const ezppUIFile = path.join(osuPath, "EZPPLauncher", "ezpp!ui.dll");
|
const ezppUIFile = path.join(osuPath, "EZPPLauncher", "ezpp!ui.dll");
|
||||||
const oldOsuGameplayFile = path.join(osuPath, "osu!gameplay.dll");
|
const oldOsuGameplayFile = path.join(osuPath, "osu!gameplay.dll");
|
||||||
const ezppGameplayFile = path.join(osuPath, "EZPPLauncher", "ezpp!gameplay.dll");
|
const ezppGameplayFile = path.join(
|
||||||
|
osuPath,
|
||||||
|
"EZPPLauncher",
|
||||||
|
"ezpp!gameplay.dll",
|
||||||
|
);
|
||||||
|
|
||||||
await fs.promises.rename(oldOsuUIFile, ezppUIFile);
|
await fs.promises.rename(oldOsuUIFile, ezppUIFile);
|
||||||
await fs.promises.rename(
|
await fs.promises.rename(
|
||||||
|
@ -413,5 +430,5 @@ module.exports = {
|
||||||
runOsuUpdater,
|
runOsuUpdater,
|
||||||
getEZPPLauncherUpdateFiles,
|
getEZPPLauncherUpdateFiles,
|
||||||
downloadEZPPLauncherUpdateFiles,
|
downloadEZPPLauncherUpdateFiles,
|
||||||
gamemodes
|
gamemodes,
|
||||||
};
|
};
|
||||||
|
|
|
@ -35,7 +35,9 @@ module.exports = {
|
||||||
richPresence = new DiscordRPC.AutoClient({ transport: "ipc" });
|
richPresence = new DiscordRPC.AutoClient({ transport: "ipc" });
|
||||||
richPresence.endlessLogin({ clientId });
|
richPresence.endlessLogin({ clientId });
|
||||||
richPresence.once("ready", () => {
|
richPresence.once("ready", () => {
|
||||||
console.log("connected presence with user " + richPresence.user.username);
|
console.log(
|
||||||
|
"connected presence with user " + richPresence.user.username,
|
||||||
|
);
|
||||||
richPresence.setActivity(currentStatus);
|
richPresence.setActivity(currentStatus);
|
||||||
intervalId = setInterval(() => {
|
intervalId = setInterval(() => {
|
||||||
richPresence.setActivity(currentStatus);
|
richPresence.setActivity(currentStatus);
|
||||||
|
|
178
main.js
178
main.js
|
@ -20,7 +20,6 @@ const {
|
||||||
runOsuWithDevServer,
|
runOsuWithDevServer,
|
||||||
replaceUIFiles,
|
replaceUIFiles,
|
||||||
findOsuInstallation,
|
findOsuInstallation,
|
||||||
updateOsuConfigHashes,
|
|
||||||
runOsuUpdater,
|
runOsuUpdater,
|
||||||
gamemodes,
|
gamemodes,
|
||||||
getEZPPLauncherUpdateFiles,
|
getEZPPLauncherUpdateFiles,
|
||||||
|
@ -38,6 +37,8 @@ const { updateAvailable, releasesUrl } = require("./electron/updateCheck");
|
||||||
const fkill = require("fkill");
|
const fkill = require("fkill");
|
||||||
const { checkImageExists } = require("./electron/imageUtil");
|
const { checkImageExists } = require("./electron/imageUtil");
|
||||||
const { isNet8Installed } = require("./electron/netUtils");
|
const { isNet8Installed } = require("./electron/netUtils");
|
||||||
|
const Logger = require("./electron/logging");
|
||||||
|
const { isWritable } = require("./electron/fileUtil");
|
||||||
|
|
||||||
// Keep a global reference of the window object, if you don't, the window will
|
// Keep a global reference of the window object, if you don't, the window will
|
||||||
// be closed automatically when the JavaScript object is garbage collected.
|
// be closed automatically when the JavaScript object is garbage collected.
|
||||||
|
@ -46,6 +47,13 @@ let osuCheckInterval;
|
||||||
let userOsuPath;
|
let userOsuPath;
|
||||||
let osuLoaded = false;
|
let osuLoaded = false;
|
||||||
let patch = false;
|
let patch = false;
|
||||||
|
let logger = new Logger(path.join(
|
||||||
|
process.platform == "win32"
|
||||||
|
? process.env["LOCALAPPDATA"]
|
||||||
|
: process.env["HOME"],
|
||||||
|
"EZPPLauncher",
|
||||||
|
"logs",
|
||||||
|
));
|
||||||
|
|
||||||
let currentUser = undefined;
|
let currentUser = undefined;
|
||||||
|
|
||||||
|
@ -66,10 +74,18 @@ function startOsuStatus() {
|
||||||
osuLoaded = true;
|
osuLoaded = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const currentUserInfo = await fetch(`https://api.ez-pp.farm/get_player_info?name=${currentUser.username}&scope=info`);
|
const currentUserInfo = await fetch(
|
||||||
|
`https://api.ez-pp.farm/get_player_info?name=${currentUser.username}&scope=info`,
|
||||||
|
);
|
||||||
const currentUserInfoJson = await currentUserInfo.json();
|
const currentUserInfoJson = await currentUserInfo.json();
|
||||||
if ("player" in currentUserInfoJson && currentUserInfoJson.player != null) {
|
if (
|
||||||
if ("info" in currentUserInfoJson.player && currentUserInfoJson.player.info != null) {
|
"player" in currentUserInfoJson &&
|
||||||
|
currentUserInfoJson.player != null
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
"info" in currentUserInfoJson.player &&
|
||||||
|
currentUserInfoJson.player.info != null
|
||||||
|
) {
|
||||||
const id = currentUserInfoJson.player.info.id;
|
const id = currentUserInfoJson.player.info.id;
|
||||||
const username = currentUserInfoJson.player.info.name;
|
const username = currentUserInfoJson.player.info.name;
|
||||||
richPresence.updateUser({
|
richPresence.updateUser({
|
||||||
|
@ -80,7 +96,6 @@ function startOsuStatus() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -112,7 +127,8 @@ function startOsuStatus() {
|
||||||
const currentModeString = gamemodes[currentMode];
|
const currentModeString = gamemodes[currentMode];
|
||||||
|
|
||||||
const currentInfoRequest = await fetch(
|
const currentInfoRequest = await fetch(
|
||||||
"https://api.ez-pp.farm/get_player_info?name=" + currentUser.username + "&scope=all",
|
"https://api.ez-pp.farm/get_player_info?name=" + currentUser.username +
|
||||||
|
"&scope=all",
|
||||||
);
|
);
|
||||||
const currentInfo = await currentInfoRequest.json();
|
const currentInfo = await currentInfoRequest.json();
|
||||||
let currentUsername = currentInfo.player.info.name;
|
let currentUsername = currentInfo.player.info.name;
|
||||||
|
@ -192,7 +208,7 @@ function startOsuStatus() {
|
||||||
richPresence.updateUser({
|
richPresence.updateUser({
|
||||||
username: currentUsername,
|
username: currentUsername,
|
||||||
id: currentId,
|
id: currentId,
|
||||||
})
|
});
|
||||||
|
|
||||||
richPresence.updateStatus({
|
richPresence.updateStatus({
|
||||||
details,
|
details,
|
||||||
|
@ -211,9 +227,19 @@ function stopOsuStatus() {
|
||||||
|
|
||||||
function registerIPCPipes() {
|
function registerIPCPipes() {
|
||||||
ipcMain.handle("ezpplauncher:login", async (e, args) => {
|
ipcMain.handle("ezpplauncher:login", async (e, args) => {
|
||||||
const hwid = getHwId();
|
let hwid = "";
|
||||||
|
try {
|
||||||
|
hwid = getHwId();
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(`Failed to get HWID.`, err);
|
||||||
|
return {
|
||||||
|
code: 500,
|
||||||
|
message: "Failed to get HWID.",
|
||||||
|
};
|
||||||
|
}
|
||||||
const timeout = new AbortController();
|
const timeout = new AbortController();
|
||||||
const timeoutId = setTimeout(() => timeout.abort(), 8000);
|
const timeoutId = setTimeout(() => timeout.abort(), 8000);
|
||||||
|
logger.log(`Logging in with user ${args.username}...`);
|
||||||
try {
|
try {
|
||||||
const fetchResult = await fetch("https://ez-pp.farm/login/check", {
|
const fetchResult = await fetch("https://ez-pp.farm/login/check", {
|
||||||
signal: timeout.signal,
|
signal: timeout.signal,
|
||||||
|
@ -238,14 +264,20 @@ function registerIPCPipes() {
|
||||||
}
|
}
|
||||||
currentUser = args;
|
currentUser = args;
|
||||||
config.remove("guest");
|
config.remove("guest");
|
||||||
}
|
logger.log(`Logged in as user ${args.username}!`);
|
||||||
|
} else logger.log(`Login failed for user ${args.username}.`);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
logger.log(
|
||||||
|
`Login failed for user ${username}.\nResponse:\n${await fetchResult
|
||||||
|
.text()}`,
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
code: 500,
|
code: 500,
|
||||||
message: "Something went wrong while logging you in.",
|
message: "Something went wrong while logging you in.",
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
logger.error("Error while logging in:", err);
|
||||||
return {
|
return {
|
||||||
code: 500,
|
code: 500,
|
||||||
message: "Something went wrong while logging you in.",
|
message: "Something went wrong while logging you in.",
|
||||||
|
@ -275,6 +307,7 @@ function registerIPCPipes() {
|
||||||
}
|
}
|
||||||
const timeout = new AbortController();
|
const timeout = new AbortController();
|
||||||
const timeoutId = setTimeout(() => timeout.abort(), 8000);
|
const timeoutId = setTimeout(() => timeout.abort(), 8000);
|
||||||
|
logger.log(`Logging in with user ${username}...`);
|
||||||
try {
|
try {
|
||||||
const fetchResult = await fetch("https://ez-pp.farm/login/check", {
|
const fetchResult = await fetch("https://ez-pp.farm/login/check", {
|
||||||
signal: timeout.signal,
|
signal: timeout.signal,
|
||||||
|
@ -297,16 +330,23 @@ function registerIPCPipes() {
|
||||||
username: username,
|
username: username,
|
||||||
password: password,
|
password: password,
|
||||||
};
|
};
|
||||||
}
|
logger.log(`Logged in as user ${username}!`);
|
||||||
|
} else logger.log(`Login failed for user ${username}.`);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
config.remove("password");
|
config.remove("password");
|
||||||
}
|
}
|
||||||
|
logger.log(
|
||||||
|
`Login failed for user ${username}.\nResponse:\n${await fetchResult
|
||||||
|
.text()}`,
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
code: 500,
|
code: 500,
|
||||||
message: "Something went wrong while logging you in.",
|
message: "Something went wrong while logging you in.",
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
logger.error("Error while logging in:", err);
|
||||||
return {
|
return {
|
||||||
code: 500,
|
code: 500,
|
||||||
message: "Something went wrong while logging you in.",
|
message: "Something went wrong while logging you in.",
|
||||||
|
@ -319,6 +359,7 @@ function registerIPCPipes() {
|
||||||
config.remove("password");
|
config.remove("password");
|
||||||
config.set("guest", "1");
|
config.set("guest", "1");
|
||||||
currentUser = undefined;
|
currentUser = undefined;
|
||||||
|
logger.log("Logged in as guest user.");
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle("ezpplauncher:logout", (e) => {
|
ipcMain.handle("ezpplauncher:logout", (e) => {
|
||||||
|
@ -326,6 +367,7 @@ function registerIPCPipes() {
|
||||||
config.remove("password");
|
config.remove("password");
|
||||||
config.remove("guest");
|
config.remove("guest");
|
||||||
currentUser = undefined;
|
currentUser = undefined;
|
||||||
|
logger.log("Loging out.");
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -342,6 +384,10 @@ function registerIPCPipes() {
|
||||||
else richPresence.connect();
|
else richPresence.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (key == "logging") {
|
||||||
|
logger.enabled = logging;
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof value == "boolean") {
|
if (typeof value == "boolean") {
|
||||||
config.set(key, value ? "true" : "false");
|
config.set(key, value ? "true" : "false");
|
||||||
} else {
|
} else {
|
||||||
|
@ -391,6 +437,18 @@ function registerIPCPipes() {
|
||||||
});
|
});
|
||||||
|
|
||||||
ipcMain.handle("ezpplauncher:launch", async (e) => {
|
ipcMain.handle("ezpplauncher:launch", async (e) => {
|
||||||
|
try {
|
||||||
|
const osuWindowTitle = windowName.getWindowText("osu!.exe");
|
||||||
|
if (osuWindowTitle.length > 0) {
|
||||||
|
mainWindow.webContents.send("ezpplauncher:alert", {
|
||||||
|
type: "error",
|
||||||
|
message: "osu! is running, please exit.",
|
||||||
|
});
|
||||||
|
mainWindow.webContents.send("ezpplauncher:launchabort");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.log("Preparing launch...");
|
||||||
const configPatch = config.get("patch");
|
const configPatch = config.get("patch");
|
||||||
patch = configPatch != undefined ? configPatch == "true" : true;
|
patch = configPatch != undefined ? configPatch == "true" : true;
|
||||||
mainWindow.webContents.send("ezpplauncher:launchstatus", {
|
mainWindow.webContents.send("ezpplauncher:launchstatus", {
|
||||||
|
@ -406,6 +464,7 @@ function registerIPCPipes() {
|
||||||
message: "osu! path not set!",
|
message: "osu! path not set!",
|
||||||
});
|
});
|
||||||
mainWindow.webContents.send("ezpplauncher:open-settings");
|
mainWindow.webContents.send("ezpplauncher:open-settings");
|
||||||
|
logger.log("osu! path is not set.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!(await isValidOsuFolder(osuPath))) {
|
if (!(await isValidOsuFolder(osuPath))) {
|
||||||
|
@ -414,6 +473,7 @@ function registerIPCPipes() {
|
||||||
type: "error",
|
type: "error",
|
||||||
message: "invalid osu! path!",
|
message: "invalid osu! path!",
|
||||||
});
|
});
|
||||||
|
logger.log("osu! path is invalid.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (patch) {
|
if (patch) {
|
||||||
|
@ -424,21 +484,31 @@ function registerIPCPipes() {
|
||||||
message: ".NET 8 is not installed.",
|
message: ".NET 8 is not installed.",
|
||||||
});
|
});
|
||||||
//open .net 8 download in browser
|
//open .net 8 download in browser
|
||||||
shell.openExternal('https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-8.0.4-windows-x64-installer');
|
shell.openExternal(
|
||||||
|
"https://dotnet.microsoft.com/en-us/download/dotnet/thank-you/runtime-desktop-8.0.4-windows-x64-installer",
|
||||||
|
);
|
||||||
|
logger.log(".NET 8 is not installed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mainWindow.webContents.send("ezpplauncher:launchstatus", {
|
mainWindow.webContents.send("ezpplauncher:launchstatus", {
|
||||||
status: "Checking for osu! updates...",
|
status: "Checking for osu! updates...",
|
||||||
});
|
});
|
||||||
await new Promise((res) => setTimeout(res, 1000));
|
await new Promise((res) => setTimeout(res, 1000));
|
||||||
const releaseStream = await getGlobalConfig(osuPath).get("_ReleaseStream");
|
const releaseStream = await getGlobalConfig(osuPath).get(
|
||||||
|
"_ReleaseStream",
|
||||||
|
);
|
||||||
const latestFiles = await getUpdateFiles(releaseStream);
|
const latestFiles = await getUpdateFiles(releaseStream);
|
||||||
const updateFiles = await getFilesThatNeedUpdate(osuPath, latestFiles);
|
const updateFiles = await getFilesThatNeedUpdate(osuPath, latestFiles);
|
||||||
if (updateFiles.length > 0) {
|
if (updateFiles.length > 0) {
|
||||||
|
logger.log("osu! updates found.");
|
||||||
const updateDownloader = downloadUpdateFiles(osuPath, updateFiles);
|
const updateDownloader = downloadUpdateFiles(osuPath, updateFiles);
|
||||||
let errored = false;
|
let errored = false;
|
||||||
updateDownloader.eventEmitter.on("error", (data) => {
|
updateDownloader.eventEmitter.on("error", (data) => {
|
||||||
const filename = data.fileName;
|
const filename = data.fileName;
|
||||||
|
logger.error(
|
||||||
|
`Failed to download/replace ${filename}!`,
|
||||||
|
data.error,
|
||||||
|
);
|
||||||
errored = true;
|
errored = true;
|
||||||
mainWindow.webContents.send("ezpplauncher:alert", {
|
mainWindow.webContents.send("ezpplauncher:alert", {
|
||||||
type: "error",
|
type: "error",
|
||||||
|
@ -447,11 +517,15 @@ function registerIPCPipes() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
updateDownloader.eventEmitter.on("data", (data) => {
|
updateDownloader.eventEmitter.on("data", (data) => {
|
||||||
|
if (data.progress >= 100) {
|
||||||
|
logger.log(`Downloaded ${data.fileName} successfully.`);
|
||||||
|
}
|
||||||
mainWindow.webContents.send("ezpplauncher:launchprogress", {
|
mainWindow.webContents.send("ezpplauncher:launchprogress", {
|
||||||
progress: Math.ceil(data.progress),
|
progress: Math.ceil(data.progress),
|
||||||
});
|
});
|
||||||
mainWindow.webContents.send("ezpplauncher:launchstatus", {
|
mainWindow.webContents.send("ezpplauncher:launchstatus", {
|
||||||
status: `Downloading ${data.fileName}(${formatBytes(data.loaded)}/${formatBytes(data.total)
|
status: `Downloading ${data.fileName}(${formatBytes(data.loaded)}/${
|
||||||
|
formatBytes(data.total)
|
||||||
})...`,
|
})...`,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -481,10 +555,15 @@ function registerIPCPipes() {
|
||||||
await new Promise((res) => setTimeout(res, 1000));
|
await new Promise((res) => setTimeout(res, 1000));
|
||||||
const patchFiles = await getEZPPLauncherUpdateFiles(osuPath);
|
const patchFiles = await getEZPPLauncherUpdateFiles(osuPath);
|
||||||
if (patchFiles.length > 0) {
|
if (patchFiles.length > 0) {
|
||||||
const patcherDownloader = await downloadEZPPLauncherUpdateFiles(osuPath, patchFiles);
|
logger.log("EZPPLauncher updates found.");
|
||||||
|
const patcherDownloader = await downloadEZPPLauncherUpdateFiles(
|
||||||
|
osuPath,
|
||||||
|
patchFiles,
|
||||||
|
);
|
||||||
let errored = false;
|
let errored = false;
|
||||||
patcherDownloader.eventEmitter.on("error", (data) => {
|
patcherDownloader.eventEmitter.on("error", (data) => {
|
||||||
const filename = data.fileName;
|
const filename = data.fileName;
|
||||||
|
logger.error(`Failed to download/replace ${filename}!`, data.error);
|
||||||
errored = true;
|
errored = true;
|
||||||
mainWindow.webContents.send("ezpplauncher:alert", {
|
mainWindow.webContents.send("ezpplauncher:alert", {
|
||||||
type: "error",
|
type: "error",
|
||||||
|
@ -493,12 +572,16 @@ function registerIPCPipes() {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
patcherDownloader.eventEmitter.on("data", (data) => {
|
patcherDownloader.eventEmitter.on("data", (data) => {
|
||||||
|
if (data.progress >= 100) {
|
||||||
|
logger.log(`Downloaded ${data.fileName} successfully.`);
|
||||||
|
}
|
||||||
mainWindow.webContents.send("ezpplauncher:launchprogress", {
|
mainWindow.webContents.send("ezpplauncher:launchprogress", {
|
||||||
progress: Math.ceil(data.progress),
|
progress: Math.ceil(data.progress),
|
||||||
});
|
});
|
||||||
mainWindow.webContents.send("ezpplauncher:launchstatus", {
|
mainWindow.webContents.send("ezpplauncher:launchstatus", {
|
||||||
status: `Downloading ${data.fileName}(${formatBytes(data.loaded)}/${formatBytes(data.total)
|
status: `Downloading ${data.fileName}(${
|
||||||
})...`,
|
formatBytes(data.loaded)
|
||||||
|
}/${formatBytes(data.total)})...`,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
await patcherDownloader.startDownload();
|
await patcherDownloader.startDownload();
|
||||||
|
@ -551,8 +634,20 @@ function registerIPCPipes() {
|
||||||
status: "Preparing launch...",
|
status: "Preparing launch...",
|
||||||
});
|
});
|
||||||
|
|
||||||
await updateOsuConfigHashes(osuPath);
|
/* await updateOsuConfigHashes(osuPath); */
|
||||||
|
logger.log("Replacing UI files...");
|
||||||
|
try {
|
||||||
await replaceUIFiles(osuPath, false);
|
await replaceUIFiles(osuPath, false);
|
||||||
|
logger.log("UI files replaced successfully.");
|
||||||
|
} catch (err) {
|
||||||
|
logger.error("Failed to replace UI files:", err);
|
||||||
|
mainWindow.webContents.send("ezpplauncher:alert", {
|
||||||
|
type: "error",
|
||||||
|
message: "Failed to replace UI files. try restarting EZPPLauncher.",
|
||||||
|
});
|
||||||
|
mainWindow.webContents.send("ezpplauncher:launchabort");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const forceUpdateFiles = [
|
const forceUpdateFiles = [
|
||||||
".require_update",
|
".require_update",
|
||||||
|
@ -570,7 +665,9 @@ function registerIPCPipes() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch { }
|
} catch (err) {
|
||||||
|
logger.error("Failed to remove force update files:", err);
|
||||||
|
}
|
||||||
|
|
||||||
const userConfig = getUserConfig(osuPath);
|
const userConfig = getUserConfig(osuPath);
|
||||||
if (richPresence.hasPresence) {
|
if (richPresence.hasPresence) {
|
||||||
|
@ -589,13 +686,18 @@ function registerIPCPipes() {
|
||||||
status: "Launching osu!...",
|
status: "Launching osu!...",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await new Promise((res) => setTimeout(res, 1000));
|
||||||
|
|
||||||
|
logger.log("Launching osu!...");
|
||||||
|
|
||||||
const onExitHook = () => {
|
const onExitHook = () => {
|
||||||
|
logger.log("osu! has exited.");
|
||||||
mainWindow.show();
|
mainWindow.show();
|
||||||
mainWindow.focus();
|
mainWindow.focus();
|
||||||
stopOsuStatus();
|
stopOsuStatus();
|
||||||
richPresence.updateUser({
|
richPresence.updateUser({
|
||||||
username: " ",
|
username: " ",
|
||||||
id: undefined
|
id: undefined,
|
||||||
});
|
});
|
||||||
richPresence.updateStatus({
|
richPresence.updateStatus({
|
||||||
state: "Idle in Launcher...",
|
state: "Idle in Launcher...",
|
||||||
|
@ -605,24 +707,37 @@ function registerIPCPipes() {
|
||||||
mainWindow.webContents.send("ezpplauncher:launchstatus", {
|
mainWindow.webContents.send("ezpplauncher:launchstatus", {
|
||||||
status: "Waiting for cleanup...",
|
status: "Waiting for cleanup...",
|
||||||
});
|
});
|
||||||
|
const timeStart = performance.now();
|
||||||
|
logger.log("Waiting for cleanup...");
|
||||||
|
|
||||||
setTimeout(async () => {
|
const cleanup = setInterval(async () => {
|
||||||
|
const osuUIFile = path.join(osuPath, "osu!ui.dll");
|
||||||
|
const osuGameplayFile = path.join(osuPath, "osu!gameplay.dll");
|
||||||
|
if (isWritable(osuUIFile) && isWritable(osuGameplayFile)) {
|
||||||
|
logger.log(
|
||||||
|
`Cleanup complete, took ${
|
||||||
|
((performance.now() - timeStart) / 1000).toFixed(3)
|
||||||
|
} seconds.`,
|
||||||
|
);
|
||||||
|
clearInterval(cleanup);
|
||||||
await replaceUIFiles(osuPath, true);
|
await replaceUIFiles(osuPath, true);
|
||||||
mainWindow.webContents.send("ezpplauncher:launchabort");
|
mainWindow.webContents.send("ezpplauncher:launchabort");
|
||||||
osuLoaded = false;
|
osuLoaded = false;
|
||||||
}, 5000);
|
}
|
||||||
|
}, 1000);
|
||||||
};
|
};
|
||||||
runOsuWithDevServer(osuPath, "ez-pp.farm", onExitHook);
|
runOsuWithDevServer(osuPath, "ez-pp.farm", onExitHook);
|
||||||
mainWindow.hide();
|
mainWindow.hide();
|
||||||
startOsuStatus();
|
startOsuStatus();
|
||||||
|
|
||||||
/* mainWindow.webContents.send("ezpplauncher:launchprogress", {
|
|
||||||
progress: 0,
|
|
||||||
});
|
|
||||||
mainWindow.webContents.send("ezpplauncher:launchprogress", {
|
|
||||||
progress: 100,
|
|
||||||
}); */
|
|
||||||
return true;
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
logger.error("Failed to launch", err);
|
||||||
|
mainWindow.webContents.send("ezpplauncher:alert", {
|
||||||
|
type: "error",
|
||||||
|
message: "Failed to launch osu!. Please try again.",
|
||||||
|
});
|
||||||
|
mainWindow.webContents.send("ezpplauncher:launchabort");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -678,6 +793,13 @@ function createWindow() {
|
||||||
richPresence.connect();
|
richPresence.connect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.init();
|
||||||
|
|
||||||
|
const loggingEnabled = config.get("logging");
|
||||||
|
if (loggingEnabled && loggingEnabled == "true") {
|
||||||
|
logger.enabled = true;
|
||||||
|
}
|
||||||
// Uncomment the following line of code when app is ready to be packaged.
|
// Uncomment the following line of code when app is ready to be packaged.
|
||||||
// loadURL(mainWindow);
|
// loadURL(mainWindow);
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "ezpplauncher-next",
|
"name": "ezpplauncher-next",
|
||||||
"version": "2.1.4",
|
"version": "2.1.5",
|
||||||
"description": "EZPPLauncher rewritten with Svelte.",
|
"description": "EZPPLauncher rewritten with Svelte.",
|
||||||
"private": false,
|
"private": false,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Button, ButtonGroup, Input, Toggle } from "flowbite-svelte";
|
import { Button, ButtonGroup, Input, Toggle } from "flowbite-svelte";
|
||||||
import { FileSearchSolid, FolderSolid } from "flowbite-svelte-icons";
|
import { FileSearchSolid, FolderSolid } from "flowbite-svelte-icons";
|
||||||
import { patch, presence } from "./../storage/localStore";
|
import { patch, presence, logging } from "./../storage/localStore";
|
||||||
|
|
||||||
let folderPath: string = "";
|
let folderPath: string = "";
|
||||||
|
|
||||||
|
@ -12,8 +12,10 @@
|
||||||
const settingPresence = settings.find(
|
const settingPresence = settings.find(
|
||||||
(setting) => setting.key == "presence"
|
(setting) => setting.key == "presence"
|
||||||
);
|
);
|
||||||
|
const settingLogging = settings.find((setting) => setting.key == "logging");
|
||||||
patch.set(settingPatch ? settingPatch.val == "true" : true);
|
patch.set(settingPatch ? settingPatch.val == "true" : true);
|
||||||
presence.set(settingPresence ? settingPresence.val == "true" : true);
|
presence.set(settingPresence ? settingPresence.val == "true" : true);
|
||||||
|
logging.set(settingLogging ? settingLogging.val == "true" : false);
|
||||||
folderPath = osuPath ? osuPath.val : "";
|
folderPath = osuPath ? osuPath.val : "";
|
||||||
});
|
});
|
||||||
window.dispatchEvent(new CustomEvent("settings-get"));
|
window.dispatchEvent(new CustomEvent("settings-get"));
|
||||||
|
@ -39,19 +41,18 @@
|
||||||
new CustomEvent("setting-update", { detail: { presence: $presence } })
|
new CustomEvent("setting-update", { detail: { presence: $presence } })
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toggleLogging = () => {
|
||||||
|
logging.set(!$logging);
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent("setting-update", { detail: { logging: $logging } })
|
||||||
|
);
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main
|
<main
|
||||||
class="h-[265px] flex flex-col justify-start p-3 animate-fadeIn opacity-0"
|
class="h-[265px] flex flex-col justify-start p-3 animate-fadeIn opacity-0"
|
||||||
>
|
>
|
||||||
<div class="flex flex-col gap-2 p-3">
|
|
||||||
<Toggle class="w-fit" bind:checked={$presence} on:click={togglePresence}
|
|
||||||
>Discord Presence</Toggle
|
|
||||||
>
|
|
||||||
<Toggle class="w-fit" bind:checked={$patch} on:click={togglePatching}
|
|
||||||
>Patching</Toggle
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div
|
<div
|
||||||
class="container flex flex-col items-center justify-center gap-5 rounded-lg p-3"
|
class="container flex flex-col items-center justify-center gap-5 rounded-lg p-3"
|
||||||
>
|
>
|
||||||
|
@ -77,4 +78,15 @@
|
||||||
</Button>
|
</Button>
|
||||||
</ButtonGroup>
|
</ButtonGroup>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex flex-col gap-2 p-3">
|
||||||
|
<Toggle class="w-fit" bind:checked={$presence} on:click={togglePresence}
|
||||||
|
>Discord Presence</Toggle
|
||||||
|
>
|
||||||
|
<Toggle class="w-fit" bind:checked={$patch} on:click={togglePatching}
|
||||||
|
>Patching</Toggle
|
||||||
|
>
|
||||||
|
<Toggle class="w-fit" bind:checked={$logging} on:click={toggleLogging}
|
||||||
|
>Debug Logging</Toggle
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
|
@ -7,8 +7,11 @@ export const updateAvailable = writable(false);
|
||||||
export const launching = writable(false);
|
export const launching = writable(false);
|
||||||
export const launchStatus = writable("Waiting...");
|
export const launchStatus = writable("Waiting...");
|
||||||
export const launchPercentage = writable(-1);
|
export const launchPercentage = writable(-1);
|
||||||
|
|
||||||
|
export const currentUser: Writable<undefined | User> = writable(undefined);
|
||||||
|
export const currentPage = writable(Page.Login);
|
||||||
|
|
||||||
export const osuPath: Writable<undefined | string> = writable(undefined);
|
export const osuPath: Writable<undefined | string> = writable(undefined);
|
||||||
export const patch = writable(true);
|
export const patch = writable(true);
|
||||||
export const presence = writable(true);
|
export const presence = writable(true);
|
||||||
export const currentUser: Writable<undefined | User> = writable(undefined);
|
export const logging = writable(false);
|
||||||
export const currentPage = writable(Page.Login);
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user