From 776a53d7beaadb55231f6b02e28090c7cc678cde Mon Sep 17 00:00:00 2001 From: GabiZar Date: Sat, 28 Mar 2026 15:52:40 +0100 Subject: [PATCH] Add Linux AppImage maker for universal builds --- forge.config.cjs | 13 +++++++++++++ main.js | 25 ++++++++++++++++++++----- package-lock.json | 39 +++++++++++++++++++++++++++++++++++++++ package.json | 4 +++- 4 files changed, 75 insertions(+), 6 deletions(-) diff --git a/forge.config.cjs b/forge.config.cjs index f7308c2..8fbc80d 100644 --- a/forge.config.cjs +++ b/forge.config.cjs @@ -40,6 +40,19 @@ if (buildTarget == "deb" || buildTarget == "all") { }); } +if (buildTarget == "appimage" || buildTarget == "all") { + makers.push({ + name: "@reforged/maker-appimage", + config: { + options: { + bin: packageJson.productName, + name: packageJson.productName, + icon: "./assets/icon.png", + }, + }, + }); +} + async function fileExists(filePath) { try { await fs.access(filePath); diff --git a/main.js b/main.js index 5ec0647..3c2b203 100644 --- a/main.js +++ b/main.js @@ -29,6 +29,7 @@ const installedModsStore = new Store({ name: "installed-mods-list" }); const NexusAPIStore = new Store({ name: "nexus-api", encryptionKey: packageJson["AES-key-nexus-api"], fileExtension: "encrypted", clearInvalidConfig: true }); const userSavePath = app.getPath("userData"); +const tempPath = app.getPath("temp"); const modSavePath = path.join(userSavePath, "mods"); const dataPath = path.join(userSavePath, "config.json"); let sevenZipPath = path7za; @@ -71,6 +72,7 @@ async function createWindow() { webPreferences: { preload: path.join(__dirname, "preload.js"), }, + backgroundColor: "#000", show: false, }); @@ -82,7 +84,7 @@ async function createWindow() { mainWindow.loadFile(path.join("renderer", htmlFile)); - mainWindow.once("ready-to-show", () => { + mainWindow.webContents.once("did-finish-load", () => { mainWindow.show(); if (!isDev) { verifyUpdate(); @@ -106,9 +108,6 @@ app.whenReady().then(async () => { } app.on("activate", async () => { - if (process.platform === "linux") { - await fs.chmod(sevenZipPath, 0o755); - } if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } @@ -1023,7 +1022,10 @@ async function downloadAndUnzip(url, toPath) { await fs.unlink(tempPath); } -function extractArchive(archivePath, destPath) { +async function extractArchive(archivePath, destPath) { + if (process.platform === "linux") { + await prepareSevenZipLinux(); + } return new Promise((resolve, reject) => { const stream = extractFull(archivePath, destPath, { $bin: sevenZipPath, @@ -1037,3 +1039,16 @@ function extractArchive(archivePath, destPath) { ipcMain.handle("get-version", () => { return VERSION; }); + +async function prepareSevenZipLinux() { + const targetPath = path.join(tempPath, "7za"); + if (await fileExists(targetPath)) { + sevenZipPath = targetPath; + return; + } + + await fs.copyFile(sevenZipPath, targetPath); + await fs.chmod(targetPath, 0o755); + + sevenZipPath = targetPath; +} diff --git a/package-lock.json b/package-lock.json index f025766..be52621 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "@electron-forge/plugin-auto-unpack-natives": "^7.11.1", "@electron-forge/plugin-fuses": "^7.11.1", "@electron/fuses": "^1.8.0", + "@reforged/maker-appimage": "^5.2.0", "cross-env": "^10.1.0", "electron": "^40.6.0" } @@ -1257,6 +1258,37 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/@reforged/maker-appimage": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@reforged/maker-appimage/-/maker-appimage-5.2.0.tgz", + "integrity": "sha512-5u7spsDMyMfwqAnTRsSipVgTIy+DW+wlfhceaRghCuTvyY8Sti8/tFhVKj4vb+dYTqPvS7m30Gl0InGv22J8RQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@electron-forge/maker-base": "^6.0.0 || ^7.0.0", + "@reforged/maker-types": "^2.1.0", + "@spacingbat3/lss": "^1.0.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=19.0.0 || ^18.11.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/SpacingBat3/ReForged?sponsor=1" + } + }, + "node_modules/@reforged/maker-types": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@reforged/maker-types/-/maker-types-2.1.0.tgz", + "integrity": "sha512-gNMAFO6mxqGwuUov0CzXGTHUMfAawlM6v/uYrqVnKeMwmceaLBt3HtfPcuNapDSH4br6D4EZ14WuWbgefmDfOQ==", + "dev": true, + "license": "ISC", + "funding": { + "type": "github", + "url": "https://github.com/SpacingBat3/ReForged?sponsor=1" + } + }, "node_modules/@sindresorhus/is": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", @@ -1270,6 +1302,13 @@ "url": "https://github.com/sindresorhus/is?sponsor=1" } }, + "node_modules/@spacingbat3/lss": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@spacingbat3/lss/-/lss-1.2.0.tgz", + "integrity": "sha512-aywhxHNb6l7COooF3m439eT/6QN8E/RSl5IVboSKthMHcp0GlZYMSoS7546rqDLmFRxTD8f1tu/NIS9vtDwYAg==", + "dev": true, + "license": "ISC" + }, "node_modules/@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", diff --git a/package.json b/package.json index 2895d5f..1b0a9ae 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,8 @@ "make": "electron-forge make", "make:msi": "cross-env BUILD_TARGET=msi electron-forge make", "make:zip": "cross-env BUILD_TARGET=zip electron-forge make", - "make:deb": "cross-env BUILD_TARGET=deb electron-forge make" + "make:deb": "cross-env BUILD_TARGET=deb electron-forge make", + "make:appimage": "cross-env BUILD_TARGET=appimage electron-forge make" }, "author": "GabiZar", "license": "GPL-3.0", @@ -23,6 +24,7 @@ "@electron-forge/plugin-auto-unpack-natives": "^7.11.1", "@electron-forge/plugin-fuses": "^7.11.1", "@electron/fuses": "^1.8.0", + "@reforged/maker-appimage": "^5.2.0", "cross-env": "^10.1.0", "electron": "^40.6.0" },