aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author0neGal <mail@0negal.com>2022-02-08 21:15:38 +0100
committerGitHub <noreply@github.com>2022-02-08 21:15:38 +0100
commit70e50148c8a4315c7fc25d5052f9ebee1c5d56bc (patch)
tree5670e225378ebcb0e73efb0c84265357f74f00cb
parente2aa874f48dc585f0d67c5655df234bdf356cc53 (diff)
parent1bd83cf1a72332e142bb63acab47ac3877061875 (diff)
downloadViper-70e50148c8a4315c7fc25d5052f9ebee1c5d56bc.tar.gz
Viper-70e50148c8a4315c7fc25d5052f9ebee1c5d56bc.zip
Merge pull request #50 from 0neGal/thunderstore
Thunderstore support
-rw-r--r--package-lock.json435
-rw-r--r--package.json3
-rw-r--r--src/app/browser.js235
-rw-r--r--src/app/icons/no-image.pngbin0 -> 1959 bytes
-rw-r--r--src/app/index.html15
-rw-r--r--src/app/main.css244
-rw-r--r--src/app/main.js18
-rw-r--r--src/index.js4
-rw-r--r--src/lang/en.json10
-rw-r--r--src/lang/es.json214
-rw-r--r--src/lang/fr.json10
-rw-r--r--src/utils.js130
12 files changed, 1155 insertions, 163 deletions
diff --git a/package-lock.json b/package-lock.json
index 2a396b9..d5a6d72 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,13 +9,14 @@
"version": "1.0.3",
"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",
- "simple-vdf": "^1.1.1",
+ "recursive-copy": "^2.0.13",
+ "simple-vdf": "^1.1.1"
"unzipper": "^0.10.11"
},
"devDependencies": {
@@ -424,6 +425,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",
@@ -979,11 +1020,6 @@
"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",
@@ -1078,6 +1114,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",
@@ -1397,6 +1458,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",
@@ -1542,6 +1614,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",
@@ -1672,6 +1752,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",
@@ -1887,6 +1991,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",
@@ -2076,6 +2210,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",
@@ -2193,6 +2335,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",
@@ -2297,6 +2453,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",
@@ -2347,6 +2511,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",
@@ -2372,6 +2541,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",
@@ -2417,6 +2605,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",
@@ -2424,6 +2620,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",
@@ -2500,6 +2701,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",
@@ -2672,6 +2897,13 @@
"integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==",
"dev": true
},
+ "node_modules/slash": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
+ "engines": {
+ "node": ">=0.10.0"
+ }
"node_modules/simple-vdf": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/simple-vdf/-/simple-vdf-1.1.1.tgz",
@@ -3547,6 +3779,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",
@@ -3967,11 +4227,6 @@
"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",
@@ -4043,6 +4298,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",
@@ -4300,6 +4576,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",
@@ -4412,6 +4696,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",
@@ -4507,6 +4796,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",
@@ -4660,6 +4969,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",
@@ -4810,6 +5142,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",
@@ -4898,6 +5235,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",
@@ -4975,6 +5323,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",
@@ -5013,6 +5366,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",
@@ -5032,6 +5390,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",
@@ -5067,6 +5438,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",
@@ -5074,6 +5453,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",
@@ -5138,6 +5522,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",
@@ -5277,6 +5684,10 @@
"integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==",
"dev": true
},
+ "slash": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+ "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU="
"simple-vdf": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/simple-vdf/-/simple-vdf-1.1.1.tgz",
diff --git a/package.json b/package.json
index 0eaccd8..fc0381f 100644
--- a/package.json
+++ b/package.json
@@ -48,12 +48,13 @@
},
"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"
},
diff --git a/src/app/browser.js b/src/app/browser.js
new file mode 100644
index 0000000..5062d86
--- /dev/null
+++ b/src/app/browser.js
@@ -0,0 +1,235 @@
+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")
+ 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)
+ }
+ }
+}; Browser.loadfront()
+
+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("installedmod", (event, modname) => {
+ setButtons(true);
+ Browser.setbutton(modname, lang("gui.browser.reinstall"));
+})
+
+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/index.html b/src/app/index.html
index fe383a0..b861736 100644
--- a/src/app/index.html
+++ b/src/app/index.html
@@ -12,6 +12,19 @@
<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 +92,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 +116,7 @@
<script src="lang.js"></script>
<script src="main.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..94ef767 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,27 @@ 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);
}
/* 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 19f6c9e..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
@@ -66,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
@@ -148,9 +158,16 @@ 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;
@@ -163,6 +180,7 @@ 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}`;
diff --git a/src/index.js b/src/index.js
index c8bfc53..a06cf69 100644
--- a/src/index.js
+++ b/src/index.js
@@ -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", () => {
diff --git a/src/lang/en.json b/src/lang/en.json
index fe9b0b0..a9eb47f 100644
--- a/src/lang/en.json
+++ b/src/lang/en.json
@@ -49,6 +49,7 @@
"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!",
diff --git a/src/lang/es.json b/src/lang/es.json
index c6e282d..9eac2b0 100644
--- a/src/lang/es.json
+++ b/src/lang/es.json
@@ -1,102 +1,112 @@
-{
- "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.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.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": "Vanilla",
- "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.",
-
- "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"
-}
+{
+ "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.",
+
+ "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"
+} \ No newline at end of file
diff --git a/src/lang/fr.json b/src/lang/fr.json
index 2fbc89a..4e6103a 100644
--- a/src/lang/fr.json
+++ b/src/lang/fr.json
@@ -49,6 +49,7 @@
"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 !",
diff --git a/src/utils.js b/src/utils.js
index 0507921..1887dd1 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");
@@ -374,9 +374,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)) {
+ mods[mods.length - 1].ManifestName = require(manifest).name;
+ }
}
}
})
@@ -393,10 +398,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)) {
+ mods[mods.length - 1].ManifestName = require(manifest).name;
+ }
}
})
@@ -439,8 +449,8 @@ 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) => {
- let modpath = path.join(settings.gamepath, "R2Northstar/mods");
+ install: (mod, destname, manifestfile) => {
+ let modname = mod.replace(/^.*(\\|\/|\:)/, "");
if (getNSVersion() == "unknown") {
winLog(lang("general.notinstalled"))
@@ -461,6 +471,16 @@ 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", "", modname);
ipcMain.emit("guigetmods");
return true;
}
@@ -469,14 +489,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 {
@@ -487,6 +510,7 @@ const mods = {
if (fs.existsSync(path.join(mod, files[i], "mod.json")) &&
fs.statSync(path.join(mod, files[i], "mod.json")).isFile()) {
+ console.log(mods.install(path.join(mod, files[i])))
if (mods.install(path.join(mod, files[i]))) {return true};
}
}
@@ -500,21 +524,84 @@ const mods = {
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)) {
+ 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)
+ }
+ }
+ }
+
+ 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,
@@ -556,10 +643,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);
}
@@ -621,6 +717,10 @@ const mods = {
}
};
+setInterval(() => {
+ ipcMain.emit("guigetmods");
+}, 1500)
+
module.exports = {
mods,
lang,