aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/FUNDING.yml2
-rw-r--r--FAQ.md31
-rw-r--r--README.md24
-rw-r--r--assets/download.pngbin0 -> 11474 bytes
-rw-r--r--assets/preview.pngbin256849 -> 257265 bytes
-rw-r--r--build/langs.js16
-rw-r--r--package-lock.json827
-rw-r--r--package.json6
-rw-r--r--src/app/browser.js264
-rw-r--r--src/app/icons/no-image.pngbin0 -> 1959 bytes
-rw-r--r--src/app/icons/viper.pngbin137107 -> 59028 bytes
-rw-r--r--src/app/index.html18
-rw-r--r--src/app/main.css298
-rw-r--r--src/app/main.js23
-rw-r--r--src/app/toast.js59
-rw-r--r--src/assets/icons/512x512.pngbin137107 -> 59028 bytes
-rw-r--r--src/assets/icons/icon.icobin201799 -> 194797 bytes
-rw-r--r--src/extras/findgame.js67
-rw-r--r--src/extras/requests.js (renamed from src/requests.js)0
-rw-r--r--src/index.js16
-rw-r--r--src/lang/en.json21
-rw-r--r--src/lang/es.json119
-rw-r--r--src/lang/fr.json21
-rw-r--r--src/lang/maintainers.json13
-rw-r--r--src/utils.js240
25 files changed, 1572 insertions, 493 deletions
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index 96f466a..8991fb3 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1,2 +1,2 @@
liberapay: 0neGal
-custom: ["https://github.com/R2Northstar"]
+custom: ["github.com/R2Northstar"]
diff --git a/FAQ.md b/FAQ.md
new file mode 100644
index 0000000..3d78f90
--- /dev/null
+++ b/FAQ.md
@@ -0,0 +1,31 @@
+## Frequently Asked Questions (FAQ)
+
+### How do I install Viper?
+
+As briefly covered in the README, you've multiple choices for installing Viper.
+
+#### Windows
+
+There's the installer, and the portable exe, we recommend using the installer as it can auto update, there's a Download button on the README which downloads the newest version of the installer.
+
+#### Linux
+
+On the [releases page](https://github.com/0neGal/viper/releases/latest) there are various package distributions we release, feel free to pick any one of them, but as with Windows only one of them supports auto-installation, that one being the AppImage.
+
+#### After Install
+
+After you've gotten Viper installed you'll select your game path (this may or may not be done automatically, however if we can't find your game automatically we'll ask you to select it manually), then go onto the Northstar tab, click "Install", and now you can launch Northstar and have fun on the frontier.
+
+If you keep getting errors about your game path being wrong follow the [instructions further below...](#this-folder-is-not-a-valid-game-path)
+
+### How do I install mods?
+
+We recommend using Thunderstore, which allows you to easily find mods and install them, to do so simply go into the Northstar tab, then go into the Mods section, and there'll be a button aptly named **"Find Mods"**, clicking it will open an easy to use UI that'll let you search for mods and install them.
+
+### "This folder is not a valid game path."
+
+When selecting a game path make sure it actually is *the game path*. Your game path is where the `Titanfall2.exe` is located, usually inside `C:\Program Files (x86)\Origin Games\Titanfall2`, however if you've installed the game somewhere else or you've installed the game through Steam it may be located somewhere else.
+
+For Steam users, you can inside Steam right click on the game, click **Properties**, then in the window that opens **Local Files**, then **Browse**, the folder that it opens is the game path.
+
+Ideally Viper should be able to find Titanfall automatically, however given we can't predict every installation of the game we can't always find the game.
diff --git a/README.md b/README.md
index bc82b23..5650c12 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,9 @@
<p align="center">
- <img src="src/assets/icons/512x512.png" width="200px"><br><br>
+ <img src="src/assets/icons/512x512.png" width="200px"><br>
+ <a href="https://github.com/0neGal/viper/releases/download/v1.2.1/Viper-Setup-1.2.1.exe"><img src="assets/download.png" width="300px"></a><br>
<a href="https://github.com/0neGal/viper/projects/1">Overview</a> |
- <a href="https://github.com/0neGal/viper/releases">Releases</a>
-</p><br><br>
+ <a href="https://github.com/0neGal/viper/releases">Releases</a><br>
+</p>
## What is Viper?
@@ -14,9 +15,9 @@ Downloads are available on the [releases page](https://github.com/0neGal/viper/r
Please note that some versions will update themselves automatically when a new release is available (just like Origin or Steam) and some will NOT, so choose it accordingly. Only the AppImage and Windows Setup/Installer can auto-update.
-**Windows:** `Viper Setup [x.y.z].exe` (auto-updates, and is recommanded), `Viper [x.y.z].exe` (single executable, no fuss)
+**Windows:** [`Viper Setup [x.y.z].exe`](https://github.com/0neGal/viper/releases/download/v1.2.1/Viper-Setup-1.2.1.exe) (auto-updates, and is recommanded), [`Viper [x.y.z].exe`](https://github.com/0neGal/viper/releases/download/v1.2.1/Viper-1.2.1.exe) (single executable, no fuss)
-**Linux:** `.AppImage` (auto-updates), `.deb`, `.rpm`, `.snap`, `.tar.gz`
+**Linux:** [`.AppImage`](https://github.com/0neGal/viper/releases/download/v1.2.1/Viper-1.2.1.AppImage) (auto-updates), [`.deb`](https://github.com/0neGal/viper/releases/download/v1.2.1/viper-1.2.1_amd64.deb), [`.rpm`](https://github.com/0neGal/viper/releases/download/v1.2.1/Viper-1.2.1.x86_64.rpm), [`.tar.gz`](https://github.com/0neGal/viper/releases/download/v1.2.1/Viper-1.2.1.tar.gz)
## What can it do specifically?
@@ -40,6 +41,19 @@ Almost all configuration takes place inside the UI, and almost no configuration
Your configuration file will be found in `%APPDATA%\viper.json` on Windows, and inside either `~/.config` or through your environment variables (`$XDG_CONFIG_HOME`) on Linux, the latter has priority.
+## Contact/Support
+
+To get support either open a GitHub issue.<br>
+Or if you must you can contact a developer through the methods below:
+
+Ways to contact the main developer: [0neGal](https://github.com/0neGal)
+ * Twitter: [@0neGal](https://twitter.com/0neGal)
+ * Reddit: [/u/0neGal](https://reddit.com/u/0neGal)
+
+### Frequently Asked Questions (FAQ)
+
+Many of the questions and problems you may have might be able to be answered by reading the [FAQ page](FAQ.md). So before opening an issue or asking for support please read through it first!
+
## Sidenote
Given that we already have so many Northstar updaters and launchers I urge people to instead of creating new launchers unless there's a very specific reason, just make a pull request on one of the existing, otherwise we'll continue to have new ones.
diff --git a/assets/download.png b/assets/download.png
new file mode 100644
index 0000000..52bef5d
--- /dev/null
+++ b/assets/download.png
Binary files differ
diff --git a/assets/preview.png b/assets/preview.png
index 2602337..572bd04 100644
--- a/assets/preview.png
+++ b/assets/preview.png
Binary files differ
diff --git a/build/langs.js b/build/langs.js
index 0e82022..9e21dff 100644
--- a/build/langs.js
+++ b/build/langs.js
@@ -1,10 +1,14 @@
const fs = require("fs");
let lang = require("../src/lang/en.json");
+let maintainers = require("../src/lang/maintainers.json");
langs = fs.readdirSync("src/lang")
langs.forEach((localefile) => {
+ if (localefile == "maintainers.json") {return}
+
let missing = [];
+ let langmaintainers = maintainers.list[localefile.replace(/\..*$/, "")];
let locale = require("../src/lang/" + localefile)
for (let i in lang) {
if (! locale[i]) {
@@ -13,6 +17,16 @@ langs.forEach((localefile) => {
}
if (missing.length > 0) {
- console.error(`${localefile} is missing: ${missing}`)
+ console.error(`${localefile} is missing:`)
+ for (let i in missing) {
+ console.log(` ${missing[i]}`)
+ }
+
+ console.log()
+
+ console.log("Maintainers of language: ")
+ for (let i in langmaintainers) {
+ console.log(` ${langmaintainers[i]}`)
+ }
}
})
diff --git a/package-lock.json b/package-lock.json
index 432c584..92141bf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,20 +1,22 @@
{
"name": "viper",
- "version": "1.0.1",
+ "version": "1.2.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "viper",
- "version": "1.0.1",
+ "version": "1.2.1",
"license": "GPL-3.0-or-later",
"dependencies": {
- "copy-dir": "^1.3.0",
"electron-updater": "^4.6.1",
"follow-redirects": "^1.14.7",
"fs-extra": "^10.0.0",
+ "fuse.js": "^6.5.3",
"marked": "^4.0.10",
"marked-man": "^0.7.0",
+ "recursive-copy": "^2.0.13",
+ "simple-vdf": "^1.1.1",
"unzipper": "^0.10.11"
},
"devDependencies": {
@@ -245,29 +247,11 @@
"integrity": "sha512-fqtSN5xn/bBzDxMT77C1rJg6CsH/R49E7qsGuvdPJa20HtV5zSTuLJPNfnlyVH3wauKnkHdLggTVkOW/xP9oQg==",
"dev": true
},
- "node_modules/@types/plist": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.2.tgz",
- "integrity": "sha512-ULqvZNGMv0zRFvqn8/4LSPtnmN4MfhlPNtJCTpKuIIxGVGZ2rYWzFXrvEBoh9CVyqSE7D6YFRJ1hydLHI6kbWw==",
- "dev": true,
- "optional": true,
- "dependencies": {
- "@types/node": "*",
- "xmlbuilder": ">=11.0.1"
- }
- },
"node_modules/@types/semver": {
"version": "7.3.9",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz",
"integrity": "sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ=="
},
- "node_modules/@types/verror": {
- "version": "1.10.5",
- "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.5.tgz",
- "integrity": "sha512-9UjMCHK5GPgQRoNbqdLIAvAy0EInuiqbW0PBMtVP6B5B2HQJlvoJHM+KodPZMEjOa5VkSc+5LH7xy+cUzQdmHw==",
- "dev": true,
- "optional": true
- },
"node_modules/@types/yargs": {
"version": "17.0.8",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.8.tgz",
@@ -423,6 +407,46 @@
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
+ "node_modules/array-differ": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
+ "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/array-union": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+ "dependencies": {
+ "array-uniq": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/array-uniq": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/arrify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
+ },
"node_modules/asar": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/asar/-/asar-3.1.0.tgz",
@@ -444,26 +468,6 @@
"@types/glob": "^7.1.1"
}
},
- "node_modules/assert-plus": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
- "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
- "dev": true,
- "optional": true,
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/astral-regex": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
- "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
- "dev": true,
- "optional": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/async": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
@@ -609,31 +613,6 @@
"concat-map": "0.0.1"
}
},
- "node_modules/buffer": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
- "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "optional": true,
- "dependencies": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.1.13"
- }
- },
"node_modules/buffer-alloc": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
@@ -836,23 +815,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/cli-truncate": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
- "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
- "dev": true,
- "optional": true,
- "dependencies": {
- "slice-ansi": "^3.0.0",
- "string-width": "^4.2.0"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
@@ -978,26 +940,11 @@
"node": ">=8"
}
},
- "node_modules/copy-dir": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/copy-dir/-/copy-dir-1.3.0.tgz",
- "integrity": "sha512-Q4+qBFnN4bwGwvtXXzbp4P/4iNk0MaiGAzvQ8OiMtlLjkIKjmNN689uVzShSM0908q7GoFHXIPx4zi75ocoaHw=="
- },
"node_modules/core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
},
- "node_modules/crc": {
- "version": "3.8.0",
- "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz",
- "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==",
- "dev": true,
- "optional": true,
- "dependencies": {
- "buffer": "^5.1.0"
- }
- },
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -1077,6 +1024,31 @@
"node": ">= 0.4"
}
},
+ "node_modules/del": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
+ "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
+ "dependencies": {
+ "globby": "^5.0.0",
+ "is-path-cwd": "^1.0.0",
+ "is-path-in-cwd": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0",
+ "rimraf": "^2.2.8"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/del/node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -1137,32 +1109,6 @@
"dmg-license": "^1.0.9"
}
},
- "node_modules/dmg-license": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.10.tgz",
- "integrity": "sha512-SVeeyiOeinV5JCPHXMdKOgK1YVbak/4+8WL2rBnfqRYpA5FaeFaQnQWb25x628am1w70CbipGDv9S51biph63A==",
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "dependencies": {
- "@types/plist": "^3.0.1",
- "@types/verror": "^1.10.3",
- "ajv": "^6.10.0",
- "crc": "^3.8.0",
- "iconv-corefoundation": "^1.1.7",
- "plist": "^3.0.4",
- "smart-buffer": "^4.0.2",
- "verror": "^1.10.0"
- },
- "bin": {
- "dmg-license": "bin/dmg-license.js"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/dot-prop": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
@@ -1396,6 +1342,17 @@
"node": ">=6"
}
},
+ "node_modules/errno": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
+ "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
+ "dependencies": {
+ "prr": "~1.0.1"
+ },
+ "bin": {
+ "errno": "cli.js"
+ }
+ },
"node_modules/es6-error": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
@@ -1464,16 +1421,6 @@
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
"dev": true
},
- "node_modules/extsprintf": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
- "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
- "dev": true,
- "engines": [
- "node >=0.6.0"
- ],
- "optional": true
- },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -1541,6 +1488,14 @@
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
+ "node_modules/fuse.js": {
+ "version": "6.5.3",
+ "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.5.3.tgz",
+ "integrity": "sha512-sA5etGE7yD/pOqivZRBvUBd/NaL2sjAu6QuSaFoe1H2BrJSkH/T/UXAJ8CdXdw7DvY3Hs8CXKYkDWX7RiP5KOg==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
@@ -1671,6 +1626,30 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/globby": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
+ "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
+ "dependencies": {
+ "array-union": "^1.0.1",
+ "arrify": "^1.0.0",
+ "glob": "^7.0.3",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/globby/node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/got": {
"version": "9.6.0",
"resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
@@ -1740,23 +1719,6 @@
"integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==",
"dev": true
},
- "node_modules/iconv-corefoundation": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz",
- "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==",
- "dev": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "dependencies": {
- "cli-truncate": "^2.1.0",
- "node-addon-api": "^1.6.3"
- },
- "engines": {
- "node": "^8.11.2 || >=10"
- }
- },
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@@ -1769,27 +1731,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/ieee754": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "optional": true
- },
"node_modules/import-lazy": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz",
@@ -1886,6 +1827,36 @@
"node": ">=8"
}
},
+ "node_modules/is-path-cwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
+ "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-path-in-cwd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz",
+ "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
+ "dependencies": {
+ "is-path-inside": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-path-in-cwd/node_modules/is-path-inside": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
+ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
+ "dependencies": {
+ "path-is-inside": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/is-path-inside": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
@@ -2075,6 +2046,14 @@
"graceful-fs": "^4.1.6"
}
},
+ "node_modules/junk": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/junk/-/junk-1.0.3.tgz",
+ "integrity": "sha1-h75jSIZJy9ym9Tqzm+yczSNH9ZI=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/keyv": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz",
@@ -2192,6 +2171,20 @@
"node": ">=10"
}
},
+ "node_modules/maximatch": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/maximatch/-/maximatch-0.1.0.tgz",
+ "integrity": "sha1-hs2NawTJ8wfAWmuUGZBtA2D7E6I=",
+ "dependencies": {
+ "array-differ": "^1.0.0",
+ "array-union": "^1.0.1",
+ "arrify": "^1.0.0",
+ "minimatch": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/mime": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
@@ -2266,13 +2259,6 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
- "node_modules/node-addon-api": {
- "version": "1.7.2",
- "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz",
- "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==",
- "dev": true,
- "optional": true
- },
"node_modules/normalize-url": {
"version": "4.5.1",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz",
@@ -2296,6 +2282,14 @@
"node": ">=4"
}
},
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
@@ -2346,6 +2340,11 @@
"node": ">=0.10.0"
}
},
+ "node_modules/path-is-inside": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM="
+ },
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@@ -2371,6 +2370,25 @@
"node": ">=4"
}
},
+ "node_modules/pinkie": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pinkie-promise": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+ "dependencies": {
+ "pinkie": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/plist": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.0.4.tgz",
@@ -2416,6 +2434,14 @@
"node": ">=0.4.0"
}
},
+ "node_modules/promise": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
+ "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
+ "dependencies": {
+ "asap": "~2.0.3"
+ }
+ },
"node_modules/proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
@@ -2423,6 +2449,11 @@
"dev": true,
"optional": true
},
+ "node_modules/prr": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
+ "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY="
+ },
"node_modules/pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
@@ -2499,6 +2530,30 @@
"util-deprecate": "~1.0.1"
}
},
+ "node_modules/recursive-copy": {
+ "version": "2.0.13",
+ "resolved": "https://registry.npmjs.org/recursive-copy/-/recursive-copy-2.0.13.tgz",
+ "integrity": "sha512-BjmE6R/dOImStEku+017L3Z0I6u/lA+SVr1sySWbTLjmQKDTESNmJ9WBZP8wbN5FuvqNvSYvRKA/IKQhAjqnpQ==",
+ "dependencies": {
+ "del": "^2.2.0",
+ "errno": "^0.1.2",
+ "graceful-fs": "^4.1.4",
+ "junk": "^1.0.1",
+ "maximatch": "^0.1.0",
+ "mkdirp": "^0.5.1",
+ "pify": "^2.3.0",
+ "promise": "^7.0.1",
+ "slash": "^1.0.0"
+ }
+ },
+ "node_modules/recursive-copy/node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/registry-auth-token": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz",
@@ -2671,30 +2726,17 @@
"integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==",
"dev": true
},
- "node_modules/slice-ansi": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
- "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
- "dev": true,
- "optional": true,
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
+ "node_modules/simple-vdf": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/simple-vdf/-/simple-vdf-1.1.1.tgz",
+ "integrity": "sha1-B+LE3sBs9hTtb0IRsYzOEjyT/Kk="
},
- "node_modules/smart-buffer": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
- "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
- "dev": true,
- "optional": true,
+ "node_modules/slash": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
"engines": {
- "node": ">= 6.0.0",
- "npm": ">= 3.0.0"
+ "node": ">=0.10.0"
}
},
"node_modules/source-map": {
@@ -3053,28 +3095,6 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
- "node_modules/verror": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
- "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
- "dev": true,
- "engines": [
- "node >=0.6.0"
- ],
- "optional": true,
- "dependencies": {
- "assert-plus": "^1.0.0",
- "core-util-is": "1.0.2",
- "extsprintf": "^1.2.0"
- }
- },
- "node_modules/verror/node_modules/core-util-is": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
- "dev": true,
- "optional": true
- },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -3145,16 +3165,6 @@
"node": ">=8"
}
},
- "node_modules/xmlbuilder": {
- "version": "15.1.1",
- "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
- "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==",
- "dev": true,
- "optional": true,
- "engines": {
- "node": ">=8.0"
- }
- },
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
@@ -3388,29 +3398,11 @@
"integrity": "sha512-fqtSN5xn/bBzDxMT77C1rJg6CsH/R49E7qsGuvdPJa20HtV5zSTuLJPNfnlyVH3wauKnkHdLggTVkOW/xP9oQg==",
"dev": true
},
- "@types/plist": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.2.tgz",
- "integrity": "sha512-ULqvZNGMv0zRFvqn8/4LSPtnmN4MfhlPNtJCTpKuIIxGVGZ2rYWzFXrvEBoh9CVyqSE7D6YFRJ1hydLHI6kbWw==",
- "dev": true,
- "optional": true,
- "requires": {
- "@types/node": "*",
- "xmlbuilder": ">=11.0.1"
- }
- },
"@types/semver": {
"version": "7.3.9",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz",
"integrity": "sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ=="
},
- "@types/verror": {
- "version": "1.10.5",
- "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.5.tgz",
- "integrity": "sha512-9UjMCHK5GPgQRoNbqdLIAvAy0EInuiqbW0PBMtVP6B5B2HQJlvoJHM+KodPZMEjOa5VkSc+5LH7xy+cUzQdmHw==",
- "dev": true,
- "optional": true
- },
"@types/yargs": {
"version": "17.0.8",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.8.tgz",
@@ -3541,6 +3533,34 @@
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
+ "array-differ": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
+ "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE="
+ },
+ "array-union": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
+ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
+ "requires": {
+ "array-uniq": "^1.0.1"
+ }
+ },
+ "array-uniq": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY="
+ },
+ "arrify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0="
+ },
+ "asap": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
+ "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
+ },
"asar": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/asar/-/asar-3.1.0.tgz",
@@ -3554,20 +3574,6 @@
"minimatch": "^3.0.4"
}
},
- "assert-plus": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
- "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
- "dev": true,
- "optional": true
- },
- "astral-regex": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
- "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
- "dev": true,
- "optional": true
- },
"async": {
"version": "0.9.2",
"resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
@@ -3679,17 +3685,6 @@
"concat-map": "0.0.1"
}
},
- "buffer": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
- "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
- "dev": true,
- "optional": true,
- "requires": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.1.13"
- }
- },
"buffer-alloc": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
@@ -3846,17 +3841,6 @@
"integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==",
"dev": true
},
- "cli-truncate": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
- "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
- "dev": true,
- "optional": true,
- "requires": {
- "slice-ansi": "^3.0.0",
- "string-width": "^4.2.0"
- }
- },
"cliui": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
@@ -3961,26 +3945,11 @@
"xdg-basedir": "^4.0.0"
}
},
- "copy-dir": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/copy-dir/-/copy-dir-1.3.0.tgz",
- "integrity": "sha512-Q4+qBFnN4bwGwvtXXzbp4P/4iNk0MaiGAzvQ8OiMtlLjkIKjmNN689uVzShSM0908q7GoFHXIPx4zi75ocoaHw=="
- },
"core-util-is": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
},
- "crc": {
- "version": "3.8.0",
- "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz",
- "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==",
- "dev": true,
- "optional": true,
- "requires": {
- "buffer": "^5.1.0"
- }
- },
"cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -4037,6 +4006,27 @@
"object-keys": "^1.0.12"
}
},
+ "del": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
+ "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
+ "requires": {
+ "globby": "^5.0.0",
+ "is-path-cwd": "^1.0.0",
+ "is-path-in-cwd": "^1.0.0",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0",
+ "rimraf": "^2.2.8"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
+ }
+ }
+ },
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -4088,23 +4078,6 @@
"js-yaml": "^4.1.0"
}
},
- "dmg-license": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.10.tgz",
- "integrity": "sha512-SVeeyiOeinV5JCPHXMdKOgK1YVbak/4+8WL2rBnfqRYpA5FaeFaQnQWb25x628am1w70CbipGDv9S51biph63A==",
- "dev": true,
- "optional": true,
- "requires": {
- "@types/plist": "^3.0.1",
- "@types/verror": "^1.10.3",
- "ajv": "^6.10.0",
- "crc": "^3.8.0",
- "iconv-corefoundation": "^1.1.7",
- "plist": "^3.0.4",
- "smart-buffer": "^4.0.2",
- "verror": "^1.10.0"
- }
- },
"dot-prop": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
@@ -4294,6 +4267,14 @@
"integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
"dev": true
},
+ "errno": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
+ "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
+ "requires": {
+ "prr": "~1.0.1"
+ }
+ },
"es6-error": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
@@ -4349,13 +4330,6 @@
}
}
},
- "extsprintf": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
- "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
- "dev": true,
- "optional": true
- },
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -4406,6 +4380,11 @@
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
+ "fuse.js": {
+ "version": "6.5.3",
+ "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.5.3.tgz",
+ "integrity": "sha512-sA5etGE7yD/pOqivZRBvUBd/NaL2sjAu6QuSaFoe1H2BrJSkH/T/UXAJ8CdXdw7DvY3Hs8CXKYkDWX7RiP5KOg=="
+ },
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
@@ -4501,6 +4480,26 @@
"define-properties": "^1.1.3"
}
},
+ "globby": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
+ "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
+ "requires": {
+ "array-union": "^1.0.1",
+ "arrify": "^1.0.0",
+ "glob": "^7.0.3",
+ "object-assign": "^4.0.1",
+ "pify": "^2.0.0",
+ "pinkie-promise": "^2.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
+ }
+ }
+ },
"got": {
"version": "9.6.0",
"resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz",
@@ -4558,17 +4557,6 @@
"integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==",
"dev": true
},
- "iconv-corefoundation": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz",
- "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==",
- "dev": true,
- "optional": true,
- "requires": {
- "cli-truncate": "^2.1.0",
- "node-addon-api": "^1.6.3"
- }
- },
"iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
@@ -4578,13 +4566,6 @@
"safer-buffer": ">= 2.1.2 < 3.0.0"
}
},
- "ieee754": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
- "dev": true,
- "optional": true
- },
"import-lazy": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz",
@@ -4654,6 +4635,29 @@
"integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
"dev": true
},
+ "is-path-cwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
+ "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0="
+ },
+ "is-path-in-cwd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz",
+ "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
+ "requires": {
+ "is-path-inside": "^1.0.0"
+ },
+ "dependencies": {
+ "is-path-inside": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
+ "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
+ "requires": {
+ "path-is-inside": "^1.0.1"
+ }
+ }
+ }
+ },
"is-path-inside": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
@@ -4804,6 +4808,11 @@
"universalify": "^2.0.0"
}
},
+ "junk": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/junk/-/junk-1.0.3.tgz",
+ "integrity": "sha1-h75jSIZJy9ym9Tqzm+yczSNH9ZI="
+ },
"keyv": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz",
@@ -4892,6 +4901,17 @@
"escape-string-regexp": "^4.0.0"
}
},
+ "maximatch": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/maximatch/-/maximatch-0.1.0.tgz",
+ "integrity": "sha1-hs2NawTJ8wfAWmuUGZBtA2D7E6I=",
+ "requires": {
+ "array-differ": "^1.0.0",
+ "array-union": "^1.0.1",
+ "arrify": "^1.0.0",
+ "minimatch": "^3.0.0"
+ }
+ },
"mime": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz",
@@ -4945,13 +4965,6 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
- "node-addon-api": {
- "version": "1.7.2",
- "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz",
- "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==",
- "dev": true,
- "optional": true
- },
"normalize-url": {
"version": "4.5.1",
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz",
@@ -4969,6 +4982,11 @@
"pify": "^3.0.0"
}
},
+ "object-assign": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+ },
"object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
@@ -5007,6 +5025,11 @@
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
+ "path-is-inside": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
+ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM="
+ },
"path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@@ -5026,6 +5049,19 @@
"dev": true,
"optional": true
},
+ "pinkie": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+ "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
+ },
+ "pinkie-promise": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+ "requires": {
+ "pinkie": "^2.0.0"
+ }
+ },
"plist": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.0.4.tgz",
@@ -5061,6 +5097,14 @@
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"dev": true
},
+ "promise": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
+ "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
+ "requires": {
+ "asap": "~2.0.3"
+ }
+ },
"proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
@@ -5068,6 +5112,11 @@
"dev": true,
"optional": true
},
+ "prr": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
+ "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY="
+ },
"pump": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
@@ -5132,6 +5181,29 @@
"util-deprecate": "~1.0.1"
}
},
+ "recursive-copy": {
+ "version": "2.0.13",
+ "resolved": "https://registry.npmjs.org/recursive-copy/-/recursive-copy-2.0.13.tgz",
+ "integrity": "sha512-BjmE6R/dOImStEku+017L3Z0I6u/lA+SVr1sySWbTLjmQKDTESNmJ9WBZP8wbN5FuvqNvSYvRKA/IKQhAjqnpQ==",
+ "requires": {
+ "del": "^2.2.0",
+ "errno": "^0.1.2",
+ "graceful-fs": "^4.1.4",
+ "junk": "^1.0.1",
+ "maximatch": "^0.1.0",
+ "mkdirp": "^0.5.1",
+ "pify": "^2.3.0",
+ "promise": "^7.0.1",
+ "slash": "^1.0.0"
+ },
+ "dependencies": {
+ "pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
+ }
+ }
+ },
"registry-auth-token": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz",
@@ -5271,24 +5343,15 @@
"integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==",
"dev": true
},
- "slice-ansi": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
- "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
- "dev": true,
- "optional": true,
- "requires": {
- "ansi-styles": "^4.0.0",
- "astral-regex": "^2.0.0",
- "is-fullwidth-code-point": "^3.0.0"
- }
+ "simple-vdf": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/simple-vdf/-/simple-vdf-1.1.1.tgz",
+ "integrity": "sha1-B+LE3sBs9hTtb0IRsYzOEjyT/Kk="
},
- "smart-buffer": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
- "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
- "dev": true,
- "optional": true
+ "slash": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU="
},
"source-map": {
"version": "0.6.1",
@@ -5580,27 +5643,6 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
- "verror": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
- "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
- "dev": true,
- "optional": true,
- "requires": {
- "assert-plus": "^1.0.0",
- "core-util-is": "1.0.2",
- "extsprintf": "^1.2.0"
- },
- "dependencies": {
- "core-util-is": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
- "dev": true,
- "optional": true
- }
- }
- },
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -5653,13 +5695,6 @@
"integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==",
"dev": true
},
- "xmlbuilder": {
- "version": "15.1.1",
- "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
- "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==",
- "dev": true,
- "optional": true
- },
"y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
diff --git a/package.json b/package.json
index 309dcbb..f53b62a 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "viper",
"productName": "Viper",
- "version": "1.0.2",
+ "version": "1.2.1",
"description": "Launcher+Updater for TF|2 Northstar",
"main": "src/index.js",
"build": {
@@ -48,12 +48,14 @@
},
"homepage": "https://github.com/0neGal/viper#readme",
"dependencies": {
- "copy-dir": "^1.3.0",
"electron-updater": "^4.6.1",
"follow-redirects": "^1.14.7",
"fs-extra": "^10.0.0",
+ "fuse.js": "^6.5.3",
"marked": "^4.0.10",
"marked-man": "^0.7.0",
+ "recursive-copy": "^2.0.13",
+ "simple-vdf": "^1.1.1",
"unzipper": "^0.10.11"
},
"devDependencies": {
diff --git a/src/app/browser.js b/src/app/browser.js
new file mode 100644
index 0000000..ded12fa
--- /dev/null
+++ b/src/app/browser.js
@@ -0,0 +1,264 @@
+const Fuse = require("fuse.js");
+var fuse;
+var packages = [];
+
+var Browser = {
+ maxentries: 50,
+ toggle: (state) => {
+ if (state) {
+ browser.scrollTo(0, 0);
+ overlay.classList.add("shown")
+ browser.classList.add("shown")
+
+ if (browserEntries.querySelectorAll(".el").length == 0) {
+ Browser.loadfront();
+ }
+ return
+ } else if (! state) {
+ if (state != undefined) {
+ overlay.classList.remove("shown")
+ browser.classList.remove("shown")
+ return
+ }
+ }
+
+ browser.scrollTo(0, 0);
+ overlay.classList.toggle("shown")
+ browser.classList.toggle("shown")
+ },
+ loadfront: async () => {
+ Browser.loading();
+
+ if (packages.length < 1) {
+ packages = await (await fetch("https://northstar.thunderstore.io/api/v1/package/")).json();
+
+ fuse = new Fuse(packages, {
+ keys: ["full_name"]
+ })
+ }
+
+ for (let i in packages) {
+ if (i == Browser.maxentries) {Browser.endoflist();break}
+ new BrowserElFromObj(packages[i]);
+ }
+ },
+ loading: (string) => {
+ if (string) {
+ browserEntries.innerHTML = `<div class="loading">${string}</div>`;
+ }
+
+ if (! browserEntries.querySelector(".loading")) {
+ browserEntries.innerHTML = `<div class="loading">${lang('gui.browser.loading')}</div>`;
+ }
+ },
+ endoflist: () => {
+ browserEntries.innerHTML += `<div class="message">${lang('gui.browser.endoflist')}</div>`
+ },
+ search: (string) => {
+ Browser.loading();
+ let res = fuse.search(string);
+
+ if (res.length < 1) {
+ Browser.loading("No results...")
+ return
+ }
+
+ for (let i = 0; i < res.length; i++) {
+ if (i == Browser.maxentries) {Browser.endoflist();break}
+ new BrowserElFromObj(res[i].item);
+ }
+ },
+ setbutton: (mod, string) => {
+ mod = normalize(mod);
+ if (document.getElementById(mod)) {
+ let elems = document.querySelectorAll(`#${mod}`);
+
+ for (let i = 0; i < elems.length; i++) {
+ elems[i].querySelector(".text button").innerHTML = string;
+ }
+ } else {
+ let make = (str) => {
+ if (document.getElementById(str)) {
+ return Browser.setbutton(str, string);
+ } else {
+ return false;
+ }
+ }
+
+ setTimeout(() => {
+ for (let i = 0; i < modsobj.all.length; i++) {
+ let modname = normalize(modsobj.all[i].Name);
+ let modfolder = normalize(modsobj.all[i].FolderName);
+
+ if (mod.includes(modname)) {
+ if (! make(modname)) {
+ if (modsobj.all[i].ManifestName) {
+ make(normalize(modsobj.all[i].ManifestName));
+ }
+ }
+ }
+ else if (mod.includes(modfolder)) {make(modfolder);break}
+ }
+ }, 1501)
+ }
+ }
+}
+
+document.body.addEventListener("keyup", (e) => {
+ if (e.key == "Escape") {Browser.toggle(false)}
+})
+
+function BrowserElFromObj(obj) {
+ let pkg = {...obj, ...obj.versions[0]};
+
+ new BrowserEl({
+ title: pkg.name,
+ image: pkg.icon,
+ author: pkg.owner,
+ url: pkg.package_url,
+ download: pkg.download_url,
+ version: pkg.version_number,
+ description: pkg.description
+ })
+}
+
+function BrowserEl(properties) {
+ properties = {
+ title: "No name",
+ version: "1.0.0",
+ image: "icons/no-image.png",
+ author: "Unnamed Pilot",
+ description: "No description",
+ ...properties
+ }
+
+ if (properties.version[0] != "v") {
+ properties.version = "v" + properties.version;
+ }
+
+ if (browserEntries.querySelector(".loading")) {
+ browserEntries.innerHTML = "";
+ }
+
+ let installstr = lang("gui.browser.install");
+
+ if (normalize(modsdiv.innerText.split("\n")).includes(normalize(properties.title))) {
+ installstr = lang("gui.browser.reinstall");
+
+ for (let i = 0; i < modsobj.all.length; i++) {
+ if (normalize(modsobj.all[i].Name) == normalize(properties.title)
+ && "v" + modsobj.all[i].Version != properties.version) {
+
+ installstr = lang("gui.browser.update");
+ }
+ }
+ } else {
+ for (let i = 0; i < modsobj.all.length; i++) {
+ let title = normalize(properties.title);
+ let folder = normalize(modsobj.all[i].FolderName);
+ let manifestname = null;
+ if (modsobj.all[i].ManifestName) {
+ manifestname = normalize(modsobj.all[i].ManifestName);
+ }
+
+ if (title.includes(folder) || title.includes(manifestname)) {
+ installstr = lang("gui.browser.reinstall");
+
+ if (folder == title
+ && "v" + modsobj.all[i].Version != properties.version) {
+
+ installstr = lang("gui.browser.update");
+ }
+ }
+ }
+ }
+
+ browserEntries.innerHTML += `
+ <div class="el" id="${normalize(properties.title)}">
+ <div class="image">
+ <img src="${properties.image}">
+ </div>
+ <div class="text">
+ <div class="title">${properties.title}</div>
+ <div class="description">${properties.description}</div>
+ <button onclick="installFromURL('${properties.download}')">${installstr}</button>
+ <button onclick="require('electron').shell.openExternal('${properties.url}')">${lang('gui.browser.info')}</button>
+ <button class="visual">${properties.version}</button>
+ <button class="visual">${lang("gui.browser.madeby")} ${properties.author}</button>
+ </div>
+ </div>
+ `
+}
+
+ipcRenderer.on("removedmod", (event, mod) => {
+ setButtons(true);
+ Browser.setbutton(mod.name, lang("gui.browser.install"));
+ if (mod.manifestname) {
+ Browser.setbutton(mod.manifestname, lang("gui.browser.install"));
+ }
+})
+
+ipcRenderer.on("failedmod", (event, modname) => {
+ setButtons(true);
+ new Toast({
+ timeout: 10000,
+ scheme: "error",
+ title: lang("gui.toast.title.failed"),
+ description: lang("gui.toast.desc.failed")
+ })
+})
+
+ipcRenderer.on("installedmod", (event, mod) => {
+ setButtons(true);
+ Browser.setbutton(mod.name, lang("gui.browser.reinstall"));
+
+ if (mod.malformed) {
+ new Toast({
+ timeout: 8000,
+ scheme: "warning",
+ title: lang("gui.toast.title.malformed"),
+ description: mod.name + " " + lang("gui.toast.desc.malformed")
+ })
+ }
+
+ new Toast({
+ scheme: "success",
+ title: lang("gui.toast.title.installed"),
+ description: mod.name + " " + lang("gui.toast.desc.installed")
+ })
+})
+
+function normalize(items) {
+ let main = (string) => {
+ return string.replaceAll(" ", "").replaceAll(".", "").replaceAll("-", "").replaceAll("_", "").toLowerCase()
+ }
+ if (typeof items == "string") {
+ return main(items)
+ } else {
+ let newArray = [];
+ for (let i = 0; i < items.length; i++) {
+ newArray.push(main(items[i]));
+ }
+
+ return newArray;
+ }
+}
+
+let searchtimeout;
+let searchstr = "";
+search.addEventListener("keyup", () => {
+ clearTimeout(searchtimeout);
+
+ if (searchstr != search.value) {
+ if (search.value.replaceAll(" ", "") == "") {
+ searchstr = "";
+ Browser.loadfront();
+ return
+ }
+
+ searchtimeout = setTimeout(() => {
+ Browser.search(search.value);
+ searchstr = search.value;
+ }, 500)
+ }
+})
diff --git a/src/app/icons/no-image.png b/src/app/icons/no-image.png
new file mode 100644
index 0000000..43265d1
--- /dev/null
+++ b/src/app/icons/no-image.png
Binary files differ
diff --git a/src/app/icons/viper.png b/src/app/icons/viper.png
index 281f3dd..69b1cce 100644
--- a/src/app/icons/viper.png
+++ b/src/app/icons/viper.png
Binary files differ
diff --git a/src/app/index.html b/src/app/index.html
index fe383a0..8222416 100644
--- a/src/app/index.html
+++ b/src/app/index.html
@@ -7,11 +7,26 @@
</head>
<body>
<div id="bgHolder"></div>
+ <div id="toasts"></div>
<div id="winbtns">
<div id="minimize" onclick="ipcRenderer.send('minimize')"></div>
<div id="close" onclick="ipcRenderer.send('exit')"></div>
</div>
+
+
+ <div id="overlay" onclick="Browser.toggle(false)"></div>
+ <div id="browser">
+ <div id="misc">
+ <input id="search" placeholder="%%gui.browser.search%%">
+ <button id="close" onclick="Browser.toggle(false)">
+ <img src="icons/close.png">
+ </button>
+ </div>
+ <div id="browserEntries">
+ <div class="loading">%%gui.browser.loading%%</div>
+ </div>
+ </div>
<nav class="gamesContainer">
<button id="vpBtn" onclick="page(0)"></button>
@@ -79,6 +94,7 @@
<button id="togglemod" onclick="selected().toggle()">%%gui.mods.toggle%%</button>
<button id="toggleall" onclick="selected(true).toggle(true)">%%gui.mods.toggleall%%</button>
<button id="installmod" onclick="installmod()">%%gui.mods.install%%</button>
+ <button id="installmod" onclick="Browser.toggle(true)">%%gui.mods.find%%</button>
</div>
</div>
</div>
@@ -102,6 +118,8 @@
<script src="lang.js"></script>
<script src="main.js"></script>
+ <script src="toast.js"></script>
+ <script src="browser.js"></script>
<script src="launcher.js"></script>
</body>
</html>
diff --git a/src/app/main.css b/src/app/main.css
index de0db46..a532490 100644
--- a/src/app/main.css
+++ b/src/app/main.css
@@ -9,7 +9,11 @@
--selbg: rgba(80, 80, 80, 0.5);
--redbg: linear-gradient(45deg, var(--red), #FA4343);
--bluebg: linear-gradient(45deg, var(--blue), #7380ED);
+}
+#browser, #modsdiv {
+ outline: 1px solid #444444;
+ border: 3px solid var(--bg);
}
::-webkit-scrollbar {
@@ -26,12 +30,191 @@
background: var(--red);
}
+::selection {
+ color: black;
+ background: var(--red);
+}
+
+body {
+ margin: 0;
+ overflow: hidden;
+ user-select: none;
+}
+
+body, button, input {font-family: "Roboto", sans-serif}
+
+button {outline: none}
+b, strong {font-weight: 700}
+body, input, button {font-weight: 500}
+
+button {
+ border: none;
+ color: white;
+ outline: none;
+ cursor: pointer;
+ font-weight: 700;
+ padding: 5px 10px;
+ border-radius: 5px;
+ transition: 0.2s ease-in-out;
+}
+
.playBtn, .gamesContainer button, #winbtns div {
cursor: pointer;
}
-#winbtns {
+#browser {
+ --spacing: var(--padding);
+
+ z-index: 2;
+ opacity: 0.0;
+ position: fixed;
+ overflow-y: scroll;
+ top: var(--spacing);
+ pointer-events: none;
+ left: var(--spacing);
+ background: var(--bg);
+ right: var(--spacing);
+ bottom: var(--spacing);
+ transform: scale(0.98);
+ backdrop-filter: blur(15px);
+ border-radius: calc(var(--padding) / 3);
+ transition: opacity 0.15s ease-in-out, transform 0.15s ease-in-out;
+}
+
+#browser.shown {
+ opacity: 1.0;
+ pointer-events: all;
+ transform: scale(1.0);
+}
+
+#overlay {
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
z-index: 1;
+ opacity: 0.0;
+ position: fixed;
+ background: var(--bg);
+ pointer-events: none;
+ transition: opacity 0.15s ease-in-out;
+}
+
+#overlay.shown {
+ opacity: 0.8;
+ pointer-events: all;
+}
+
+@keyframes fadein {
+ 0% {opacity: 0.0}
+ 100% {opacity: 1.0}
+}
+
+#browser .el, #browser #misc, #browser .loading {
+ --spacing: calc(var(--padding) / 2);
+ --height: calc(var(--padding) * 3);
+ --mischeight: calc(var(--padding) * 1.5);
+
+ animation-duration: 0.15s;
+ animation-iteration-count: 1;
+ animation-name: fadein;
+ animation-fill-mode: forwards;
+ animation-timing-function: ease-in-out;
+
+ opacity: 0.0;
+ transition: 0.15s ease-in-out;
+}
+
+#browser .el, #browser #search, #browser #close {
+ color: white;
+ display: flex;
+ align-items: center;
+ height: var(--height);
+ margin: var(--spacing);
+ padding: var(--spacing);
+ background: var(--selbg);
+ border-radius: var(--spacing);
+ width: calc(100% - var(--spacing) * 4);
+}
+
+#browser #misc, #browser #search {
+ --height: var(--mischeight);
+}
+
+#browser #misc {
+ display: flex;
+}
+
+#browser #search {
+ border: none;
+ outline: none;
+ transition: filter 0.15s ease-in-out;
+ width: calc(100% - var(--spacing) * 2);
+}
+
+#browser #search:focus {
+ filter: brightness(1.5);
+}
+
+#browser #close {
+ --height: calc(var(--padding) * 1.5);
+
+ padding: 0px;
+ margin-left: 0px;
+ width: var(--height);
+}
+
+#browser #close img {
+ opacity: 0.6;
+ width: var(--height);
+ height: var(--height);
+ transform: scale(0.6);
+}
+
+#browser .loading {
+ width: 100%;
+ color: white;
+ display: flex;
+ text-align: center;
+ align-items: center;
+ justify-content: center;
+ height: calc(100% - var(--mischeight) - var(--height));
+}
+
+#browser .message {
+ color: white;
+ text-align: center;
+ margin: var(--padding);
+ width: calc(100% - var(--padding));
+}
+
+#browser .el .image, #browser .el .image img {
+ width: var(--height);
+ height: var(--height);
+ margin-right: var(--spacing);
+ border-radius: var(--spacing);
+}
+
+#browser .el .text {
+ overflow: hidden;
+}
+
+#browser .el .title, #browser .el .description {
+ height: 1.2em;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+
+#browser .el .title {font-size: 1.2em}
+#browser .el .description {font-size: 0.8em}
+#browser .el button {
+ background: var(--blue);
+ margin-top: var(--spacing);
+}
+
+#winbtns {
+ z-index: 2;
display: flex;
position: fixed;
top: var(--padding);
@@ -54,40 +237,18 @@
#winbtns div:hover {opacity: 1.0}
#winbtns div:active {transform: scale(0.98)}
-body {
- margin: 0;
- overflow: hidden;
- user-select: none;
- font-family: "Roboto", sans-serif;
-}
-
-button {outline: none}
-b, strong {font-weight: 700}
-body, input, button {font-weight: 500}
-
-button {
- border: none;
- color: white;
- outline: none;
- font-weight: 700;
- padding: 5px 10px;
- border-radius: 5px;
- transition: 0.2s ease-in-out;
-}
-
button:hover {filter: brightness(110%)}
button:active {filter: brightness(90%)}
img {pointer-events: none}
#bgHolder {
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- pointer-events: none;
- position: fixed;
- transform: scale(1.1);
+ top: -5px;
+ left: -5px;
+ right: -5px;
+ bottom: -5px;
+ z-index: -1;
+ position: absolute;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
@@ -162,7 +323,7 @@ img {pointer-events: none}
}
.contentContainer {
- width: 90%;
+ width: 85%;
color: white;
flex-grow: 1;
opacity: 1.0;
@@ -346,6 +507,12 @@ button:disabled {
pointer-events: none;
}
+button.visual {
+ opacity: 1.0;
+ pointer-events: none;
+ background: transparent !important;
+}
+
code {
font-size: 16px;
padding: 2px 5px;
@@ -385,16 +552,81 @@ code {
}
.modbtns button {
- margin-left: calc(var(--padding) / 3);
+ margin-left: var(--spacing);
+ --spacing: calc(var(--padding) / 3);
+ margin-top: calc(var(--spacing) / 2);
+ margin-bottom: calc(var(--spacing) / 2);
+}
+
+#toasts {
+ position: fixed;
+ z-index: 100000;
+ right: calc(var(--padding) * 1.5);
+ bottom: calc(var(--padding) * 1.5);
+}
+
+@keyframes bodyfadeaway {
+ 0% {opacity: 0.0; transform: scale(0.95)}
+ 100% {opacity: 1.0; transform: scale(1.0)}
+}
+
+#toasts .toast {
+ width: 300px;
+ opacity: 0.0;
+ cursor: pointer;
+ overflow: hidden;
+ max-height: 100vh;
+ background: #FFFFFF;
+ transform: scale(0.95);
+ transition: 0.2s ease-in-out;
+ padding: calc(var(--padding) / 2);
+ margin-top: calc(var(--padding) / 2);
+ border-radius: calc(var(--padding) / 2.5);
+ box-shadow: 0px 5px 15px rgba(0, 0, 0, 0.2);
+
+ animation-duration: 0.2s;
+ animation-iteration-count: 1;
+ animation-name: bodyfadeaway;
+ animation-fill-mode: forwards;
+ animation-timing-function: ease-in-out;
+}
+
+#toasts .toast.hidden {
+ margin-top: 0px;
+ max-height: 0px;
+ padding-top: 0px;
+ padding-bottom: 0px;
+ filter: opacity(0.0);
+ transform: scale(0.95);
+}
+
+#toasts .toast:not(.hidden):hover {filter: opacity(0.9)}
+#toasts .toast:not(.hidden):active {filter: opacity(0.8)}
+
+.toast .title {
+}
+
+.toast .description {
+ opacity: 0.8;
+ font-size: 0.8em;
+ font-weight: 600;
}
/* drag control */
-#bgHolder {
+#bgHolder,
+.contentContainer,
+.gamesContainer {
user-select: none;
-webkit-app-region: drag;
}
-a, button, .contentMenu, #close, #nsRelease, #vpReleaseNotes, .mod {
+#overlay.shown ~ #bgHolder,
+#overlay.shown ~ .contentContainer,
+#overlay.shown ~ .gamesContainer {
+ -webkit-app-region: no-drag;
+}
+
+a, button, #close, #nsRelease, #vpReleaseNotes, .mod, #overlay, #modsdiv, #winbtns, .contentMenu {
-webkit-app-region: no-drag;
}
diff --git a/src/app/main.js b/src/app/main.js
index 5f0cc9a..169f86f 100644
--- a/src/app/main.js
+++ b/src/app/main.js
@@ -3,6 +3,7 @@ const path = require("path");
const { ipcRenderer, shell } = require("electron");
const lang = require("../lang");
+var modsobj = {};
let shouldInstallNorthstar = false;
// Base settings
@@ -26,13 +27,11 @@ if (fs.existsSync("viper.json")) {
settings.zip = path.join(settings.gamepath + "/northstar.zip");
if (settings.gamepath.length === 0) {
- alert(lang("general.missingpath"));
setpath(false);
} else {
setpath(true);
}
} else {
- alert(lang("general.missingpath"));
setpath();
}
@@ -68,6 +67,15 @@ function log(msg) {
// updating/installing Northstar.
function setButtons(state) {
playNsBtn.disabled = !state;
+
+ let disablearray = (array) => {
+ for (let i = 0; i < array.length; i++) {
+ array[i].disabled = !state;
+ }
+ }
+
+ disablearray(document.querySelectorAll("#nsMods .buttons.modbtns button"))
+ disablearray(document.querySelectorAll("#browser #browserEntries .text button"))
}
// Frontend part of updating Northstar
@@ -150,12 +158,20 @@ function selected(all) {
// Tells the main process to install a mod
function installmod() {
+ setButtons(false);
ipcRenderer.send("installmod")
}
+// Tells the main process to install a mod from a URL
+function installFromURL(url) {
+ setButtons(false);
+ ipcRenderer.send("installfromurl", url)
+}
+
// Frontend part of settings a new game path
ipcRenderer.on("newpath", (event, newpath) => {
settings.gamepath = newpath;
+ ipcRenderer.send("guigetmods");
})
// Continuation of log()
@@ -164,6 +180,9 @@ ipcRenderer.on("alert", (event, msg) => {alert(msg)})
// Updates the installed mods
ipcRenderer.on("mods", (event, mods) => {
+ modsobj = mods;
+ if (! mods) {return}
+
modcount.innerHTML = `${lang("gui.mods.count")} ${mods.all.length}`;
modsdiv.innerHTML = "";
diff --git a/src/app/toast.js b/src/app/toast.js
new file mode 100644
index 0000000..2a8555e
--- /dev/null
+++ b/src/app/toast.js
@@ -0,0 +1,59 @@
+function Toast(properties) {
+ let toast = {
+ fg: "#000000",
+ bg: "#FFFFFF",
+ timeout: 3000,
+ title: "Untitled Toast",
+ description: "No description provided for toast",
+ ...properties
+ }
+
+ switch(toast.scheme) {
+ case "error":
+ toast.fg = "#FFFFFF";
+ toast.bg = "var(--red)";
+ break
+ case "success":
+ toast.fg = "#FFFFFF";
+ toast.bg = "#60D394";
+ break
+ case "warning":
+ toast.fg = "#FFFFFF";
+ toast.bg = "#FF9B85";
+ break
+ }
+
+
+ let id = Date.now();
+ if (document.getElementById(id)) {id = id + 1}
+ let el = document.createElement("div");
+
+ el.classList.add("toast");
+
+ el.style.color = toast.fg;
+ el.style.background = toast.bg;
+
+ el.id = id;
+ el.setAttribute("onclick", `dismissToast(${id})`);
+
+ el.innerHTML = `
+ <div class="title">${toast.title}</div>
+ <div class="description">${toast.description}</div>
+ `
+
+ toasts.appendChild(el);
+
+ setTimeout(() => {
+ dismissToast(id);
+ }, toast.timeout)
+}
+
+function dismissToast(id) {
+ id = document.getElementById(id);
+ if (id) {
+ id.classList.add("hidden");
+ setTimeout(() => {
+ id.remove();
+ }, 500)
+ }
+}
diff --git a/src/assets/icons/512x512.png b/src/assets/icons/512x512.png
index 281f3dd..69b1cce 100644
--- a/src/assets/icons/512x512.png
+++ b/src/assets/icons/512x512.png
Binary files differ
diff --git a/src/assets/icons/icon.ico b/src/assets/icons/icon.ico
index 32df0c5..06702df 100644
--- a/src/assets/icons/icon.ico
+++ b/src/assets/icons/icon.ico
Binary files differ
diff --git a/src/extras/findgame.js b/src/extras/findgame.js
new file mode 100644
index 0000000..42c9b85
--- /dev/null
+++ b/src/extras/findgame.js
@@ -0,0 +1,67 @@
+const fs = require("fs");
+const path = require("path");
+const vdf = require("simple-vdf");
+const { app } = require("electron");
+
+const util = require("util");
+const exec = util.promisify(require("child_process").exec);
+
+module.exports = async () => {
+ let gamepath = "";
+
+ // Autodetect path
+ // Windows only using powershell and windows registery
+ // Get-Item -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Respawn\Titanfall2\
+ if (process.platform == "win32") {
+ try {
+ const {stdout} = await exec("Get-ItemProperty -Path Registry::HKEY_LOCAL_MACHINE\\SOFTWARE\\Respawn\\Titanfall2\\ -Name \"Install Dir\"", {"shell":"powershell.exe"});
+
+ const gamepath = stdout.split('\n')
+ .filter(r => r.indexOf("Install Dir") !== -1)[0]
+ .replace(/\s+/g,' ')
+ .trim()
+ .replace("Install Dir : ","");
+
+ if (gamepath) {return gamepath}
+ } catch (err) {}
+ }
+
+ // Detect using Steam VDF
+ function readvdf(data) {
+ // Parse read_data
+ data = vdf.parse(data);
+
+ // `.length - 1` This is because the last value is `contentstatsid`
+ for (let pathIterator = 0; pathIterator < Object.values(data["libraryfolders"]).length - 1; pathIterator++) {
+ let data_array = Object.values(data["libraryfolders"][pathIterator])
+
+ if (fs.existsSync(data_array[0] + "/steamapps/common/Titanfall2/Titanfall2.exe")) {
+ return data_array[0] + "/steamapps/common/Titanfall2";
+ }
+ }
+ }
+
+ let folder = null;
+ switch (process.platform) {
+ case "win32":
+ folder = "C:\\Program Files (x86)\\Steam\\steamapps\\libraryfolders.vdf";
+ break
+ case "linux":
+ case "openbsd":
+ case "freebsd":
+ folder = path.join(app.getPath("home"), "/.steam/steam/steamapps/libraryfolders.vdf");
+ break
+ }
+
+ if (fs.existsSync(folder) && folder) {
+ let data = fs.readFileSync(folder)
+ let read_vdf = readvdf(data.toString())
+ if (read_vdf ) {return read_vdf}
+ }
+
+ if (gamepath) {
+ return gamepath;
+ } else {
+ return false;
+ }
+}
diff --git a/src/requests.js b/src/extras/requests.js
index 16b1330..16b1330 100644
--- a/src/requests.js
+++ b/src/extras/requests.js
diff --git a/src/index.js b/src/index.js
index 3f50840..a06cf69 100644
--- a/src/index.js
+++ b/src/index.js
@@ -8,7 +8,7 @@ const events = new Emitter();
const utils = require("./utils");
const cli = require("./cli");
-const requests = require("./requests");
+const requests = require("./extras/requests");
// Starts the actual BrowserWindow, which is only run when using the
// GUI, for the CLI this function is never called.
@@ -43,9 +43,13 @@ function start() {
ipcMain.on("exit", () => {process.exit(0)})
ipcMain.on("minimize", () => {win.minimize()})
+ ipcMain.on("installfromurl", (event, url) => {utils.mods.installFromURL(url)})
ipcMain.on("winLog", (event, ...args) => {win.webContents.send("log", ...args)});
ipcMain.on("winAlert", (event, ...args) => {win.webContents.send("alert", ...args)});
ipcMain.on("ns-update-event", (event) => win.webContents.send("ns-update-event", event));
+ ipcMain.on("failedmod", (event, modname) => {win.webContents.send("failedmod", modname)});
+ ipcMain.on("removedmod", (event, modname) => {win.webContents.send("removedmod", modname)});
+ ipcMain.on("installedmod", (event, modname) => {win.webContents.send("installedmod", modname)});
ipcMain.on("guigetmods", (event, ...args) => {win.webContents.send("mods", utils.mods.list())});
win.webContents.on("dom-ready", () => {
@@ -87,9 +91,13 @@ ipcMain.on("launchVanilla", (event) => {utils.launch("vanilla")})
ipcMain.on("update", (event) => {utils.update()})
ipcMain.on("setpathcli", (event) => {utils.setpath()});
ipcMain.on("setpath", (event, value) => {
- if (!value) {
- utils.setpath(win);
- } else if (!win.isVisible()) {
+ if (! value) {
+ if (! win.isVisible()) {
+ utils.setpath(win);
+ } else {
+ utils.setpath(win, true);
+ }
+ } else if (! win.isVisible()) {
win.show();
}
});
diff --git a/src/lang/en.json b/src/lang/en.json
index c2b6f98..27630ec 100644
--- a/src/lang/en.json
+++ b/src/lang/en.json
@@ -42,13 +42,14 @@
"gui.versions.northstar": "Northstar version",
"gui.exit": "Exit",
"gui.update": "Update",
- "gui.setpath": "Game Path",
+ "gui.setpath": "Change Game Path",
"gui.update.check": "Check for updates",
"gui.mods": "Mods",
"gui.mods.count": "Mods Installed:",
"gui.mods.disabledtag": "Disabled",
"gui.mods.install": "Install Mod",
+ "gui.mods.find": "Find Mods",
"gui.mods.toggle": "Toggle Mod",
"gui.mods.toggleall": "Toggle All",
"gui.mods.remove": "Remove Mod",
@@ -62,6 +63,15 @@
"gui.mods.installing": "Installing mod...",
"gui.mods.installedmod": "Installed mod!",
+ "gui.browser.info": "Info",
+ "gui.browser.madeby": "by",
+ "gui.browser.search": "Search...",
+ "gui.browser.update": "Update",
+ "gui.browser.install": "Install",
+ "gui.browser.reinstall": "Re-Install",
+ "gui.browser.loading": "Loading mods...",
+ "gui.browser.endoflist": "Maximum packages has been loaded.<br>Use the search for finding other packages!",
+
"gui.update.downloading": "Downloading...",
"gui.update.extracting": "Extracting update...",
"gui.update.finished": "Done! Ready to play!",
@@ -80,6 +90,13 @@
"gui.gamepath.must": "The game path must be set to start Viper.",
"gui.gamepath.wrong": "This folder is not a valid game path.",
+ "gui.toast.title.installed": "Mod installed!",
+ "gui.toast.title.failed": "Failed to install",
+ "gui.toast.title.malformed": "Incorrect folder structure!",
+ "gui.toast.desc.installed": "has been installed successfully!",
+ "gui.toast.desc.malformed": "has an incorrect folder structure, if you're the developer, you should fix this.",
+ "gui.toast.desc.failed": "An unknown error occurred while trying to install the mod. This may be the author's fault, and it may also be Viper's fault.",
+
"viper.menu.main": "Viper",
"viper.menu.release": "Release Notes",
"viper.menu.info": "Extras",
@@ -96,7 +113,7 @@
"general.mods.enabled": "Enabled mods:",
"general.mods.disabled": "Disabled mods:",
"general.mods.installed": "Installed mods:",
- "general.missingpath": "Game path is not set!",
+ "general.missingpath": "Game location could not be found automatically! Please select it manually!",
"general.notinstalled": "Northstar is not installed!",
"general.launching": "Launching"
}
diff --git a/src/lang/es.json b/src/lang/es.json
new file mode 100644
index 0000000..8beabef
--- /dev/null
+++ b/src/lang/es.json
@@ -0,0 +1,119 @@
+{
+ "cli.help.help": "muestra este mensaje de ayuda",
+ "cli.help.debug": "habre las herramientas de desarrollador/depuración ",
+ "cli.help.version": "muestra la información de la versión",
+ "cli.help.cli": "obliga la linea de comandos a habilitarse",
+ "cli.help.update": "actualiza Northstar desde la ruta de juego establecida",
+ "cli.help.setpath": "establece la ruta del juego",
+ "cli.help.updatevp": "actualiza Viper si es soportado",
+ "cli.help.installmod": "instala una modificación, desde una carpeta o zip",
+ "cli.help.removemod": "remueve una modificación",
+ "cli.help.togglemod": "alterna el estado de la modificación",
+
+ "cli.setpath.noarg": "No se ha proporcionado ningún argumento para --setpath",
+
+ "cli.update.current": "Versión actual:",
+ "cli.update.downloading": "Descargando...",
+ "cli.update.checking": "Buscando actualizaciones...",
+ "cli.update.downloaddone": "¡Descarga completa! Extrayendo...",
+ "cli.update.finished": "Instalación/Actualización completada!",
+ "cli.update.uptodate": "La ultima versión (%s) ya está instalada, omitiendo actualización.",
+ "cli.update.uptodate.short": "Está actualizado",
+
+ "cli.autoupdates.checking": "Buscando actualizaciones de Northstar...",
+ "cli.autoupdates.available": "¡Actualización de Northsar disponible!",
+ "cli.autoupdates.gamerunning": "El juego se está ejecutando, no se puede actualizar Northstar",
+ "cli.autoupdates.updatingns": "Lanzando proceso de actualización...",
+ "cli.autoupdates.noupdate": "No hay actualizaciones de Northstar disponibles.",
+
+ "cli.launch.linuxerror": "La ejecución del juego en Linux aun no está implementada",
+
+ "cli.mods.failed": "¡Fallo al instalar el mod!",
+ "cli.mods.removed": "¡Modificación removida exitosamente!",
+ "cli.mods.toggled": "¡El estado de la modificación ha cambiado exitosamente!",
+ "cli.mods.installed": "¡Modificiación instalada exitosamente!",
+ "cli.mods.cantfind": "¡No se encuentra una modificación con ese nombre!",
+ "cli.mods.notamod": "La carpeta o el archivo seleccionado no es una modificación",
+ "cli.mods.toggledall": "¡Estado de todas las modiciaciones ha sido cambiado exitosamente!",
+ "cli.mods.improperjson": "%s's mod.json tiene errores de formato",
+
+ "gui.welcome": "Bienvenido a Viper!",
+ "gui.versions.viper": "Versión de Viper",
+ "gui.versions.northstar": "Versión de Northstar",
+ "gui.exit": "Salir",
+ "gui.update": "Actualizar",
+ "gui.setpath": "Cambiar la ruta del juego",
+
+ "gui.update.check": "Buscar actualizaciones",
+ "gui.mods": "Modificaciones (Mods)",
+ "gui.mods.count": "Modificaciones instaladas:",
+ "gui.mods.disabledtag": "Deshabilitado",
+ "gui.mods.install": "Instalar modificación",
+ "gui.mods.find": "Encontrar modificaciones",
+ "gui.mods.toggle": "Alternar modificación",
+ "gui.mods.toggleall": "Alternar todo",
+ "gui.mods.remove": "Remover modificación",
+ "gui.mods.removeall": "Remover todo",
+ "gui.mods.nothingselected": "No has seleccionado una modificación.",
+ "gui.mods.toggleall.confirm": "Alternar todo podría deshabilitar las modificaciones requeridas para que Northstar funcione. ¿Está seguro?",
+ "gui.mods.removeall.confirm": "Eliminar todas las modificaciones generalmente requerirá que reinstales Northstar. ¿Está seguro?",
+ "gui.mods.required.confirm": "Ha seleccionado un mod esencial, es posible que Northstar no funcione sin él. ¿Está seguro?",
+ "gui.mods.notamod": "¡No es una modificación!",
+ "gui.mods.extracting": "Extrayendo modificación...",
+ "gui.mods.installing": "Instalando modificación...",
+ "gui.mods.installedmod": "¡Modificación instalada!",
+
+ "gui.browser.info": "Información",
+ "gui.browser.madeby": "por",
+ "gui.browser.search": "Buscar...",
+ "gui.browser.update": "Actualizar",
+ "gui.browser.install": "Instalar",
+ "gui.browser.reinstall": "Re-Instalar",
+ "gui.browser.loading": "Cargando modificaciones...",
+ "gui.browser.endoflist": "Se ha cargado el máximo de paquetes.<br>¡Usa la búsqueda para encontrar otros paquetes!",
+
+ "gui.update.downloading": "Descargando...",
+ "gui.update.extracting": "Extrayendo actualización...",
+ "gui.update.finished": "¡Hecho! ¡Está listo para jugar!",
+ "gui.update.uptodate": "¡Ya está actualizado!",
+ "gui.update.available": "Hay una actualización disponible para Viper, ¿desea reiniciar y aplicarla?",
+
+ "gui.nsupdate.gaming.title": "¡Actualización de Northstar disponible!",
+ "gui.nsupdate.gaming.body": "Una actualización de northstar está disponible.\nPuedes forzar su instalación despues de cerrar el juego.",
+
+ "gui.launch": "Ejecutar",
+ "gui.launchvanilla": "Vainilla",
+ "gui.launchnorthstar": "Northstar",
+ "gui.installnorthstar": "Instalar",
+
+ "gui.selectpath": "Por favor, ¡elija la ruta del juego!",
+ "gui.gamepath.must": "La ruta del juego debe establecerse para ejecutar Viper.",
+ "gui.gamepath.wrong": "Esta carpeta no es una ruta válida para el juego.",
+
+ "gui.toast.title.installed": "¡Modificación instalada!",
+ "gui.toast.title.failed": "¡Falló al instalar!",
+ "gui.toast.title.malformed": "¡Estructura de las carpetas incorrecta!",
+ "gui.toast.desc.installed": "¡Ha sido instalado exitosamente!",
+ "gui.toast.desc.malformed": "tiene una estructura de carpetas incorrecta, si usted es el desarrollador, debe corregir esto.",
+ "gui.toast.desc.failed": "Se produjo un error desconocido al intentar instalar la modificación. Esto puede ser culpa del autor de la modificación, y también puede ser culpa de Viper.",
+
+ "viper.menu.main": "Viper",
+ "viper.menu.release": "Notas de la versión",
+ "viper.menu.info": "Extras",
+ "viper.menu.info.links": "Links",
+ "viper.menu.info.credits": "Creditos",
+
+ "viper.info.discord": "Unete al Discord:",
+ "viper.info.issues": "Reporta problemas de Viper:",
+
+ "ns.menu.main": "Northstar Launcher",
+ "ns.menu.mods": "Modificiaciones",
+ "ns.menu.release": "Notas de actualización",
+
+ "general.mods.enabled": "Modificaciones habilitadas:",
+ "general.mods.disabled": "Modificaciones deshabilitadas:",
+ "general.mods.installed": "Modificiaciones intaladas:",
+ "general.missingpath": "¡La ruta del jueno no se ha podido encontrar automaticamente! ¡Por favor, elige la ruta manualmente!",
+ "general.notinstalled": "¡Northstar no se ha instalado!",
+ "general.launching": "Ejecutando"
+}
diff --git a/src/lang/fr.json b/src/lang/fr.json
index 59a3090..3bdeec6 100644
--- a/src/lang/fr.json
+++ b/src/lang/fr.json
@@ -42,13 +42,14 @@
"gui.versions.northstar": "Version de Northstar",
"gui.exit": "Fermer",
"gui.update": "Mise à jour",
- "gui.setpath": "Chemin du jeu",
+ "gui.setpath": "Mettre à jour le chemin du jeu",
"gui.update.check": "Vérifier les mises à jour",
"gui.mods": "Mods",
"gui.mods.count": "Mods installés :",
"gui.mods.disabledtag": "Désactivé",
"gui.mods.install": "Installer le mod",
+ "gui.mods.find": "Chercher des mods",
"gui.mods.toggle": "Activer/désactiver le mod",
"gui.mods.toggleall": "Activer/désactiver tous les mods",
"gui.mods.remove": "Supprimer le mod",
@@ -62,6 +63,15 @@
"gui.mods.installing": "Installation du mod...",
"gui.mods.installedmod": "Mod installé !",
+ "gui.browser.info": "Info",
+ "gui.browser.madeby": "par",
+ "gui.browser.search": "Rechercher",
+ "gui.browser.update": "Mise à jour",
+ "gui.browser.install": "Installer",
+ "gui.browser.reinstall": "Réinstaller",
+ "gui.browser.loading": "Chargement des mods...",
+ "gui.browser.endoflist": "Fin de la liste de mods.<br>Utilisez la barre de recherche pour en trouver davantage !",
+
"gui.update.downloading": "Téléchargement de la mise à jour...",
"gui.update.extracting": "Extraction des fichiers...",
"gui.update.finished": "Terminé, vous pouvez jouer !",
@@ -80,6 +90,13 @@
"gui.gamepath.must": "Vous devez sélectionner le chemin du dossier du jeu Titanfall 2 pour pouvoir lancer Viper.",
"gui.gamepath.wrong": "Ce dossier ne contient pas le jeu Titanfall 2, et n'est donc pas valide.",
+ "gui.toast.title.installed": "Mod installé !",
+ "gui.toast.title.failed": "L'installation a échoué",
+ "gui.toast.title.malformed": "La structure du dossier du mod est incorrecte.",
+ "gui.toast.desc.installed": "a été installé avec succès !",
+ "gui.toast.desc.malformed": "a une structure de dossier incorrecte ; si vous êtes son développeur, vous devriez réparer ça.",
+ "gui.toast.desc.failed": "Une erreur inconnue est survenue lors de l'installation du mod. Cela peut être du ressort de l'auteur du mod ou de Viper.",
+
"viper.menu.main": "Viper",
"viper.menu.release": "Notes de mises à jour",
"viper.menu.info": "Informations",
@@ -96,7 +113,7 @@
"general.mods.enabled": "Mods activés :",
"general.mods.disabled": "Mods désactivés :",
"general.mods.installed": "Mods installés :",
- "general.missingpath": "Le chemin du client n'est pas défini !",
+ "general.missingpath": "Le chemin du client n'a pu être trouvé automatiquement, merci de le sélectionner manuellement.",
"general.notinstalled": "Northstar n'est pas installé !",
"general.launching": "Lancement"
}
diff --git a/src/lang/maintainers.json b/src/lang/maintainers.json
new file mode 100644
index 0000000..094814a
--- /dev/null
+++ b/src/lang/maintainers.json
@@ -0,0 +1,13 @@
+{
+ "explanation": "This file is for storing contact information for the various maintainers of various languages/localizations",
+
+ "list": {
+ "es": [
+ "https://github.com/AA-Delta"
+ ],
+
+ "fr": [
+ "https://github.com/Alystrasz"
+ ]
+ }
+}
diff --git a/src/utils.js b/src/utils.js
index a41def4..a0c88ef 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -1,6 +1,6 @@
const path = require("path");
const fs = require("fs-extra");
-const copy = require("copy-dir");
+const copy = require("recursive-copy");
const { app, dialog, ipcMain, Notification } = require("electron");
const Emitter = require("events");
@@ -8,7 +8,8 @@ const events = new Emitter();
const cli = require("./cli");
const lang = require("./lang");
-const requests = require("./requests");
+const requests = require("./extras/requests");
+const findgame = require("./extras/findgame");
const unzip = require("unzipper");
const run = require("child_process").spawn;
@@ -115,10 +116,39 @@ northstar_auto_updates: {
//
// If running with CLI it takes in the --setpath argument otherwise it
// open the systems file browser for the user to select a path.
-function setpath(win) {
+async function setpath(win, forcedialog) {
+ function setGamepath(folder) {
+ settings.gamepath = folder;
+ settings.zip = path.join(settings.gamepath + "/northstar.zip");
+ saveSettings();
+ win.webContents.send("newpath", settings.gamepath);
+ ipcMain.emit("newpath", null, settings.gamepath);
+
+ modpath = path.join(settings.gamepath, "R2Northstar/mods");
+ }
+
if (! win) { // CLI
- settings.gamepath = cli.param("setpath");
+ setGamepath(cli.param("setpath"));
} else { // GUI
+ if (! forcedialog) {
+ function setGamepath(folder, forcedialog) {
+ settings.gamepath = folder;
+ settings.zip = path.join(settings.gamepath + "/northstar.zip");
+ saveSettings();
+ win.webContents.send("newpath", settings.gamepath);
+ ipcMain.emit("newpath", null, settings.gamepath);
+ }
+
+ let gamepath = await findgame();
+ if (gamepath) {
+ setGamepath(gamepath);
+ return;
+ }
+
+ winAlert(lang("general.missingpath"));
+ }
+
+ // Fallback to manual selection
dialog.showOpenDialog({properties: ["openDirectory"]}).then(res => {
if (res.canceled) {
ipcMain.emit("newpath", null, false);
@@ -129,16 +159,12 @@ function setpath(win) {
return;
}
- settings.gamepath = res.filePaths[0];
- settings.zip = path.join(settings.gamepath + "/northstar.zip");
- saveSettings();
- win.webContents.send("newpath", settings.gamepath);
- ipcMain.emit("newpath", null, settings.gamepath);
+ setGamepath(res.filePaths[0])
+
+ cli.exit();
+ return;
}).catch(err => {console.error(err)})
}
-
- saveSettings();
- cli.exit();
}
// As to not have to do the same one liner a million times, this
@@ -176,6 +202,19 @@ function getTF2Version() {
}
}
+
+// Renames excluded files to their original name
+function restoreExcludedFiles() {
+ for (let i = 0; i < settings.excludes.length; i++) {
+ let exclude = path.join(settings.gamepath + "/" + settings.excludes[i]);
+ if (fs.existsSync(exclude + ".excluded")) {
+ fs.renameSync(exclude + ".excluded", exclude)
+ }
+ }
+}
+// At start, restore excluded files who might have been created by an incomplete update process.
+restoreExcludedFiles();
+
// Installs/Updates Northstar
//
// If Northstar is already installed it'll be an update, otherwise it'll
@@ -186,14 +225,6 @@ function getTF2Version() {
// <file>.excluded, then rename them back after the extraction. The
// unzip module does not support excluding files directly.
async function update() {
- // Renames excluded files to <file>.excluded
- for (let i = 0; i < settings.excludes.length; i++) {
- let exclude = path.join(settings.gamepath + "/" + settings.excludes[i]);
- if (fs.existsSync(exclude)) {
- fs.renameSync(exclude, exclude + ".excluded")
- }
- }
-
ipcMain.emit("ns-update-event", "cli.update.checking");
console.log(lang("cli.update.checking"));
var version = getNSVersion();
@@ -215,6 +246,14 @@ async function update() {
ipcMain.emit("ns-update-event", "cli.update.downloading");
}
+ // Renames excluded files to <file>.excluded
+ for (let i = 0; i < settings.excludes.length; i++) {
+ let exclude = path.join(settings.gamepath + "/" + settings.excludes[i]);
+ if (fs.existsSync(exclude)) {
+ fs.renameSync(exclude, exclude + ".excluded")
+ }
+ }
+
// Start the download of the zip
https.get(requests.getLatestNsVersionLink(), (res) => {
let stream = fs.createWriteStream(settings.zip);
@@ -237,16 +276,10 @@ async function update() {
// 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("getversion");
-
- // Renames excluded files to their original name
- for (let i = 0; i < settings.excludes.length; i++) {
- let exclude = path.join(settings.gamepath + "/" + settings.excludes[i]);
- if (fs.existsSync(exclude + ".excluded")) {
- fs.renameSync(exclude + ".excluded", exclude)
- }
- }
+ fs.writeFileSync(path.join(settings.gamepath, "ns_version.txt"), latestAvailableVersion);
+ ipcMain.emit("getversion");
+
+ restoreExcludedFiles();
ipcMain.emit("guigetmods");
ipcMain.emit("ns-update-event", "cli.update.uptodate.short");
@@ -323,6 +356,8 @@ const mods = {
// combination of the other two, enabled being enabled mods, and you
// guessed it, disabled being disabled mods.
list: () => {
+ let modpath = path.join(settings.gamepath, "R2Northstar/mods");
+
if (getNSVersion() == "unknown") {
winLog(lang("general.notinstalled"))
console.log("error: " + lang("general.notinstalled"))
@@ -349,9 +384,14 @@ const mods = {
try {
mods.push({...require(path.join(modpath, file, "mod.json")), FolderName: file, Disabled: false})
}catch(err) {
- console.log("error: " + lang("cli.mods.improperjson"), file)
+ if (cli.hasArgs()) {console.log("error: " + lang("cli.mods.improperjson"), file)}
mods.push({Name: file, FolderName: file, Version: "unknown", Disabled: false})
}
+
+ let manifest = path.join(modpath, file, "manifest.json");
+ if (fs.existsSync(manifest)) {
+ try {mods[mods.length - 1].ManifestName = require(manifest).name}catch(err){}
+ }
}
}
})
@@ -368,10 +408,15 @@ const mods = {
try {
disabled.push({...require(path.join(disabledPath, file, "mod.json")), FolderName: file, Disabled: true})
}catch(err) {
- console.log("error: " + lang("cli.mods.improperjson"), file)
+ if (cli.hasArgs()) {console.log("error: " + lang("cli.mods.improperjson"), file)}
disabled.push({Name: file, FolderName: file, Version: "unknown", Disabled: true})
}
}
+
+ let manifest = path.join(modpath, file, "manifest.json");
+ if (fs.existsSync(manifest)) {
+ try {mods[mods.length - 1].ManifestName = require(manifest).name}catch(err){}
+ }
}
})
@@ -389,6 +434,8 @@ const mods = {
// the absolute basics will be provided and we can't know the
// version or similar.
get: (mod) => {
+ let modpath = path.join(settings.gamepath, "R2Northstar/mods");
+
if (getNSVersion() == "unknown") {
winLog(lang("general.notinstalled"))
console.log("error: " + lang("general.notinstalled"))
@@ -462,7 +509,9 @@ const mods = {
// Either a zip or folder is supported, we'll also try to search
// inside the zip or folder to see if buried in another folder or
// not, as sometimes that's the case.
- install: (mod) => {
+ install: (mod, destname, manifestfile, malformed = false) => {
+ let modname = mod.replace(/^.*(\\|\/|\:)/, "");
+
if (getNSVersion() == "unknown") {
winLog(lang("general.notinstalled"))
console.log("error: " + lang("general.notinstalled"))
@@ -482,6 +531,19 @@ const mods = {
cli.exit();
winLog(lang("gui.mods.installedmod"))
+
+ if (modname == "mods") {
+ let manifest = path.join(app.getPath("userData"), "Archives/manifest.json")
+
+ if (fs.existsSync(manifest)) {
+ modname = require(manifest).name;
+ }
+ }
+
+ ipcMain.emit("installedmod", "", {
+ name: modname,
+ malformed: malformed,
+ });
ipcMain.emit("guigetmods");
return true;
}
@@ -490,14 +552,17 @@ const mods = {
if (fs.statSync(mod).isDirectory()) {
winLog(lang("gui.mods.installing"))
+ files = fs.readdirSync(mod);
if (fs.existsSync(path.join(mod, "mod.json")) &&
fs.statSync(path.join(mod, "mod.json")).isFile()) {
- copy.sync(mod, path.join(modpath, mod.replace(/^.*(\\|\/|\:)/, "")), {
- mode: true,
- cover: true,
- utimes: true,
- });
+ if (fs.existsSync(path.join(modpath, modname))) {
+ fs.rmSync(path.join(modpath, modname), {recursive: true});
+ }
+ let copydest = path.join(modpath, modname);
+ if (typeof destname == "string") {copydest = path.join(modpath, destname)}
+ copy(mod, copydest)
+ copy(manifestfile, path.join(copydest, "manifest.json"))
return installed();
} else {
@@ -508,39 +573,110 @@ const mods = {
if (fs.existsSync(path.join(mod, files[i], "mod.json")) &&
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};
}
}
}
- notamod();
- return false;
+ return notamod();
}
+
+ return notamod();
} else {
winLog(lang("gui.mods.extracting"))
let cache = path.join(app.getPath("userData"), "Archives");
if (fs.existsSync(cache)) {
fs.rmSync(cache, {recursive: true});
- fs.mkdirSync(cache);
+ fs.mkdirSync(path.join(cache, "mods"), {recursive: true});
} else {
- fs.mkdirSync(cache);
+ fs.mkdirSync(path.join(cache, "mods"), {recursive: true});
}
try {
fs.createReadStream(mod).pipe(unzip.Extract({path: cache}))
.on("finish", () => {
- if (mods.install(cache)) {
- installed();
- } else {return notamod()}
+ 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("failedmod");
+ return notamod();
+ }
+ }
+
+ return notamod();
+ }
+
+ if (mods.install(cache)) {
+ installed();
+ } else {return notamod()}
+ }, 1000)
});
}catch(err) {return notamod()}
}
},
+
+ // Installs mods from URL's
+ //
+ // This'll simply download the file that the URL points to and then
+ // install it with mods.install()
+ installFromURL: (url) => {
+ https.get(url, (res) => {
+ let tmp = path.join(app.getPath("cache"), "vipertmp");
+ let modlocation = path.join(tmp, "/mod.zip");
+
+ if (fs.existsSync(tmp)) {
+ if (! fs.statSync(tmp).isDirectory()) {
+ fs.rmSync(tmp)
+ }
+ } else {
+ fs.mkdirSync(tmp)
+ if (fs.existsSync(modlocation)) {
+ fs.rmSync(modlocation)
+ }
+ }
+
+ let stream = fs.createWriteStream(modlocation);
+ res.pipe(stream);
+
+ // let received = 0;
+ // // Progress messages, we should probably switch this to
+ // // percentage instead of how much is downloaded.
+ // res.on("data", (chunk) => {
+ // received += chunk.length;
+ // ipcMain.emit("ns-update-event", lang("gui.update.downloading") + " " + (received / 1024 / 1024).toFixed(1) + "mb");
+ // })
+
+ stream.on("finish", () => {
+ stream.close();
+ mods.install(modlocation);
+ })
+ })
+ },
+
// Removes mods
//
// Takes in the names of the mod then removes it, no confirmation,
// that'd be up to the GUI.
remove: (mod) => {
+ let modpath = path.join(settings.gamepath, "R2Northstar/mods");
+
if (getNSVersion() == "unknown") {
winLog(lang("general.notinstalled"))
console.log("error: " + lang("general.notinstalled"))
@@ -575,10 +711,19 @@ const mods = {
}
if (fs.statSync(modPath).isDirectory()) {
+ let manifestname = null;
+ if (fs.existsSync(path.join(modPath, "manifest.json"))) {
+ manifestname = require(path.join(modPath, "manifest.json")).name;
+ }
+
fs.rmSync(modPath, {recursive: true});
console.log(lang("cli.mods.removed"));
cli.exit();
ipcMain.emit("guigetmods");
+ ipcMain.emit("removedmod", "", {
+ name: mod.replace(/^.*(\\|\/|\:)/, ""),
+ manifestname: manifestname
+ });
} else {
cli.exit(1);
}
@@ -591,6 +736,8 @@ const mods = {
// you checked for if a mod is already disable and if not run the
// function. However we currently have no need for that.
toggle: (mod, fork) => {
+ let modpath = path.join(settings.gamepath, "R2Northstar/mods");
+
if (getNSVersion() == "unknown") {
winLog(lang("general.notinstalled"))
console.log("error: " + lang("general.notinstalled"))
@@ -639,6 +786,9 @@ const mods = {
};
console.log(mods.modfile().get())
+setInterval(() => {
+ ipcMain.emit("guigetmods");
+}, 1500)
module.exports = {
mods,