diff --git a/main.js b/main.js index 83f37de..e6adb93 100644 --- a/main.js +++ b/main.js @@ -1,144 +1,141 @@ -const { app, BrowserWindow , ipcMain, dialog, shell} = require('electron/main'); -const path = require('node:path'); -const Store = require('electron-store').default; -const fs = require('fs/promises'); -const { createWriteStream } = require('fs'); -const { pipeline } = require('stream/promises'); -const extract = require('extract-zip'); -const Nexus = require('@nexusmods/nexus-api').default; +import { app, BrowserWindow, ipcMain, dialog, shell } from "electron"; +import path from "path"; +import { fileURLToPath } from "url"; +import Store from "electron-store"; +import fs from "fs/promises"; +import { createWriteStream } from "fs"; +import { pipeline } from "stream/promises"; +import extract from "extract-zip"; +import NexusModule from "@nexusmods/nexus-api"; +const Nexus = NexusModule.default; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); const store = new Store(); -const userSavePath = app.getPath('userData') -const dataPath = `${userSavePath}\\config.json` -let silksongPath = store.get('silksong-path') +const userSavePath = app.getPath("userData"); +const dataPath = `${userSavePath}\\config.json`; +let silksongPath = store.get("silksong-path"); -let nexusAPI = store.get('nexus-api') -let nexus = undefined -createNexus() +let nexusAPI = store.get("nexus-api"); +let nexus = undefined; +createNexus(); -let bepinexFolderPath = `${silksongPath}/BepInEx` -let bepinexBackupPath = `${silksongPath}/BepInEx-Backup` -const bepinexFiles = [ - ".doorstop_version", - "changelog.txt", - "doorstop_config.ini", - "winhttp.dll" - ] +let bepinexFolderPath = `${silksongPath}/BepInEx`; +let bepinexBackupPath = `${silksongPath}/BepInEx-Backup`; +const bepinexFiles = [".doorstop_version", "changelog.txt", "doorstop_config.ini", "winhttp.dll"]; -let bepinexVersion -let bepinexBackupVersion -const bepinexStore = new Store({cwd: 'bepinex-version'}); +let bepinexVersion; +let bepinexBackupVersion; +const bepinexStore = new Store({ cwd: "bepinex-version" }); -let mainWindow -let htmlFile +let mainWindow; +let htmlFile; async function createWindow() { mainWindow = new BrowserWindow({ width: 1280, height: 720, webPreferences: { - preload: path.join(__dirname, 'preload.js') - } - }) + preload: path.join(__dirname, "preload.js"), + }, + }); - if(await fileExists(dataPath)) { - htmlFile = "index.html" - } - else { - htmlFile = "welcome.html" + if (await fileExists(dataPath)) { + htmlFile = "index.html"; + } else { + htmlFile = "welcome.html"; } - mainWindow.loadFile(`renderer/${htmlFile}`) + mainWindow.loadFile(`renderer/${htmlFile}`); } app.whenReady().then(() => { - createWindow() + createWindow(); - app.on('activate', () => { + app.on("activate", () => { if (BrowserWindow.getAllWindows().length === 0) { - createWindow() + createWindow(); } - }) -}) + }); +}); -app.on('window-all-closed', () => { - if (process.platform !== 'darwin') { - app.quit() +app.on("window-all-closed", () => { + if (process.platform !== "darwin") { + app.quit(); } -}) +}); +////////////////////////////////////////////////////// ///////////////// SAVING AND LOADING ///////////////// -ipcMain.handle('save-path', (event, path) => { - saveSilksongPath(path) +ipcMain.handle("save-path", (event, path) => { + saveSilksongPath(path); }); function saveSilksongPath(path) { silksongPath = path; - bepinexFolderPath = `${silksongPath}/BepInEx` - bepinexBackupPath = `${silksongPath}/BepInEx-Backup` - store.set('silksong-path', silksongPath); + bepinexFolderPath = `${silksongPath}/BepInEx`; + bepinexBackupPath = `${silksongPath}/BepInEx-Backup`; + store.set("silksong-path", silksongPath); } -ipcMain.handle('load-path', () => { - silksongPath = store.get('silksong-path'); - if (silksongPath == undefined) { +ipcMain.handle("load-path", () => { + silksongPath = store.get("silksong-path"); + if (silksongPath == undefined) { return ""; } return silksongPath; }); - function saveBepinexVersion(version) { bepinexVersion = version; if (bepinexVersion == undefined) { - bepinexStore.delete('bepinex-version'); + bepinexStore.delete("bepinex-version"); return; } - bepinexStore.set('bepinex-version', version); -}; + bepinexStore.set("bepinex-version", version); +} -ipcMain.handle('load-bepinex-version', () => { - bepinexVersion = bepinexStore.get('bepinex-version'); +ipcMain.handle("load-bepinex-version", () => { + bepinexVersion = bepinexStore.get("bepinex-version"); return bepinexVersion; }); - function saveBepinexBackupVersion(version) { bepinexBackupVersion = version; if (bepinexBackupVersion == undefined) { - bepinexStore.delete('bepinex-backup-version'); + bepinexStore.delete("bepinex-backup-version"); return; } - bepinexStore.set('bepinex-backup-version', version); -}; + bepinexStore.set("bepinex-backup-version", version); +} -ipcMain.handle('load-bepinex-backup-version', () => { - bepinexBackupVersion = bepinexStore.get('bepinex-backup-version'); +ipcMain.handle("load-bepinex-backup-version", () => { + bepinexBackupVersion = bepinexStore.get("bepinex-backup-version"); return bepinexBackupVersion; }); - -ipcMain.handle('save-nexus-api', (event, api) => { + +ipcMain.handle("save-nexus-api", (event, api) => { nexusAPI = api; - createNexus() - store.set('nexus-api', nexusAPI); + createNexus(); + store.set("nexus-api", nexusAPI); }); -ipcMain.handle('load-nexus-api', () => { - nexusAPI = store.get('nexus-api'); - if (nexusAPI == undefined) { +ipcMain.handle("load-nexus-api", () => { + nexusAPI = store.get("nexus-api"); + if (nexusAPI == undefined) { return ""; } return nexusAPI; }); - -ipcMain.handle('save-theme', (event, theme, lacePinState) => { - store.set('theme.theme', theme); - store.set('theme.lacePinState', lacePinState); +ipcMain.handle("save-theme", (event, theme, lacePinState) => { + store.set("theme.theme", theme); + store.set("theme.lacePinState", lacePinState); }); -ipcMain.handle('load-theme', () => { - theme = [store.get('theme.theme'), store.get('theme.lacePinState')]; - if (theme[0] == undefined) { +ipcMain.handle("load-theme", () => { + const theme = [store.get("theme.theme"), store.get("theme.lacePinState")]; + if (theme[0] == undefined) { return ["Silksong", false]; } return theme; @@ -156,45 +153,43 @@ async function fileExists(filePath) { } } -ipcMain.handle('delete-data', async () => { +ipcMain.handle("delete-data", async () => { if (await fileExists(dataPath)) { - await fs.unlink(dataPath) + await fs.unlink(dataPath); } }); -ipcMain.handle('export-data', async () => { - if (!await fileExists(dataPath)) { - return +ipcMain.handle("export-data", async () => { + if (!(await fileExists(dataPath))) { + return; } const { canceled, filePath } = await dialog.showSaveDialog({ - title: 'Export Data', - defaultPath: 'config.json', - filters: [ - { name: 'JSON', extensions: ['json'] } - ] - }) + title: "Export Data", + defaultPath: "config.json", + filters: [{ name: "JSON", extensions: ["json"] }], + }); - if (canceled || !filePath) return + if (canceled || !filePath) return; - await fs.copyFile(dataPath, filePath) -}) + await fs.copyFile(dataPath, filePath); +}); -ipcMain.handle('import-data', async () => { +ipcMain.handle("import-data", async () => { const { canceled, filePaths } = await dialog.showOpenDialog({ - title: 'Import Data', - properties: ['openFile'], - filters: [{ name: 'JSON', extensions: ['json'] }] - }) + title: "Import Data", + properties: ["openFile"], + filters: [{ name: "JSON", extensions: ["json"] }], + }); - if (canceled || !filePaths) return false + if (canceled || !filePaths) return false; - if(await fileExists(dataPath)) { - await fs.unlink(dataPath) + if (await fileExists(dataPath)) { + await fs.unlink(dataPath); } - await fs.copyFile(filePaths[0], dataPath,fs.constants.COPYFILE_EXCL) - return true -}) + await fs.copyFile(filePaths[0], dataPath, fs.constants.COPYFILE_EXCL); + return true; +}); ////////////////////////////////////////////////////// ////////////////////// BEPINEX /////////////////////// @@ -202,157 +197,151 @@ ipcMain.handle('import-data', async () => { async function installBepinex() { if (await fileExists(bepinexBackupPath)) { if (await fileExists(`${bepinexBackupPath}/BepInEx`)) { - await fs.cp(`${bepinexBackupPath}/BepInEx`, bepinexFolderPath, { recursive: true }) + await fs.cp(`${bepinexBackupPath}/BepInEx`, bepinexFolderPath, { + recursive: true, + }); } for (const file of bepinexFiles) { - const filePath = `${silksongPath}/${file}` + const filePath = `${silksongPath}/${file}`; if (await fileExists(`${bepinexBackupPath}/${file}`)) { - await fs.copyFile(`${bepinexBackupPath}/${file}`, filePath) + await fs.copyFile(`${bepinexBackupPath}/${file}`, filePath); } } - await fs.rm(bepinexBackupPath, { recursive: true }) + await fs.rm(bepinexBackupPath, { recursive: true }); - bepinexBackupVersion = bepinexStore.get('bepinex-backup-version') - saveBepinexVersion(bepinexBackupVersion) - saveBepinexBackupVersion(undefined) - } - else { - const GITHUB_URL = "https://api.github.com/repos/bepinex/bepinex/releases/latest" + bepinexBackupVersion = bepinexStore.get("bepinex-backup-version"); + saveBepinexVersion(bepinexBackupVersion); + saveBepinexBackupVersion(undefined); + } else { + const GITHUB_URL = "https://api.github.com/repos/bepinex/bepinex/releases/latest"; const res = await fetch(GITHUB_URL, { headers: { "User-Agent": "SilkFlyLauncher/1.0.0", - "Accept": "application/vnd.github+json", - } - }) + Accept: "application/vnd.github+json", + }, + }); if (!res.ok) { - throw new Error(`GitHub API error: ${res.status}`) + throw new Error(`GitHub API error: ${res.status}`); } const release = await res.json(); - const asset = release.assets.find( - a => a.name.endsWith(".zip") && a.name.toLowerCase().includes("win_x64") - ); + const asset = release.assets.find((a) => a.name.endsWith(".zip") && a.name.toLowerCase().includes("win_x64")); - const download = await fetch(asset.browser_download_url) + const download = await fetch(asset.browser_download_url); if (!download.ok) { throw new Error("Download error"); } - const filePath = `${userSavePath}\\bepinex.zip` + const filePath = `${userSavePath}\\bepinex.zip`; - await pipeline( - download.body, - createWriteStream(filePath) - ) + await pipeline(download.body, createWriteStream(filePath)); - await extract(filePath, { dir: silksongPath}) - await fs.unlink(filePath) + await extract(filePath, { dir: silksongPath }); + await fs.unlink(filePath); - saveBepinexVersion(release.tag_name) + saveBepinexVersion(release.tag_name); } } -ipcMain.handle('install-bepinex', async () => { - await installBepinex() -}) +ipcMain.handle("install-bepinex", async () => { + await installBepinex(); +}); async function uninstallBepinex() { if (await fileExists(bepinexFolderPath)) { - await fs.rm(bepinexFolderPath, { recursive: true }) + await fs.rm(bepinexFolderPath, { recursive: true }); } for (const file of bepinexFiles) { - const filePath = `${silksongPath}/${file}` + const filePath = `${silksongPath}/${file}`; if (await fileExists(filePath)) { - await fs.unlink(filePath) + await fs.unlink(filePath); } } - saveBepinexVersion(undefined) + saveBepinexVersion(undefined); } -ipcMain.handle('uninstall-bepinex', async () => { - await uninstallBepinex() -}) +ipcMain.handle("uninstall-bepinex", async () => { + await uninstallBepinex(); +}); async function backupBepinex() { - if (await fileExists(bepinexBackupPath) == false) { - await fs.mkdir(bepinexBackupPath) + if ((await fileExists(bepinexBackupPath)) == false) { + await fs.mkdir(bepinexBackupPath); } if (await fileExists(bepinexFolderPath)) { - await fs.cp(bepinexFolderPath, `${bepinexBackupPath}/BepInEx`, { recursive: true }) + await fs.cp(bepinexFolderPath, `${bepinexBackupPath}/BepInEx`, { + recursive: true, + }); } for (const file of bepinexFiles) { - const filePath = `${silksongPath}/${file}` + const filePath = `${silksongPath}/${file}`; if (await fileExists(filePath)) { - await fs.copyFile(filePath, `${bepinexBackupPath}/${file}`) + await fs.copyFile(filePath, `${bepinexBackupPath}/${file}`); } } - saveBepinexBackupVersion(bepinexVersion) - await uninstallBepinex() + saveBepinexBackupVersion(bepinexVersion); + await uninstallBepinex(); } -ipcMain.handle('backup-bepinex', async () => { - await backupBepinex() -}) +ipcMain.handle("backup-bepinex", async () => { + await backupBepinex(); +}); -ipcMain.handle('delete-bepinex-backup', async () => { +ipcMain.handle("delete-bepinex-backup", async () => { if (await fileExists(bepinexBackupPath)) { - await fs.rm(bepinexBackupPath, { recursive: true }) - saveBepinexBackupVersion(undefined) + await fs.rm(bepinexBackupPath, { recursive: true }); + saveBepinexBackupVersion(undefined); } -}) +}); ////////////////////////////////////////////////////// /////////////////////// NEXUS //////////////////////// async function createNexus() { if (nexusAPI == undefined) { - return + return; } try { - nexus = await Nexus.create( - nexusAPI, - 'silk-fly-launcher', - '1.0.0', - 'hollowknightsilksong' - ); + nexus = await Nexus.create(nexusAPI, "silk-fly-launcher", "1.0.0", "hollowknightsilksong"); } catch (error) { - nexus = undefined + console.log(error); + nexus = undefined; } } -ipcMain.handle('verify-nexus-api', async () => { - return await verifyNexusAPI() -}) +ipcMain.handle("verify-nexus-api", async () => { + return await verifyNexusAPI(); +}); async function verifyNexusAPI() { if (nexus == undefined) { - return false + return false; } if (await nexus.getValidationResult()) { - return true + return true; } } -ipcMain.handle('get-latest-mods', async () => { +ipcMain.handle("get-latest-mods", async () => { if (nexus == undefined) { - return + return; } - mods = await nexus.getLatestAdded() - return mods -}) + const mods = await nexus.getLatestAdded(); + return mods; +}); -ipcMain.handle('download-mod', async (event, link) => { +ipcMain.handle("download-mod", async (event, link) => { if (nexus == undefined) { - return + return; } const nexusWindow = new BrowserWindow({ @@ -362,46 +351,43 @@ ipcMain.handle('download-mod', async (event, link) => { parent: mainWindow, webPreferences: { nodeIntegration: false, - contextIsolation: true - } - }) + contextIsolation: true, + }, + }); - nexusWindow.loadURL(link) -}) + nexusWindow.loadURL(link); +}); ////////////////////////////////////////////////////// //////////////////// UNCATEGORIZE //////////////////// -ipcMain.handle('auto-detect-game-path', async () => { - const defaultsSilksongPaths = [ - ":/Program Files (x86)/Steam/steamapps/common/Hollow Knight Silksong", - ":/SteamLibrary/steamapps/common/Hollow Knight Silksong" - ] +ipcMain.handle("auto-detect-game-path", async () => { + const defaultsSilksongPaths = [":/Program Files (x86)/Steam/steamapps/common/Hollow Knight Silksong", ":/SteamLibrary/steamapps/common/Hollow Knight Silksong"]; for (const path of defaultsSilksongPaths) { - for (let i = 'A'.charCodeAt(0); i <= 'Z'.charCodeAt(0); i++) { - const fullPath = `${String.fromCharCode(i)}${path}` + for (let i = "A".charCodeAt(0); i <= "Z".charCodeAt(0); i++) { + const fullPath = `${String.fromCharCode(i)}${path}`; if (await fileExists(fullPath)) { - saveSilksongPath(fullPath) - return + saveSilksongPath(fullPath); + return; } } } -}) +}); -ipcMain.handle('load-main-page', () => { - htmlFile = "index.html" - mainWindow.loadFile(`renderer/${htmlFile}`) -}) +ipcMain.handle("load-main-page", () => { + htmlFile = "index.html"; + mainWindow.loadFile(`renderer/${htmlFile}`); +}); -ipcMain.handle('get-page', () => { - return htmlFile -}) +ipcMain.handle("get-page", () => { + return htmlFile; +}); -ipcMain.handle('open-link', async (event, link) => { - await shell.openExternal(link) -}) +ipcMain.handle("open-link", async (event, link) => { + await shell.openExternal(link); +}); -ipcMain.handle('open-window', async (event, file) => { +ipcMain.handle("open-window", async (event, file) => { const win = new BrowserWindow({ width: 600, height: 720, @@ -409,32 +395,30 @@ ipcMain.handle('open-window', async (event, file) => { parent: mainWindow, webPreferences: { nodeIntegration: false, - contextIsolation: true - } - }) + contextIsolation: true, + }, + }); - win.title = file - win.loadFile(file) -}) + win.title = file; + win.loadFile(file); +}); -ipcMain.handle('launch-game', async (event, mode) => { - const silksongExecutablePath = `${silksongPath}/Hollow Knight Silksong.exe` - if (mode === "modded"){ +ipcMain.handle("launch-game", async (event, mode) => { + const silksongExecutablePath = `${silksongPath}/Hollow Knight Silksong.exe`; + if (mode === "modded") { if (await fileExists(bepinexFolderPath)) { - await shell.openExternal(silksongExecutablePath) - } - else { - await installBepinex() - await shell.openExternal(silksongExecutablePath) + await shell.openExternal(silksongExecutablePath); + } else { + await installBepinex(); + await shell.openExternal(silksongExecutablePath); } } - if (mode === "vanilla"){ + if (mode === "vanilla") { if (await fileExists(bepinexFolderPath)) { - await backupBepinex() - await shell.openExternal(silksongExecutablePath) - } - else { - await shell.openExternal(silksongExecutablePath) + await backupBepinex(); + await shell.openExternal(silksongExecutablePath); + } else { + await shell.openExternal(silksongExecutablePath); } } -}) +}); diff --git a/package.json b/package.json index e5661ff..d4004f6 100644 --- a/package.json +++ b/package.json @@ -1,20 +1,21 @@ { - "name": "silkflylauncher", - "version": "1.0.0", - "description": "A launcher and manager for silksong bepinex mods written in javascript", - "main": "main.js", - "scripts": { - "start": "electron .", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "GabiZar", - "license": "SEE LICENSE IN LICENSE", - "devDependencies": { - "electron": "^39.2.7" - }, - "dependencies": { - "@nexusmods/nexus-api": "^1.1.5", - "electron-store": "^11.0.2", - "extract-zip": "^2.0.1" - } + "name": "silkflylauncher", + "version": "1.0.0", + "description": "A launcher and manager for silksong bepinex mods written in javascript", + "main": "main.js", + "type": "module", + "scripts": { + "start": "electron .", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "GabiZar", + "license": "GPL-3.0", + "devDependencies": { + "electron": "^39.2.7" + }, + "dependencies": { + "@nexusmods/nexus-api": "^1.1.5", + "electron-store": "^11.0.2", + "extract-zip": "^2.0.1" + } } diff --git a/preload.js b/preload.js index f5537e4..14873af 100644 --- a/preload.js +++ b/preload.js @@ -1,47 +1,47 @@ -const { contextBridge, ipcRenderer } = require('electron') +const { contextBridge, ipcRenderer } = require("electron"); -const VERSION = "1.0.0" +const VERSION = "1.0.0"; -contextBridge.exposeInMainWorld('versions', { +contextBridge.exposeInMainWorld("versions", { silkFlyLauncher: () => VERSION, node: () => process.versions.node, chromium: () => process.versions.chrome, - electron: () => process.versions.electron + electron: () => process.versions.electron, }); -contextBridge.exposeInMainWorld('files', { - delete: () => ipcRenderer.invoke('delete-data'), - export: () => ipcRenderer.invoke('export-data'), - import: () => ipcRenderer.invoke('import-data'), +contextBridge.exposeInMainWorld("files", { + delete: () => ipcRenderer.invoke("delete-data"), + export: () => ipcRenderer.invoke("export-data"), + import: () => ipcRenderer.invoke("import-data"), - autoDetectGamePath: () => ipcRenderer.invoke('auto-detect-game-path'), - saveSilksongPath: (path) => ipcRenderer.invoke('save-path', path), - loadSilksongPath: () => ipcRenderer.invoke('load-path'), - loadBepinexVersion: () => ipcRenderer.invoke('load-bepinex-version'), - loadBepinexBackupVersion: () => ipcRenderer.invoke('load-bepinex-backup-version'), - saveNexusAPI: (api) => ipcRenderer.invoke('save-nexus-api', api), - loadNexusAPI: () => ipcRenderer.invoke('load-nexus-api'), - saveTheme: (theme, lacePinState) => ipcRenderer.invoke('save-theme', theme, lacePinState), - loadTheme: () => ipcRenderer.invoke('load-theme') + autoDetectGamePath: () => ipcRenderer.invoke("auto-detect-game-path"), + saveSilksongPath: (path) => ipcRenderer.invoke("save-path", path), + loadSilksongPath: () => ipcRenderer.invoke("load-path"), + loadBepinexVersion: () => ipcRenderer.invoke("load-bepinex-version"), + loadBepinexBackupVersion: () => ipcRenderer.invoke("load-bepinex-backup-version"), + saveNexusAPI: (api) => ipcRenderer.invoke("save-nexus-api", api), + loadNexusAPI: () => ipcRenderer.invoke("load-nexus-api"), + saveTheme: (theme, lacePinState) => ipcRenderer.invoke("save-theme", theme, lacePinState), + loadTheme: () => ipcRenderer.invoke("load-theme"), }); -contextBridge.exposeInMainWorld('electronAPI', { - openExternalLink: (url) => ipcRenderer.invoke('open-link', url), - openWindow: (file) => ipcRenderer.invoke('open-window', file), - launchGame: (mode) => ipcRenderer.invoke('launch-game', mode), - loadMainPage: () => ipcRenderer.invoke('load-main-page'), - getPage: () => ipcRenderer.invoke('get-page') +contextBridge.exposeInMainWorld("electronAPI", { + openExternalLink: (url) => ipcRenderer.invoke("open-link", url), + openWindow: (file) => ipcRenderer.invoke("open-window", file), + launchGame: (mode) => ipcRenderer.invoke("launch-game", mode), + loadMainPage: () => ipcRenderer.invoke("load-main-page"), + getPage: () => ipcRenderer.invoke("get-page"), }); -contextBridge.exposeInMainWorld('bepinex', { - install: () => ipcRenderer.invoke('install-bepinex'), - uninstall: () => ipcRenderer.invoke('uninstall-bepinex'), - backup: () => ipcRenderer.invoke('backup-bepinex'), - deleteBackup: () => ipcRenderer.invoke('delete-bepinex-backup') -}) +contextBridge.exposeInMainWorld("bepinex", { + install: () => ipcRenderer.invoke("install-bepinex"), + uninstall: () => ipcRenderer.invoke("uninstall-bepinex"), + backup: () => ipcRenderer.invoke("backup-bepinex"), + deleteBackup: () => ipcRenderer.invoke("delete-bepinex-backup"), +}); -contextBridge.exposeInMainWorld('nexus', { - verifyAPI: () => ipcRenderer.invoke('verify-nexus-api'), - getLatestMods: () => ipcRenderer.invoke('get-latest-mods'), - download: (link) => ipcRenderer.invoke('download-mod', link) -}) \ No newline at end of file +contextBridge.exposeInMainWorld("nexus", { + verifyAPI: () => ipcRenderer.invoke("verify-nexus-api"), + getLatestMods: () => ipcRenderer.invoke("get-latest-mods"), + download: (link) => ipcRenderer.invoke("download-mod", link), +}); diff --git a/renderer/assets/github.svg b/renderer/assets/github.svg new file mode 100644 index 0000000..7e4ff60 --- /dev/null +++ b/renderer/assets/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/renderer/index.html b/renderer/index.html index 4b87242..8ff8e05 100644 --- a/renderer/index.html +++ b/renderer/index.html @@ -1,195 +1,197 @@ - + - - - Silk Fly Launcher - - - + + + Silk Fly Launcher + + + +
+ -
- - - - - + - -
-

Silk Fly Launcher

-
-
-
-
+ + + - - - - - - - - - + - - \ No newline at end of file + + + + + + + + + diff --git a/renderer/renderer.js b/renderer/renderer.js index 7cfe321..1b2c818 100644 --- a/renderer/renderer.js +++ b/renderer/renderer.js @@ -8,13 +8,13 @@ const onlineModsTemplate = document.getElementById("online-mods-template"); const settingsTemplate = document.getElementById("settings-template"); const modTemplate = document.getElementById("mod-template"); -let oldPage -let actualTheme = [] +let oldPage; +let actualTheme = []; ////////////////////////////////////////////////////// ///////////////// CONST FOR WELCOME ////////////////// -let actualPage = 0 +let actualPage = 0; const pageDiv = document.getElementById("page"); const buttonDiv = document.getElementById("button-div"); @@ -31,16 +31,15 @@ const tutorialTemplate = document.getElementById("tutorial-template"); ////////////////////////////////////////////////////// ////////////////////// STARTUP /////////////////////// -on_startup() +on_startup(); async function on_startup() { - if (await electronAPI.getPage() == "index.html") { - const theme = await files.loadTheme() - changeTheme(theme[0], theme[1]) - navigate("home") - } - else if (await electronAPI.getPage() == "welcome.html") { - welcomeNavigate() + if ((await electronAPI.getPage()) == "index.html") { + const theme = await files.loadTheme(); + changeTheme(theme[0], theme[1]); + navigate("home"); + } else if ((await electronAPI.getPage()) == "welcome.html") { + welcomeNavigate(); } } @@ -49,223 +48,220 @@ async function on_startup() { async function navigate(page) { if (oldPage == page) { - return + return; } - oldPage = page + oldPage = page; - view.replaceChildren() + view.replaceChildren(); switch (page) { case "home": title.innerText = "Silk Fly Launcher"; - const HomeTemplateCopy = HomeTemplate.content.cloneNode(true) - view.appendChild(HomeTemplateCopy) + const HomeTemplateCopy = HomeTemplate.content.cloneNode(true); + view.appendChild(HomeTemplateCopy); break; case "mods-installed": title.innerText = "Installed Mods"; - const installedModsTemplateCopy = installedModsTemplate.content.cloneNode(true) - const searchFormInstalled = installedModsTemplateCopy.getElementById("search-form") - - searchFormInstalled.addEventListener('submit', async function(event) { - event.preventDefault() - }) + const installedModsTemplateCopy = installedModsTemplate.content.cloneNode(true); + const searchFormInstalled = installedModsTemplateCopy.getElementById("search-form"); - view.appendChild(installedModsTemplateCopy) + searchFormInstalled.addEventListener("submit", async function (event) { + event.preventDefault(); + }); + + view.appendChild(installedModsTemplateCopy); break; case "mods-online": title.innerText = "Online Mods"; - const onlineModsTemplateCopy = onlineModsTemplate.content.cloneNode(true) - const ModsContainer = onlineModsTemplateCopy.getElementById("mods-container") - const searchFormNexus = onlineModsTemplateCopy.getElementById("search-form") - - searchFormNexus.addEventListener('submit', async function(event) { - event.preventDefault() - }) + const onlineModsTemplateCopy = onlineModsTemplate.content.cloneNode(true); + const ModsContainer = onlineModsTemplateCopy.getElementById("mods-container"); + const searchFormNexus = onlineModsTemplateCopy.getElementById("search-form"); - view.appendChild(onlineModsTemplateCopy) + searchFormNexus.addEventListener("submit", async function (event) { + event.preventDefault(); + }); - mods = await nexus.getLatestMods() + view.appendChild(onlineModsTemplateCopy); + + mods = await nexus.getLatestMods(); if (mods == undefined) { break; } - for(const mod of mods) { + for (const mod of mods) { if (mod.name == undefined) { - continue + continue; } - const modTemplateCopy = modTemplate.content.cloneNode(true) + const modTemplateCopy = modTemplate.content.cloneNode(true); if (mod.name) { - const modTitleText = modTemplateCopy.getElementById("mod-title") - modTitleText.innerText = mod.name + const modTitleText = modTemplateCopy.getElementById("mod-title"); + modTitleText.innerText = mod.name; } if (mod.author) { - const modAuthorText = modTemplateCopy.getElementById("mod-author") - modAuthorText.innerText = `by ${mod.author}` + const modAuthorText = modTemplateCopy.getElementById("mod-author"); + modAuthorText.innerText = `by ${mod.author}`; } if (mod.endorsement_count) { - const modEndorsementsNumber = modTemplateCopy.getElementById("mod-endorsements-number") + const modEndorsementsNumber = modTemplateCopy.getElementById("mod-endorsements-number"); if (mod.endorsement_count > 1) { - modEndorsementsNumber.innerText = `${mod.endorsement_count} likes` - } - else { - modEndorsementsNumber.innerText = `${mod.endorsement_count} like` + modEndorsementsNumber.innerText = `${mod.endorsement_count} likes`; + } else { + modEndorsementsNumber.innerText = `${mod.endorsement_count} like`; } } if (mod.summary) { - const modDescriptionText = modTemplateCopy.getElementById("mod-description") - modDescriptionText.innerText = mod.summary + const modDescriptionText = modTemplateCopy.getElementById("mod-description"); + modDescriptionText.innerText = mod.summary; } if (mod.picture_url) { - const modPicture = modTemplateCopy.getElementById("mod-icon") - modPicture.src = mod.picture_url + const modPicture = modTemplateCopy.getElementById("mod-icon"); + modPicture.src = mod.picture_url; } if (mod.version && mod.updated_timestamp) { - const modVersionText = modTemplateCopy.getElementById("mod-version") - modVersionText.innerText = `V${mod.version} last updated on ${mod.updated_time.slice(0, 10)}` + const modVersionText = modTemplateCopy.getElementById("mod-version"); + modVersionText.innerText = `V${mod.version} last updated on ${mod.updated_time.slice(0, 10)}`; } - const modUrl = `https://www.nexusmods.com/hollowknightsilksong/mods/${mod.mod_id}` + const modUrl = `https://www.nexusmods.com/hollowknightsilksong/mods/${mod.mod_id}`; - const modLinkButton = modTemplateCopy.getElementById("external-link") - modLinkButton.href = modUrl - modLinkButton.addEventListener('click', function(event) { - event.preventDefault() - const modLink = modLinkButton.href - electronAPI.openExternalLink(modLink) - }) + const modLinkButton = modTemplateCopy.getElementById("external-link"); + modLinkButton.href = modUrl; + modLinkButton.addEventListener("click", function (event) { + event.preventDefault(); + const modLink = modLinkButton.href; + electronAPI.openExternalLink(modLink); + }); - modDownloadButton = modTemplateCopy.getElementById("download-mod-button") - modDownloadButton.addEventListener('click', function(event) { - event.preventDefault() - const modDownloadLink = `${modUrl}?tab=files` - nexus.download(modDownloadLink) - }) + modDownloadButton = modTemplateCopy.getElementById("download-mod-button"); + modDownloadButton.addEventListener("click", function (event) { + event.preventDefault(); + const modDownloadLink = `${modUrl}?tab=files`; + nexus.download(modDownloadLink); + }); - ModsContainer.appendChild(modTemplateCopy) + ModsContainer.appendChild(modTemplateCopy); } break; case "general-settings": title.innerText = "Settings"; - const settingsTemplateCopy = settingsTemplate.content.cloneNode(true) - const silksongPathInput = settingsTemplateCopy.getElementById("silksong-path-input") - const nexusAPIInput = settingsTemplateCopy.getElementById("nexus-api-input") - const versionsList = settingsTemplateCopy.getElementById("versions-list") + const settingsTemplateCopy = settingsTemplate.content.cloneNode(true); + const silksongPathInput = settingsTemplateCopy.getElementById("silksong-path-input"); + const nexusAPIInput = settingsTemplateCopy.getElementById("nexus-api-input"); + const versionsList = settingsTemplateCopy.getElementById("versions-list"); const versionsDictionnary = { - "Silk-Fly-Launcher": `Silk Fly Launcher: v${versions.silkFlyLauncher()}`, - "Electron": `Electron: v${versions.electron()}`, - "Node": `Node.js: v${versions.node()}`, - "Chromium": `Chromium: v${versions.chromium()}`, - } - const lacePinCheckbox = settingsTemplateCopy.getElementById('lace-pin'); + "Silk-Fly-Launcher": `Silk Fly Launcher: v${versions.silkFlyLauncher()}`, + Electron: `Electron: v${versions.electron()}`, + Node: `Node.js: v${versions.node()}`, + Chromium: `Chromium: v${versions.chromium()}`, + }; + const lacePinCheckbox = settingsTemplateCopy.getElementById("lace-pin"); - silksongPathInput.value = await files.loadSilksongPath() - silksongPathInput.addEventListener('input', async function(event) { - let silksongPath = silksongPathInput.value - files.saveSilksongPath(silksongPath) + silksongPathInput.value = await files.loadSilksongPath(); + silksongPathInput.addEventListener("input", async function (event) { + let silksongPath = silksongPathInput.value; + files.saveSilksongPath(silksongPath); }); - nexusAPIInput.value = await files.loadNexusAPI() - nexusAPIInput.addEventListener('input', async function(event) { - let nexusAPI = nexusAPIInput.value - files.saveNexusAPI(nexusAPI) + nexusAPIInput.value = await files.loadNexusAPI(); + nexusAPIInput.addEventListener("input", async function (event) { + let nexusAPI = nexusAPIInput.value; + files.saveNexusAPI(nexusAPI); }); - - for(const element of versionsList.children) { - element.innerText = versionsDictionnary[element.id] + + for (const element of versionsList.children) { + element.innerText = versionsDictionnary[element.id]; } - const theme = await files.loadTheme() - lacePinCheckbox.checked = theme[1] + const theme = await files.loadTheme(); + lacePinCheckbox.checked = theme[1]; - lacePinCheckbox.addEventListener('change', async function() { + lacePinCheckbox.addEventListener("change", async function () { if (this.checked) { const theme = await files.loadTheme(); changeTheme(theme[0], true); - toggleThemesMenu() - } - else { + toggleThemesMenu(); + } else { const theme = await files.loadTheme(); changeTheme(theme[0], false); - toggleThemesMenu() + toggleThemesMenu(); } }); - view.appendChild(settingsTemplateCopy) - setBepinexVersion() - setThemeButton() - verifyNexusAPI() + view.appendChild(settingsTemplateCopy); + setBepinexVersion(); + setThemeButton(); + verifyNexusAPI(); break; } } async function welcomeNavigate() { - pageDiv.replaceChildren() + pageDiv.replaceChildren(); switch (actualPage) { case 0: - pageDiv.appendChild(welcomeTemplate.content.cloneNode(true)) - buttonDiv.replaceChildren() - buttonDiv.appendChild(oneButtonTemplate.content.cloneNode(true)) + pageDiv.appendChild(welcomeTemplate.content.cloneNode(true)); + buttonDiv.replaceChildren(); + buttonDiv.appendChild(oneButtonTemplate.content.cloneNode(true)); break; case 1: - pageDiv.appendChild(silksongPathTemplate.content.cloneNode(true)) - buttonDiv.replaceChildren() - buttonDiv.appendChild(twoButtonTemplate.content.cloneNode(true)) + pageDiv.appendChild(silksongPathTemplate.content.cloneNode(true)); + buttonDiv.replaceChildren(); + buttonDiv.appendChild(twoButtonTemplate.content.cloneNode(true)); - const silksongPathInput = document.getElementById("silksong-path-input") - if (await files.loadSilksongPath() == "") { - autoDetectGamePath() - } - else { - document.getElementById("silksong-path-input").value = await files.loadSilksongPath() + const silksongPathInput = document.getElementById("silksong-path-input"); + if ((await files.loadSilksongPath()) == "") { + autoDetectGamePath(); + } else { + document.getElementById("silksong-path-input").value = await files.loadSilksongPath(); } - silksongPathInput.addEventListener('input', async function(event) { - let silksongPath = silksongPathInput.value - await files.saveSilksongPath(silksongPath) + silksongPathInput.addEventListener("input", async function (event) { + let silksongPath = silksongPathInput.value; + await files.saveSilksongPath(silksongPath); }); break; case 2: - pageDiv.appendChild(nexusTemplate.content.cloneNode(true)) - const nexusLink = document.getElementById("external-link") - nexusLink.addEventListener('click', function(event) { - event.preventDefault() - const url = nexusLink.href - electronAPI.openExternalLink(url) - }) + pageDiv.appendChild(nexusTemplate.content.cloneNode(true)); + const nexusLink = document.getElementById("external-link"); + nexusLink.addEventListener("click", function (event) { + event.preventDefault(); + const url = nexusLink.href; + electronAPI.openExternalLink(url); + }); - const nexusAPIInput = document.getElementById("nexus-api-input") - nexusAPIInput.value = await files.loadNexusAPI() - nexusAPIInput.addEventListener('input', async function(event) { - let nexusAPI = nexusAPIInput.value - await files.saveNexusAPI(nexusAPI) + const nexusAPIInput = document.getElementById("nexus-api-input"); + nexusAPIInput.value = await files.loadNexusAPI(); + nexusAPIInput.addEventListener("input", async function (event) { + let nexusAPI = nexusAPIInput.value; + await files.saveNexusAPI(nexusAPI); }); break; case 3: - pageDiv.appendChild(styleTemplate.content.cloneNode(true)) + pageDiv.appendChild(styleTemplate.content.cloneNode(true)); break; case 4: - pageDiv.appendChild(tutorialTemplate.content.cloneNode(true)) + pageDiv.appendChild(tutorialTemplate.content.cloneNode(true)); break; case 5: - electronAPI.loadMainPage() + electronAPI.loadMainPage(); break; } } function next() { - actualPage++ - welcomeNavigate() + actualPage++; + welcomeNavigate(); } function back() { - actualPage-- - welcomeNavigate() + actualPage--; + welcomeNavigate(); } ////////////////////////////////////////////////////// @@ -273,149 +269,145 @@ function back() { async function initialImportData() { if (await files.import()) { - electronAPI.loadMainPage() + electronAPI.loadMainPage(); } } async function importData() { - await files.import() - document.getElementById("silksong-path-input").value = await files.loadSilksongPath() - document.getElementById("nexus-api-input").value = await files.loadNexusAPI() - const lacePinCheckbox = document.getElementById('lace-pin') - const theme = await files.loadTheme() - lacePinCheckbox.checked = theme[1] - changeTheme(theme[0]) - toggleThemesMenu() + await files.import(); + document.getElementById("silksong-path-input").value = await files.loadSilksongPath(); + document.getElementById("nexus-api-input").value = await files.loadNexusAPI(); + const lacePinCheckbox = document.getElementById("lace-pin"); + const theme = await files.loadTheme(); + lacePinCheckbox.checked = theme[1]; + changeTheme(theme[0]); + toggleThemesMenu(); } async function exportData() { - await files.export() + await files.export(); } async function deleteData() { - const lacePinCheckbox = document.getElementById('lace-pin') - lacePinCheckbox.checked = false - changeTheme("Silksong") - toggleThemesMenu() - await files.delete() - document.getElementById("silksong-path-input").value = await files.loadSilksongPath() - document.getElementById("nexus-api-input").value = await files.loadNexusAPI() + const lacePinCheckbox = document.getElementById("lace-pin"); + lacePinCheckbox.checked = false; + changeTheme("Silksong"); + toggleThemesMenu(); + await files.delete(); + document.getElementById("silksong-path-input").value = await files.loadSilksongPath(); + document.getElementById("nexus-api-input").value = await files.loadNexusAPI(); } ////////////////////////////////////////////////////// ////////////////////// BEPINEX /////////////////////// async function installBepinex() { - await bepinex.install() - setBepinexVersion() + await bepinex.install(); + setBepinexVersion(); } async function uninstallBepinex() { - await bepinex.uninstall() - setBepinexVersion() + await bepinex.uninstall(); + setBepinexVersion(); } async function backupBepinex() { - await bepinex.backup() - setBepinexVersion() + await bepinex.backup(); + setBepinexVersion(); } async function deleteBepinexBackup() { - await bepinex.deleteBackup() - setBepinexVersion() + await bepinex.deleteBackup(); + setBepinexVersion(); } async function setBepinexVersion() { - const bepinexVersionText = document.getElementById("bepinex-version-text") + const bepinexVersionText = document.getElementById("bepinex-version-text"); if (bepinexVersionText == undefined) { - return + return; } - - const bepinexVersion = await files.loadBepinexVersion() - const bepinexBackupVersion = await files.loadBepinexBackupVersion() - if(bepinexVersion == undefined) { - if(bepinexBackupVersion == undefined) { - bepinexVersionText.innerText = "BepInEx is not installed" + + const bepinexVersion = await files.loadBepinexVersion(); + const bepinexBackupVersion = await files.loadBepinexBackupVersion(); + if (bepinexVersion == undefined) { + if (bepinexBackupVersion == undefined) { + bepinexVersionText.innerText = "BepInEx is not installed"; + } else { + bepinexVersionText.innerText = `BepInEx ${bepinexBackupVersion} is backed up`; } - else { - bepinexVersionText.innerText = `BepInEx ${bepinexBackupVersion} is backed up` - } - } - else { - bepinexVersionText.innerText = `BepInEx ${bepinexVersion} is installed` + } else { + bepinexVersionText.innerText = `BepInEx ${bepinexVersion} is installed`; } } async function searchInstalledMods() { - const searchInput = document.getElementById("search-input") - console.log(searchInput.value) + const searchInput = document.getElementById("search-input"); + console.log(searchInput.value); } ////////////////////////////////////////////////////// /////////////////////// NEXUS //////////////////////// async function verifyNexusAPI() { - response = await nexus.verifyAPI() + response = await nexus.verifyAPI(); - const nexusCheckImage = document.getElementById("nexus-check-image") + const nexusCheckImage = document.getElementById("nexus-check-image"); if (nexusCheckImage == undefined) { - return + return; } if (response) { - nexusCheckImage.src = "assets/check.svg" - } - else { - nexusCheckImage.src = "assets/cross.svg" + nexusCheckImage.src = "assets/check.svg"; + } else { + nexusCheckImage.src = "assets/cross.svg"; } } async function searchNexusMods() { - const searchInput = document.getElementById("search-input") - console.log(searchInput.value) + const searchInput = document.getElementById("search-input"); + console.log(searchInput.value); } ////////////////////////////////////////////////////// /////////////////////// THEMES /////////////////////// function toggleThemesMenu() { - const themesMenu = document.getElementById("themes-menu") + const themesMenu = document.getElementById("themes-menu"); if (themesMenu) { - themesMenu.classList.toggle("show") + themesMenu.classList.toggle("show"); } } async function setThemeButton() { - const themesButton = document.getElementById("themes-button") + const themesButton = document.getElementById("themes-button"); if (themesButton) { - const theme = await files.loadTheme() - themesButton.textContent = theme[0] + const theme = await files.loadTheme(); + themesButton.textContent = theme[0]; } } function changeTheme(theme, state) { - toggleThemesMenu() + toggleThemesMenu(); - const lacePinCheckbox = document.getElementById('lace-pin'); + const lacePinCheckbox = document.getElementById("lace-pin"); if (lacePinCheckbox) { lacePinState = lacePinCheckbox.checked; - } - else if (state) { - lacePinState = state - } - else { - lacePinState = false + } else if (state) { + lacePinState = state; + } else { + lacePinState = false; } if (actualTheme[0] == theme && actualTheme[1] == lacePinState) { - return + return; } - actualTheme = [theme, lacePinState] + actualTheme = [theme, lacePinState]; - files.saveTheme(theme, lacePinState) + files.saveTheme(theme, lacePinState); - setThemeButton() + setThemeButton(); + // prettier-ignore const themesColors = { "var": ["--primary-color", "--secondary-color", "--background-color"], "Silksong": ["rgba(255, 25, 0, 0.3)", "#ff6b6b", "rgba(255, 72, 0, 0.2)"], @@ -426,17 +418,18 @@ function changeTheme(theme, state) { "Surface": ["rgba(75, 120, 255, 0.3)", "#87c3ff", "rgba(42, 107, 203, 0.2)"], "Steel": ["rgba(164, 164, 164, 0.3)", "#c5b9b9", "rgba(255, 255, 255, 0.2)"] } - for(let i = 0; i < 3; i++) { - document.documentElement.style.setProperty(themesColors.var[i], themesColors[theme][i]) + + for (let i = 0; i < 3; i++) { + document.documentElement.style.setProperty(themesColors.var[i], themesColors[theme][i]); } - const backgroundVideo = document.getElementById("background-video") - let backgroundVideoPath = `assets/background/${theme}.mp4` + const backgroundVideo = document.getElementById("background-video"); + let backgroundVideoPath = `assets/background/${theme}.mp4`; if (lacePinState) { - backgroundVideoPath = `assets/background/${theme} Lace Pin.mp4` + backgroundVideoPath = `assets/background/${theme} Lace Pin.mp4`; } - - backgroundVideo.src = backgroundVideoPath + + backgroundVideo.src = backgroundVideoPath; } ////////////////////////////////////////////////////// @@ -444,12 +437,12 @@ function changeTheme(theme, state) { async function launch(mode) { await electronAPI.launchGame(mode); - setBepinexVersion() + setBepinexVersion(); } async function autoDetectGamePath() { - await files.autoDetectGamePath() + await files.autoDetectGamePath(); if (document.getElementById("silksong-path-input")) { - document.getElementById("silksong-path-input").value = await files.loadSilksongPath() + document.getElementById("silksong-path-input").value = await files.loadSilksongPath(); } -} \ No newline at end of file +} diff --git a/renderer/style.css b/renderer/style.css index 908eadd..2a65e39 100644 --- a/renderer/style.css +++ b/renderer/style.css @@ -2,7 +2,9 @@ margin: 0; box-sizing: border-box; font-family: "Segoe UI", sans-serif; - cursor: url("assets/cursor.png") 0 0, auto !important; + cursor: + url("assets/cursor.png") 0 0, + auto !important; } :root { @@ -13,7 +15,7 @@ --text-color: #eee; --transparent-black: rgba(0, 0, 0, 0.4); --darker-transparent-black: rgba(0, 0, 0, 0.8); - --transparent-grey: rgba(30, 30, 30, 0.8) + --transparent-grey: rgba(30, 30, 30, 0.8); } body { @@ -69,6 +71,10 @@ body { height: 100px; } +.invert-color { + filter: invert(1); +} + .nav { padding: 20px; } @@ -86,7 +92,7 @@ body { margin-bottom: 10px; padding: 0 4px 4px; - border-bottom: 1px solid var(--secondary-color); + border-bottom: 1px solid var(--secondary-color); } .nav button { @@ -124,7 +130,7 @@ body { margin-bottom: 20px; color: var(--text-color); padding: 0 4px 4px; - border-bottom: 1px solid var(--secondary-color); + border-bottom: 1px solid var(--secondary-color); } .view { @@ -135,7 +141,7 @@ body { z-index: 0; box-shadow: 0 0 50px var(--darker-transparent-black); overflow: auto; - height: 90%; + height: 90%; } .horizontal-div { @@ -371,4 +377,4 @@ body { border: solid var(--text-color); border-width: 0 2px 2px 0; transform: rotate(45deg); -} \ No newline at end of file +} diff --git a/renderer/welcome.html b/renderer/welcome.html index bf25f2c..2a14ab2 100644 --- a/renderer/welcome.html +++ b/renderer/welcome.html @@ -1,84 +1,87 @@ - + - - - Welcome to Silk Fly Launcher - - - - -
- + + + Welcome to Silk Fly Launcher + + + + +
+ -
-
-
-
-
-
- - - - - - - - - - - - - + - - - \ No newline at end of file + + + + + + + + + + + + + + +