diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | src/app/index.html | 12 | ||||
-rw-r--r-- | src/index.js | 75 | ||||
-rw-r--r-- | src/lang/en.json | 3 | ||||
-rw-r--r-- | src/utils.js | 239 |
5 files changed, 182 insertions, 148 deletions
@@ -1,2 +1,3 @@ dist/ node_modules/ +.vscode/
\ No newline at end of file diff --git a/src/app/index.html b/src/app/index.html index 2305e4c..0255dd6 100644 --- a/src/app/index.html +++ b/src/app/index.html @@ -107,6 +107,18 @@ <input type="text"> </div> </div> + <h2>%%gui.settings.title.misc%%</h2> + <div class="option" name="originkill"> + <div class="text"> + %%gui.settings.originkill.title%% + <div class="desc"> + %%gui.settings.originkill.desc%% + </div> + </div> + <div class="actions"> + <button class="switch off"></button> + </div> + </div> </div> </div> diff --git a/src/index.js b/src/index.js index 96976b7..ddaa928 100644 --- a/src/index.js +++ b/src/index.js @@ -6,6 +6,7 @@ const { app, ipcMain, BrowserWindow, dialog } = require("electron"); const utils = require("./utils"); const cli = require("./cli"); const requests = require("./extras/requests"); +const { settings } = require("./utils"); var log = console.log; @@ -33,10 +34,10 @@ function start() { nodeIntegration: true, contextIsolation: false, }, - }); + }); // when --debug is added it'll open the dev tools - if (cli.hasParam("debug")) {win.openDevTools()} + if (cli.hasParam("debug")) { win.openDevTools() } // general setup win.removeMenu(); @@ -46,23 +47,35 @@ function start() { win.webContents.send(channel, data); }; send = win.send; - ipcMain.on("exit", () => {process.exit(0)}); - ipcMain.on("minimize", () => {win.minimize()}); - ipcMain.on("relaunch", () => {app.relaunch();app.exit()}); + ipcMain.on("exit", () => { + if (settings.originkill) { + utils.isOriginRunning().then((running) => { + if (running) { + utils.killOrigin().then(process.exit(0)) + } else { + process.exit(0) + } + }) + } else { + process.exit(0) + } + }); + ipcMain.on("minimize", () => { win.minimize() }); + ipcMain.on("relaunch", () => { app.relaunch(); app.exit() }); // passthrough to renderer from main - ipcMain.on("win-log", (event, ...args) => {send("log", ...args)}); - ipcMain.on("win-alert", (event, ...args) => {send("alert", ...args)}); + ipcMain.on("win-log", (event, ...args) => { send("log", ...args) }); + ipcMain.on("win-alert", (event, ...args) => { send("alert", ...args) }); // mod states - ipcMain.on("failed-mod", (event, modname) => {send("failed-mod", modname)}); - ipcMain.on("removed-mod", (event, modname) => {send("removed-mod", modname)}); - ipcMain.on("gui-getmods", (event, ...args) => {send("mods", utils.mods.list())}); - ipcMain.on("installed-mod", (event, modname) => {send("installed-mod", modname)}); + ipcMain.on("failed-mod", (event, modname) => { send("failed-mod", modname) }); + ipcMain.on("removed-mod", (event, modname) => { send("removed-mod", modname) }); + ipcMain.on("gui-getmods", (event, ...args) => { send("mods", utils.mods.list()) }); + ipcMain.on("installed-mod", (event, modname) => { send("installed-mod", modname) }); // install calls - ipcMain.on("install-from-path", (event, path) => {utils.mods.install(path)}); - ipcMain.on("install-from-url", (event, url) => {utils.mods.installFromURL(url)}); + ipcMain.on("install-from-path", (event, path) => { utils.mods.install(path) }); + ipcMain.on("install-from-url", (event, url) => { utils.mods.installFromURL(url) }); win.webContents.on("dom-ready", () => { send("mods", utils.mods.list()); @@ -71,18 +84,18 @@ function start() { // ensures gamepath still exists and is valid on startup let gamepathlost = false; ipcMain.on("gamepath-lost", (event, ...args) => { - if (! gamepathlost) { + if (!gamepathlost) { gamepathlost = true; send("gamepath-lost"); } }); - ipcMain.on("save-settings", (event, obj) => {utils.saveSettings(obj)}); + ipcMain.on("save-settings", (event, obj) => { utils.saveSettings(obj) }); // allows renderer to check for updates - ipcMain.on("ns-update-event", (event) => {send("ns-update-event", event)}); + ipcMain.on("ns-update-event", (event) => { send("ns-update-event", event) }); ipcMain.on("can-autoupdate", () => { - if (! autoUpdater.isUpdaterActive() || cli.hasParam("no-vp-updates")) { + if (!autoUpdater.isUpdaterActive() || cli.hasParam("no-vp-updates")) { send("cant-autoupdate"); } }) @@ -115,34 +128,34 @@ ipcMain.on("install-mod", () => { if (cli.hasArgs()) { utils.mods.install(cli.param("installmod")); } else { - dialog.showOpenDialog({properties: ["openFile"]}).then(res => { + dialog.showOpenDialog({ properties: ["openFile"] }).then(res => { if (res.filePaths.length != 0) { utils.mods.install(res.filePaths[0]); } else { send("set-buttons", true); } - }).catch(err => {error(err)}); + }).catch(err => { error(err) }); } }) -ipcMain.on("remove-mod", (event, mod) => {utils.mods.remove(mod)}); -ipcMain.on("toggle-mod", (event, mod) => {utils.mods.toggle(mod)}); +ipcMain.on("remove-mod", (event, mod) => { utils.mods.remove(mod) }); +ipcMain.on("toggle-mod", (event, mod) => { utils.mods.toggle(mod) }); -ipcMain.on("launch-ns", () => {utils.launch()}); -ipcMain.on("launch-vanilla", () => {utils.launch("vanilla")}); +ipcMain.on("launch-ns", () => { utils.launch() }); +ipcMain.on("launch-vanilla", () => { utils.launch("vanilla") }); -ipcMain.on("setlang", (event, lang) => {utils.setlang(lang)}); +ipcMain.on("setlang", (event, lang) => { utils.setlang(lang) }); -ipcMain.on("update", () => {utils.update()}) -ipcMain.on("setpath-cli", () => {utils.setpath()}); +ipcMain.on("update", () => { utils.update() }) +ipcMain.on("setpath-cli", () => { utils.setpath() }); ipcMain.on("setpath", (event, value) => { - if (! value) { - if (! win.isVisible()) { + if (!value) { + if (!win.isVisible()) { utils.setpath(win); } else { utils.setpath(win, true); } - } else if (! win.isVisible()) { + } else if (!win.isVisible()) { win.show(); } }); @@ -157,7 +170,7 @@ function sendVersionsInfo() { } // sends the version info back to the renderer -ipcMain.on("get-version", () => {sendVersionsInfo()}); +ipcMain.on("get-version", () => { sendVersionsInfo() }); // prints out version info for the CLI ipcMain.on("version-cli", () => { @@ -194,7 +207,7 @@ ipcMain.on("getmods", () => { // allows renderer to set a new renderer ipcMain.on("newpath", (event, newpath) => { - if (newpath === false && ! win.isVisible()) { + if (newpath === false && !win.isVisible()) { win.send("no-path-selected"); } else { _sendVersionsInfo(); diff --git a/src/lang/en.json b/src/lang/en.json index 34c4619..3ae6ff1 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -91,6 +91,7 @@ "gui.settings.title.ns": "Northstar", "gui.settings.title.language": "Language", "gui.settings.title.updates": "Updates", + "gui.settings.title.misc": "Miscellaneous", "gui.settings.nsargs.title": "Launch options", "gui.settings.nsargs.desc": "Here you can add launch options for Northstar/Titanfall.", "gui.settings.autolang.title": "Auto-Detect Language", @@ -103,6 +104,8 @@ "gui.settings.nsupdate.desc": "Viper will automatically keep Northstar up-to-date, however it can still manually be updated through the Northstar page.", "gui.settings.excludes.title": "Retain files on update", "gui.settings.excludes.desc": "When Northstar is updated, files specified here will not be overwritten by files from the new Northstar update, unless you know what you're changing, you should probably not change anything here. Each file is separated with a space.", + "gui.settings.originkill.title": "Automatically quit Origin", + "gui.settings.originkill.desc": "When Viper exits, automatically quit Origin client too. Mirrors behavior of launching the game through Steam.", "gui.update.downloading": "Downloading...", "gui.update.extracting": "Extracting update...", diff --git a/src/utils.js b/src/utils.js index 061c3f1..2e81bdf 100644 --- a/src/utils.js +++ b/src/utils.js @@ -37,7 +37,9 @@ var settings = { excludes: [ "ns_startup_args.txt", "ns_startup_args_dedi.txt" - ] + ], + + originkill: false } // Logs into the dev tools of the renderer @@ -58,11 +60,11 @@ if (fs.existsSync("viper.json")) { // Validates viper.json try { json = JSON.parse(conf); - }catch (e) { + } catch (e) { invalidsettings = true; } - settings = {...settings, ...json}; + settings = { ...settings, ...json }; settings.zip = path.join(settings.gamepath + "/northstar.zip"); let args = path.join(settings.gamepath, "ns_startup_args.txt"); @@ -95,7 +97,7 @@ async function isGameRunning() { break } - if (i == procs.length - 1) {resolve(false)} + if (i == procs.length - 1) { resolve(false) } } }); }); @@ -103,44 +105,44 @@ async function isGameRunning() { //Check if origin client is running async function isOriginRunning() { - return new Promise(resolve => { - let procs = ["origin.exe"]; //check this, probably not right - let cmd = (() => { - switch (process.platform) { - case "linux": return "ps -A"; - case "win32": return "tasklist"; - } - })(); - - exec(cmd, (err, stdout) => { - procs.forEach( proc => { - if (stdout.includes(proc)) { - resolve(true); - return; - } - resolve(false); - }); + return new Promise(resolve => { + let procs = ["Origin.exe", "OriginClientService.exe"]; + let cmd = (() => { + switch (process.platform) { + case "linux": return "ps -A"; + case "win32": return "tasklist"; + } + })(); + + exec(cmd, (err, stdout) => { + procs.forEach(proc => { + if (stdout.includes(proc)) { + resolve(true); + return; + } + resolve(false); + }); + }); }); - }); } //Kill origin client async function killOrigin() { - return Promise(resolve => { - let proc = "origin.exe" ; //need to match above - let cmd = (() => { - switch (process.platform) { - case "linux": return "killall " + proc; - case "win32": return "taskkill /IM " + proc + " /F"; - } - })(); - - exec(cmd, (err, stdout) => { - //do some checking here maybe? idk we're going to be exiting so maybe we should - //just try and fail silently if we don't find shit - resolve(true); + return new Promise(resolve => { + let proc = "Origin.exe"; //I'm pretty sure we only have to kill this one + let cmd = (() => { + switch (process.platform) { + case "linux": return "killall " + proc; + case "win32": return "taskkill /IM " + proc + " /F"; + } + })(); + + exec(cmd, (err, stdout) => { + //do some checking here maybe? idk we're going to be exiting so maybe we should + //just try and fail silently if we don't find shit + resolve(true); + }); }); - }); } // Handles auto updating Northstar. @@ -148,7 +150,7 @@ async function killOrigin() { // It uses isGameRunning() to ensure it doesn't run while the game is // running, as that may have all kinds of issues. function handleNorthstarUpdating() { - if (! settings.nsupdate || ! fs.existsSync("viper.json") || settings.gamepath.length === 0) { + if (!settings.nsupdate || !fs.existsSync("viper.json") || settings.gamepath.length === 0) { return; } @@ -163,7 +165,7 @@ function handleNorthstarUpdating() { if (await isGameRunning()) { console.log(lang("cli.autoupdates.gamerunning")); new Notification({ - title: lang("gui.nsupdate.gaming.title"), + title: lang("gui.nsupdate.gaming.title"), body: lang("gui.nsupdate.gaming.body") }).show(); } else { @@ -175,7 +177,7 @@ function handleNorthstarUpdating() { } setTimeout( - _checkForUpdates, + _checkForUpdates, 15 * 60 * 1000 // interval in between each update check // by default 15 minutes. @@ -201,10 +203,10 @@ async function setpath(win, forcedialog) { modpath = path.join(settings.gamepath, "R2Northstar/mods"); } - if (! win) { // CLI + if (!win) { // CLI setGamepath(cli.param("setpath")); } else { // GUI - if (! forcedialog) { + if (!forcedialog) { function setGamepath(folder, forcedialog) { settings.gamepath = folder; settings.zip = path.join(settings.gamepath + "/northstar.zip"); @@ -223,12 +225,12 @@ async function setpath(win, forcedialog) { } // Fallback to manual selection - dialog.showOpenDialog({properties: ["openDirectory"]}).then(res => { + dialog.showOpenDialog({ properties: ["openDirectory"] }).then(res => { if (res.canceled) { ipcMain.emit("newpath", null, false); return; } - if (! fs.existsSync(path.join(res.filePaths[0], "Titanfall2.exe"))) { + if (!fs.existsSync(path.join(res.filePaths[0], "Titanfall2.exe"))) { ipcMain.emit("wrong-path"); return; } @@ -237,7 +239,7 @@ async function setpath(win, forcedialog) { cli.exit(); return; - }).catch(err => {console.error(err)}) + }).catch(err => { console.error(err) }) } } @@ -248,15 +250,15 @@ async function setpath(win, forcedialog) { // You can also pass a settings object to the function and it'll try and // merge it together with the already existing settings function saveSettings(obj = {}) { - if (invalidsettings) {return false} + if (invalidsettings) { return false } - settings = {...settings, ...obj}; + settings = { ...settings, ...obj }; if (fs.existsSync(settings.gamepath)) { fs.writeFileSync(path.join(settings.gamepath, "ns_startup_args.txt"), settings.nsargs); } - fs.writeFileSync(app.getPath("appData") + "/viper.json", JSON.stringify({...settings, ...obj})); + fs.writeFileSync(app.getPath("appData") + "/viper.json", JSON.stringify({ ...settings, ...obj })); } // Returns the current Northstar version @@ -313,7 +315,7 @@ restoreExcludedFiles(); // <file>.excluded, then rename them back after the extraction. The // unzip module does not support excluding files directly. async function update() { - if (! gamepathExists()) {return} + if (!gamepathExists()) { return } ipcMain.emit("ns-update-event", "cli.update.checking"); console.log(lang("cli.update.checking")); @@ -332,7 +334,7 @@ async function update() { } else { if (version != "unknown") { console.log(lang("cli.update.current"), version); - }; + }; console.log(lang("cli.update.downloading") + ":", latestAvailableVersion); ipcMain.emit("ns-update-event", "cli.update.downloading"); } @@ -365,19 +367,19 @@ async function update() { console.log(lang("cli.update.downloaddone")); // Extracts the zip, this is the part where we're actually // installing Northstar. - fs.createReadStream(settings.zip).pipe(unzip.Extract({path: settings.gamepath})) - .on("finish", () => { - fs.writeFileSync(path.join(settings.gamepath, "ns_version.txt"), latestAvailableVersion); - ipcMain.emit("get-version"); - - restoreExcludedFiles(); - - ipcMain.emit("gui-getmods"); - ipcMain.emit("ns-update-event", "cli.update.uptodate.short"); - winLog(lang("gui.update.finished")); - console.log(lang("cli.update.finished")); - cli.exit(); - }) + fs.createReadStream(settings.zip).pipe(unzip.Extract({ path: settings.gamepath })) + .on("finish", () => { + fs.writeFileSync(path.join(settings.gamepath, "ns_version.txt"), latestAvailableVersion); + ipcMain.emit("get-version"); + + restoreExcludedFiles(); + + ipcMain.emit("gui-getmods"); + ipcMain.emit("ns-update-event", "cli.update.uptodate.short"); + winLog(lang("gui.update.finished")); + console.log(lang("cli.update.finished")); + cli.exit(); + }) }) }) } @@ -390,7 +392,7 @@ async function update() { function updatevp(autoinstall) { const { autoUpdater } = require("electron-updater"); - if (! autoUpdater.isUpdaterActive()) { + if (!autoUpdater.isUpdaterActive()) { if (settings.nsupdate) { handleNorthstarUpdating(); } @@ -403,7 +405,7 @@ function updatevp(autoinstall) { }); } - autoUpdater.on("error", (info) => {cli.exit(1)}); + autoUpdater.on("error", (info) => { cli.exit(1) }); autoUpdater.on("update-not-available", (info) => { // only check for NS updates if Viper itself has no updates and // if NS auto updates is enabled. @@ -429,7 +431,7 @@ function launch(version) { } process.chdir(settings.gamepath); - switch(version) { + switch (version) { case "vanilla": console.log(lang("general.launching"), "Vanilla..."); run(path.join(settings.gamepath + "/Titanfall2.exe")); @@ -471,8 +473,8 @@ const mods = { let enabled = []; let disabled = []; - if (! fs.existsSync(modpath)) { - fs.mkdirSync(path.join(modpath), {recursive: true}); + if (!fs.existsSync(modpath)) { + fs.mkdirSync(path.join(modpath), { recursive: true }); return { enabled: [], disabled: [], @@ -491,9 +493,10 @@ const mods = { Version: "unknown", Name: "unknown", FolderName: file, - ...mod} + ...mod + } - obj.Disabled = ! mods.modfile().get(obj.Name); + obj.Disabled = !mods.modfile().get(obj.Name); let manifestfile = path.join(modpath, file, "manifest.json"); if (fs.existsSync(manifestfile)) { @@ -542,7 +545,7 @@ const mods = { for (let i = 0; i < list.length; i++) { if (list[i].Name == mod) { return list[i]; - } else {continue} + } else { continue } } return false; @@ -556,11 +559,11 @@ const mods = { let modpath = path.join(settings.gamepath, "R2Northstar/mods"); let file = path.join(modpath, "..", "enabledmods.json"); - if (! fs.existsSync(modpath)) { - fs.mkdirSync(path.join(modpath), {recursive: true}); + if (!fs.existsSync(modpath)) { + fs.mkdirSync(path.join(modpath), { recursive: true }); } - if (! fs.existsSync(file)) { + if (!fs.existsSync(file)) { fs.writeFileSync(file, "{}"); } @@ -587,7 +590,7 @@ const mods = { toggle: (mod) => { let data = JSON.parse(repair(fs.readFileSync(file, "utf8"))); if (data[mod] != undefined) { - data[mod] = ! data[mod]; + data[mod] = !data[mod]; } else { data[mod] = false; } @@ -653,19 +656,19 @@ const mods = { return true; } - if (! fs.existsSync(mod)) {return notamod()} + if (!fs.existsSync(mod)) { return notamod() } if (fs.statSync(mod).isDirectory()) { winLog(lang("gui.mods.installing")); files = fs.readdirSync(mod); - if (fs.existsSync(path.join(mod, "mod.json")) && + if (fs.existsSync(path.join(mod, "mod.json")) && fs.statSync(path.join(mod, "mod.json")).isFile()) { if (fs.existsSync(path.join(modpath, modname))) { - fs.rmSync(path.join(modpath, modname), {recursive: true}); + fs.rmSync(path.join(modpath, modname), { recursive: true }); } let copydest = path.join(modpath, modname); - if (typeof destname == "string") {copydest = path.join(modpath, destname)} + if (typeof destname == "string") { copydest = path.join(modpath, destname) } copy(mod, copydest); copy(manifestfile, path.join(copydest, "manifest.json")); @@ -679,7 +682,7 @@ const mods = { fs.statSync(path.join(mod, files[i], "mod.json")).isFile()) { mods.install(path.join(mod, files[i])); - if (mods.install(path.join(mod, files[i]))) {return true}; + if (mods.install(path.join(mod, files[i]))) { return true }; } } } @@ -692,52 +695,52 @@ const mods = { winLog(lang("gui.mods.extracting")); let cache = path.join(app.getPath("userData"), "Archives"); if (fs.existsSync(cache)) { - fs.rmSync(cache, {recursive: true}); - fs.mkdirSync(path.join(cache, "mods"), {recursive: true}); + fs.rmSync(cache, { recursive: true }); + fs.mkdirSync(path.join(cache, "mods"), { recursive: true }); } else { - fs.mkdirSync(path.join(cache, "mods"), {recursive: true}); + fs.mkdirSync(path.join(cache, "mods"), { recursive: true }); } try { if (mod.replace(/.*\./, "").toLowerCase() == "zip") { - fs.createReadStream(mod).pipe(unzip.Extract({path: cache})) - .on("finish", () => { - setTimeout(() => { - let manifest = path.join(cache, "manifest.json"); - if (fs.existsSync(manifest)) { - files = fs.readdirSync(path.join(cache, "mods")); - if (fs.existsSync(path.join(cache, "mods/mod.json"))) { - if (mods.install(path.join(cache, "mods"), require(manifest).name, manifest, true)) { - return true; - } - } else { - for (let i = 0; i < files.length; i++) { - let mod = path.join(cache, "mods", files[i]); - if (fs.statSync(mod).isDirectory()) { - setTimeout(() => { - if (mods.install(mod, false, manifest)) {return true}; - }, 1000) + fs.createReadStream(mod).pipe(unzip.Extract({ path: cache })) + .on("finish", () => { + setTimeout(() => { + let manifest = path.join(cache, "manifest.json"); + if (fs.existsSync(manifest)) { + files = fs.readdirSync(path.join(cache, "mods")); + if (fs.existsSync(path.join(cache, "mods/mod.json"))) { + if (mods.install(path.join(cache, "mods"), require(manifest).name, manifest, true)) { + return true; + } + } else { + for (let i = 0; i < files.length; i++) { + let mod = path.join(cache, "mods", files[i]); + if (fs.statSync(mod).isDirectory()) { + setTimeout(() => { + if (mods.install(mod, false, manifest)) { return true }; + }, 1000) + } } - } - if (files.length == 0) { - ipcMain.emit("failed-mod"); - return notamod(); + if (files.length == 0) { + ipcMain.emit("failed-mod"); + return notamod(); + } } - } - return notamod(); - } + return notamod(); + } - if (mods.install(cache)) { - installed(); - } else {return notamod()} - }, 1000) - }); + if (mods.install(cache)) { + installed(); + } else { return notamod() } + }, 1000) + }); } else { return notamod(); } - }catch(err) {return notamod()} + } catch (err) { return notamod() } } }, @@ -751,7 +754,7 @@ const mods = { let modlocation = path.join(tmp, "/mod.zip"); if (fs.existsSync(tmp)) { - if (! fs.statSync(tmp).isDirectory()) { + if (!fs.statSync(tmp).isDirectory()) { fs.rmSync(tmp); } } else { @@ -794,12 +797,12 @@ const mods = { } let disabled = path.join(modpath, "disabled"); - if (! fs.existsSync(disabled)) { + if (!fs.existsSync(disabled)) { fs.mkdirSync(disabled); } let modName = mods.get(mod).FolderName; - if (! modName) { + if (!modName) { console.log("error: " + lang("cli.mods.cantfind")); cli.exit(1); return; @@ -817,7 +820,7 @@ const mods = { manifestname = require(path.join(modPath, "manifest.json")).name; } - fs.rmSync(modPath, {recursive: true}); + fs.rmSync(modPath, { recursive: true }); console.log(lang("cli.mods.removed")); cli.exit(); ipcMain.emit("gui-getmods"); @@ -856,7 +859,7 @@ const mods = { } mods.modfile().toggle(mod); - if (! fork) { + if (!fork) { console.log(lang("cli.mods.toggled")); cli.exit(); } @@ -889,6 +892,8 @@ module.exports = { getNSVersion, getTF2Version, isGameRunning, + isOriginRunning, + killOrigin, gamepathExists, handleNorthstarUpdating, setlang: (lang) => { |