Compare commits
60 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be9642eff1 | ||
|
|
d884b7d3d6 | ||
|
|
6d35be79b8 | ||
|
|
70ca06eb16 | ||
|
|
210ddbae06 | ||
|
|
3ee57831b9 | ||
|
|
72f83c3ac4 | ||
|
|
13d87dc85e | ||
|
|
0415cb77f7 | ||
|
|
b4da701080 | ||
|
|
ed2361ff22 | ||
|
|
c587e93c56 | ||
|
|
6ba0896a6e | ||
|
|
843b57e03e | ||
|
|
49fb4c68b6 | ||
|
|
477ecbb4ba | ||
|
|
4abce9d084 | ||
|
|
7f54858b27 | ||
|
|
be176fab71 | ||
|
|
e60f04bb79 | ||
|
|
17f1c4ff6f | ||
|
|
a7ded71404 | ||
|
|
31799ccfb0 | ||
|
|
dde696627e | ||
|
|
50b2e864c2 | ||
|
|
dfa007669b | ||
|
|
4b27c67e83 | ||
|
|
f58ed485a9 | ||
|
|
c31eb8154b | ||
|
|
253277984b | ||
|
|
23c0647e6c | ||
|
|
fd45068a46 | ||
|
|
9f9f665ede | ||
|
|
fd0055032f | ||
|
|
a993d34c9d | ||
|
|
f232defd1c | ||
|
|
887f11ab37 | ||
|
|
4c34f10bb2 | ||
|
|
684f3330e9 | ||
|
|
178bb0c012 | ||
|
|
39cc30de53 | ||
|
|
aae4223294 | ||
|
|
bddfa60f19 | ||
|
|
58b10cfcfe | ||
|
|
36a751bb7b | ||
|
|
6a67f07a9e | ||
|
|
c43871950c | ||
|
|
fe70701de8 | ||
|
|
80f5735d04 | ||
|
|
3305900cb8 | ||
|
|
c495e71f35 | ||
|
|
4721c46d8c | ||
|
|
0aaddf24c6 | ||
|
|
427fde27ad | ||
|
|
a12ba017bc | ||
|
|
7a2161d746 | ||
|
|
d0e7a319d6 | ||
|
|
4afafa5038 | ||
|
|
583680d311 | ||
|
|
70dd38f79d |
16
.github/workflows/release.yml
vendored
@@ -26,19 +26,3 @@ jobs:
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
RELEASE: true
|
||||
|
||||
- name: Update AUR package
|
||||
if: ${{ matrix.os == 'ubuntu-latest' }}
|
||||
run: |
|
||||
mkdir -p -m 700 ~/.ssh
|
||||
echo $SSH_KEY > ~/.ssh/aur
|
||||
echo $SSH_PUB_KEY > ~/.ssh/aur.pub
|
||||
chmod 600 ~/.ssh/*
|
||||
|
||||
export GIT_SSH_COMMAND="ssh -i ~/.ssh/aur"
|
||||
|
||||
sudo ./scripts/ci/install_makepkg.sh
|
||||
./scripts/ci/aur_bump.sh
|
||||
env:
|
||||
SSH_KEY: ${{ secrets.AUR_SSH_KEY }}
|
||||
SSH_PUB_KEY: ${{ secrets.AUR_SSH_PUB_KEY }}
|
||||
|
||||
9
.vscode/settings.json
vendored
@@ -9,10 +9,17 @@
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[javascriptreact]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[json]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"[jsonc]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
}
|
||||
},
|
||||
"cSpell.words": ["Vesktop"]
|
||||
}
|
||||
|
||||
25
README.md
@@ -1,18 +1,23 @@
|
||||
# Vencord Desktop
|
||||
# Vesktop
|
||||
|
||||
A standalone Electron app that loads Discord & Vencord
|
||||
Vesktop is a cross platform desktop app aiming to give you a snappier Discord experience with Vencord pre-installed
|
||||
|
||||
Vencord Desktop is currently in very early alpha. Bug reports, feature requests & contributions are highly appreciated!!
|
||||
**Not yet supported**:
|
||||
- Global Keybinds
|
||||
|
||||
Bug reports, feature requests & contributions are highly appreciated!!
|
||||
|
||||

|
||||
|
||||
## Installing
|
||||
|
||||
### Windows
|
||||
|
||||
Download and run Vencord-Desktop-Setup-VERSION.exe from [releases](https://github.com/Vencord/Desktop/releases/latest)
|
||||
Download and run Vesktop-Setup-VERSION.exe from [releases](https://github.com/Vencord/Vesktop/releases/latest)
|
||||
|
||||
### Mac
|
||||
|
||||
Download and run Vencord-Desktop-VERSION.dmg from [releases](https://github.com/Vencord/Desktop/releases/latest)
|
||||
Download and run Vesktop-VERSION.dmg from [releases](https://github.com/Vencord/Vesktop/releases/latest)
|
||||
|
||||
### Linux
|
||||
|
||||
@@ -22,15 +27,15 @@ Install [vencord-desktop-git](https://aur.archlinux.org/packages/vencord-desktop
|
||||
|
||||
#### Ubuntu/Debian based
|
||||
|
||||
Download Vencord-Desktop-VERSION.deb from [releases](https://github.com/Vencord/Desktop/releases/latest)
|
||||
Download Vesktop-VERSION.deb from [releases](https://github.com/Vencord/Vesktop/releases/latest)
|
||||
|
||||
#### Fedora/RHEL based
|
||||
|
||||
Download Vencord-Desktop-VERSION.rpm from [releases](https://github.com/Vencord/Desktop/releases/latest)
|
||||
Download Vesktop-VERSION.rpm from [releases](https://github.com/Vencord/Vesktop/releases/latest)
|
||||
|
||||
#### Other
|
||||
|
||||
Either download Vencord-Desktop-VERSION.AppImage and just run it directly or grab Vencord-Desktop-VERSION.tar.gz, extract it somewhere and run `vencorddesktop`.
|
||||
Either download Vesktop-VERSION.AppImage and just run it directly or grab Vesktop-VERSION.tar.gz, extract it somewhere and run `vencorddesktop`.
|
||||
|
||||
A flatpak is planned, if you want packages for other repos, feel free to create them and they can be linked as unofficial here
|
||||
|
||||
@@ -39,8 +44,8 @@ A flatpak is planned, if you want packages for other repos, feel free to create
|
||||
Packaging will create builds in the dist/ folder. You can then install them like mentioned above or distribute them
|
||||
|
||||
```sh
|
||||
git clone https://github.com/Vencord/Desktop
|
||||
cd Desktop
|
||||
git clone https://github.com/Vencord/Vesktop
|
||||
cd Vesktop
|
||||
|
||||
# Install Dependencies
|
||||
pnpm i
|
||||
|
||||
34
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "VencordDesktop",
|
||||
"version": "0.1.6",
|
||||
"version": "0.2.7",
|
||||
"private": true,
|
||||
"description": "",
|
||||
"keywords": [],
|
||||
@@ -22,13 +22,18 @@
|
||||
"testTypes": "tsc --noEmit",
|
||||
"watch": "pnpm build --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"arrpc": "github:OpenAsar/arrpc#061d473dc742266fc7f61587ed18e666543fed1e"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
|
||||
"@types/node": "^18.15.11",
|
||||
"@types/react": "^18.0.33",
|
||||
"@typescript-eslint/eslint-plugin": "^5.57.1",
|
||||
"@typescript-eslint/parser": "^5.57.1",
|
||||
"@vencord/types": "^0.1.2",
|
||||
"dotenv": "^16.0.3",
|
||||
"electron": "^23.2.0",
|
||||
"electron": "^25.2.0",
|
||||
"electron-builder": "^23.6.0",
|
||||
"esbuild": "^0.17.14",
|
||||
"eslint": "^8.38.0",
|
||||
@@ -52,7 +57,7 @@
|
||||
},
|
||||
"build": {
|
||||
"appId": "dev.vencord.desktop",
|
||||
"productName": "Vencord Desktop",
|
||||
"productName": "Vesktop",
|
||||
"files": [
|
||||
"!*",
|
||||
"dist/js",
|
||||
@@ -62,7 +67,7 @@
|
||||
],
|
||||
"linux": {
|
||||
"category": "Network",
|
||||
"maintainer": "vendicated+vencord-desktop@riseup.net",
|
||||
"maintainer": "vendicated+vesktop@riseup.net",
|
||||
"target": [
|
||||
"deb",
|
||||
"tar.gz",
|
||||
@@ -70,7 +75,7 @@
|
||||
"AppImage"
|
||||
],
|
||||
"desktop": {
|
||||
"Name": "Vencord Desktop",
|
||||
"Name": "Vesktop",
|
||||
"GenericName": "Internet Messenger",
|
||||
"Type": "Application",
|
||||
"Categories": "Network;InstantMessaging;Chat;",
|
||||
@@ -78,11 +83,30 @@
|
||||
}
|
||||
},
|
||||
"mac": {
|
||||
"target": [
|
||||
{
|
||||
"target": "default",
|
||||
"arch": [
|
||||
"x64",
|
||||
"arm64"
|
||||
]
|
||||
}
|
||||
],
|
||||
"category": "Network"
|
||||
},
|
||||
"nsis": {
|
||||
"include": "build/installer.nsh",
|
||||
"oneClick": false
|
||||
},
|
||||
"win": {
|
||||
"target": [
|
||||
"nsis",
|
||||
"portable"
|
||||
]
|
||||
},
|
||||
"publish": {
|
||||
"provider": "github",
|
||||
"releaseType": "release"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
333
pnpm-lock.yaml
generated
@@ -1,6 +1,18 @@
|
||||
lockfileVersion: '6.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
dependencies:
|
||||
arrpc:
|
||||
specifier: github:OpenAsar/arrpc#061d473dc742266fc7f61587ed18e666543fed1e
|
||||
version: github.com/OpenAsar/arrpc/061d473dc742266fc7f61587ed18e666543fed1e
|
||||
|
||||
devDependencies:
|
||||
'@fal-works/esbuild-plugin-global-externals':
|
||||
specifier: ^2.1.2
|
||||
version: 2.1.2
|
||||
'@types/node':
|
||||
specifier: ^18.15.11
|
||||
version: 18.15.11
|
||||
@@ -13,12 +25,15 @@ devDependencies:
|
||||
'@typescript-eslint/parser':
|
||||
specifier: ^5.57.1
|
||||
version: 5.57.1(eslint@8.38.0)(typescript@5.0.2)
|
||||
'@vencord/types':
|
||||
specifier: ^0.1.2
|
||||
version: 0.1.2
|
||||
dotenv:
|
||||
specifier: ^16.0.3
|
||||
version: 16.0.3
|
||||
electron:
|
||||
specifier: ^23.2.0
|
||||
version: 23.2.0
|
||||
specifier: ^25.2.0
|
||||
version: 25.2.0
|
||||
electron-builder:
|
||||
specifier: ^23.6.0
|
||||
version: 23.6.0
|
||||
@@ -71,6 +86,11 @@ packages:
|
||||
resolution: {integrity: sha512-sAP4LldeWNz0lNzmTird3uWfFDWWTeg6V/MsmyyLR9X1idwKBWIgt/ZvinqQldJm3LecKEs1emkbquO6PCiLVQ==}
|
||||
dev: true
|
||||
|
||||
/@aashutoshrathi/word-wrap@1.2.6:
|
||||
resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/@develar/schema-utils@2.6.5:
|
||||
resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==}
|
||||
engines: {node: '>= 8.9.0'}
|
||||
@@ -115,7 +135,7 @@ packages:
|
||||
resolution: {integrity: sha512-BDXFbYOJzT/NBEtp71cvsrGPwGAMGRB/349rwKuoxNSiKjPraNNnlK6MIIabViCjqZugu6j+xeMDlEkWdHHJSg==}
|
||||
dependencies:
|
||||
'@esbuild-kit/core-utils': 3.1.0
|
||||
get-tsconfig: 4.5.0
|
||||
get-tsconfig: 4.6.2
|
||||
dev: true
|
||||
|
||||
/@esbuild-kit/core-utils@3.1.0:
|
||||
@@ -129,7 +149,7 @@ packages:
|
||||
resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==}
|
||||
dependencies:
|
||||
'@esbuild-kit/core-utils': 3.1.0
|
||||
get-tsconfig: 4.5.0
|
||||
get-tsconfig: 4.6.2
|
||||
dev: true
|
||||
|
||||
/@esbuild/android-arm64@0.17.14:
|
||||
@@ -337,21 +357,21 @@ packages:
|
||||
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
|
||||
dependencies:
|
||||
eslint: 8.38.0
|
||||
eslint-visitor-keys: 3.4.0
|
||||
eslint-visitor-keys: 3.4.1
|
||||
dev: true
|
||||
|
||||
/@eslint-community/regexpp@4.5.0:
|
||||
resolution: {integrity: sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==}
|
||||
/@eslint-community/regexpp@4.5.1:
|
||||
resolution: {integrity: sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==}
|
||||
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
|
||||
dev: true
|
||||
|
||||
/@eslint/eslintrc@2.0.2:
|
||||
resolution: {integrity: sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==}
|
||||
/@eslint/eslintrc@2.0.3:
|
||||
resolution: {integrity: sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
dependencies:
|
||||
ajv: 6.12.6
|
||||
debug: 4.3.4
|
||||
espree: 9.5.1
|
||||
espree: 9.5.2
|
||||
globals: 13.20.0
|
||||
ignore: 5.2.4
|
||||
import-fresh: 3.3.0
|
||||
@@ -367,8 +387,12 @@ packages:
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
dev: true
|
||||
|
||||
/@humanwhocodes/config-array@0.11.8:
|
||||
resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==}
|
||||
/@fal-works/esbuild-plugin-global-externals@2.1.2:
|
||||
resolution: {integrity: sha512-cEee/Z+I12mZcFJshKcCqC8tuX5hG3s+d+9nZ3LabqKF1vKdF41B92pJVCBggjAGORAeOzyyDDKrZwIkLffeOQ==}
|
||||
dev: true
|
||||
|
||||
/@humanwhocodes/config-array@0.11.10:
|
||||
resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==}
|
||||
engines: {node: '>=10.10.0'}
|
||||
dependencies:
|
||||
'@humanwhocodes/object-schema': 1.2.1
|
||||
@@ -453,8 +477,8 @@ packages:
|
||||
'@types/responselike': 1.0.0
|
||||
dev: true
|
||||
|
||||
/@types/debug@4.1.7:
|
||||
resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==}
|
||||
/@types/debug@4.1.8:
|
||||
resolution: {integrity: sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==}
|
||||
dependencies:
|
||||
'@types/ms': 0.7.31
|
||||
dev: true
|
||||
@@ -478,8 +502,8 @@ packages:
|
||||
resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==}
|
||||
dev: true
|
||||
|
||||
/@types/json-schema@7.0.11:
|
||||
resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
|
||||
/@types/json-schema@7.0.12:
|
||||
resolution: {integrity: sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==}
|
||||
dev: true
|
||||
|
||||
/@types/json5@0.0.29:
|
||||
@@ -492,6 +516,10 @@ packages:
|
||||
'@types/node': 18.15.11
|
||||
dev: true
|
||||
|
||||
/@types/lodash@4.14.195:
|
||||
resolution: {integrity: sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==}
|
||||
dev: true
|
||||
|
||||
/@types/minimatch@5.1.2:
|
||||
resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==}
|
||||
dev: true
|
||||
@@ -501,10 +529,6 @@ packages:
|
||||
resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==}
|
||||
dev: true
|
||||
|
||||
/@types/node@16.18.22:
|
||||
resolution: {integrity: sha512-LJSIirgASa1LicFGTUFwDY7BfKDtLIbijqDLkH47LxEo/jtdrtiZ4/kLPD99bEQhTcPcuh6KhDllHqRxygJD2w==}
|
||||
dev: true
|
||||
|
||||
/@types/node@18.15.11:
|
||||
resolution: {integrity: sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==}
|
||||
dev: true
|
||||
@@ -522,6 +546,19 @@ packages:
|
||||
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
|
||||
dev: true
|
||||
|
||||
/@types/react-dom@18.2.6:
|
||||
resolution: {integrity: sha512-2et4PDvg6PVCyS7fuTc4gPoksV58bW0RwSxWKcPRcHZf0PRUGq03TKcD/rUHe3azfV6/5/biUBJw+HhCQjaP0A==}
|
||||
dependencies:
|
||||
'@types/react': 18.0.33
|
||||
dev: true
|
||||
|
||||
/@types/react@17.0.2:
|
||||
resolution: {integrity: sha512-Xt40xQsrkdvjn1EyWe1Bc0dJLcil/9x2vAuW7ya+PuQip4UYUaXyhzWmAbwRsdMgwOFHpfp7/FFZebDU6Y8VHA==}
|
||||
dependencies:
|
||||
'@types/prop-types': 15.7.5
|
||||
csstype: 3.1.2
|
||||
dev: true
|
||||
|
||||
/@types/react@18.0.33:
|
||||
resolution: {integrity: sha512-sHxzVxeanvQyQ1lr8NSHaj0kDzcNiGpILEVt69g9S31/7PfMvNCKLKcsHw4lYKjs3cGNJjXSP4mYzX43QlnjNA==}
|
||||
dependencies:
|
||||
@@ -540,8 +577,8 @@ packages:
|
||||
resolution: {integrity: sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==}
|
||||
dev: true
|
||||
|
||||
/@types/semver@7.3.13:
|
||||
resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==}
|
||||
/@types/semver@7.5.0:
|
||||
resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==}
|
||||
dev: true
|
||||
|
||||
/@types/verror@1.10.6:
|
||||
@@ -579,7 +616,7 @@ packages:
|
||||
typescript:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.5.0
|
||||
'@eslint-community/regexpp': 4.5.1
|
||||
'@typescript-eslint/parser': 5.57.1(eslint@8.38.0)(typescript@5.0.2)
|
||||
'@typescript-eslint/scope-manager': 5.57.1
|
||||
'@typescript-eslint/type-utils': 5.57.1(eslint@8.38.0)(typescript@5.0.2)
|
||||
@@ -589,7 +626,7 @@ packages:
|
||||
grapheme-splitter: 1.0.4
|
||||
ignore: 5.2.4
|
||||
natural-compare-lite: 1.4.0
|
||||
semver: 7.3.8
|
||||
semver: 7.5.3
|
||||
tsutils: 3.21.0(typescript@5.0.2)
|
||||
typescript: 5.0.2
|
||||
transitivePeerDependencies:
|
||||
@@ -663,7 +700,7 @@ packages:
|
||||
debug: 4.3.4
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
semver: 7.3.8
|
||||
semver: 7.5.3
|
||||
tsutils: 3.21.0(typescript@5.0.2)
|
||||
typescript: 5.0.2
|
||||
transitivePeerDependencies:
|
||||
@@ -677,14 +714,14 @@ packages:
|
||||
eslint: ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.4.0(eslint@8.38.0)
|
||||
'@types/json-schema': 7.0.11
|
||||
'@types/semver': 7.3.13
|
||||
'@types/json-schema': 7.0.12
|
||||
'@types/semver': 7.5.0
|
||||
'@typescript-eslint/scope-manager': 5.57.1
|
||||
'@typescript-eslint/types': 5.57.1
|
||||
'@typescript-eslint/typescript-estree': 5.57.1(typescript@5.0.2)
|
||||
eslint: 8.38.0
|
||||
eslint-scope: 5.1.1
|
||||
semver: 7.3.8
|
||||
semver: 7.5.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
@@ -695,19 +732,31 @@ packages:
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 5.57.1
|
||||
eslint-visitor-keys: 3.4.0
|
||||
eslint-visitor-keys: 3.4.1
|
||||
dev: true
|
||||
|
||||
/acorn-jsx@5.3.2(acorn@8.8.2):
|
||||
/@vencord/types@0.1.2:
|
||||
resolution: {integrity: sha512-C/dqZHn3aod/4izZT9sgZEef4478M7QNKTY8Gx2yB1CRYawJcs6hupXT/1SMmepKqrULbltL04Cnh5ieBm3Ucw==}
|
||||
dependencies:
|
||||
'@types/lodash': 4.14.195
|
||||
'@types/node': 18.15.11
|
||||
'@types/react': 18.0.33
|
||||
'@types/react-dom': 18.2.6
|
||||
discord-types: 1.3.26
|
||||
standalone-electron-types: 1.0.0
|
||||
type-fest: 3.8.0
|
||||
dev: true
|
||||
|
||||
/acorn-jsx@5.3.2(acorn@8.9.0):
|
||||
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
|
||||
peerDependencies:
|
||||
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||
dependencies:
|
||||
acorn: 8.8.2
|
||||
acorn: 8.9.0
|
||||
dev: true
|
||||
|
||||
/acorn@8.8.2:
|
||||
resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==}
|
||||
/acorn@8.9.0:
|
||||
resolution: {integrity: sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
@@ -781,8 +830,8 @@ packages:
|
||||
minimatch: 3.1.2
|
||||
read-config-file: 6.2.0
|
||||
sanitize-filename: 1.6.3
|
||||
semver: 7.3.8
|
||||
tar: 6.1.13
|
||||
semver: 7.5.3
|
||||
tar: 6.1.15
|
||||
temp-file: 3.4.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -816,7 +865,7 @@ packages:
|
||||
call-bind: 1.0.2
|
||||
define-properties: 1.2.0
|
||||
es-abstract: 1.21.2
|
||||
get-intrinsic: 1.2.0
|
||||
get-intrinsic: 1.2.1
|
||||
is-string: 1.0.7
|
||||
dev: true
|
||||
|
||||
@@ -1020,7 +1069,7 @@ packages:
|
||||
resolution: {integrity: sha512-QiQHweYsh8o+U/KNCZFSvISRnvRctb8m/2rB2I1JdByzvNKxPeFLlHFRPQRXab6aYeXc18j9LpsDLJ3sGQmWTQ==}
|
||||
dependencies:
|
||||
7zip-bin: 5.1.1
|
||||
'@types/debug': 4.1.7
|
||||
'@types/debug': 4.1.8
|
||||
'@types/fs-extra': 9.0.13
|
||||
app-builder-bin: 4.0.0
|
||||
bluebird-lst: 1.0.9
|
||||
@@ -1060,8 +1109,8 @@ packages:
|
||||
engines: {node: '>=10.6.0'}
|
||||
dev: true
|
||||
|
||||
/cacheable-request@7.0.2:
|
||||
resolution: {integrity: sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==}
|
||||
/cacheable-request@7.0.4:
|
||||
resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==}
|
||||
engines: {node: '>=8'}
|
||||
dependencies:
|
||||
clone-response: 1.0.3
|
||||
@@ -1077,7 +1126,7 @@ packages:
|
||||
resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
|
||||
dependencies:
|
||||
function-bind: 1.1.1
|
||||
get-intrinsic: 1.2.0
|
||||
get-intrinsic: 1.2.1
|
||||
dev: true
|
||||
|
||||
/callsites@3.1.0:
|
||||
@@ -1249,7 +1298,7 @@ packages:
|
||||
supports-color:
|
||||
optional: true
|
||||
dependencies:
|
||||
ms: 2.1.2
|
||||
ms: 2.1.3
|
||||
dev: true
|
||||
|
||||
/debug@4.3.4:
|
||||
@@ -1342,6 +1391,13 @@ packages:
|
||||
path-type: 4.0.0
|
||||
dev: true
|
||||
|
||||
/discord-types@1.3.26:
|
||||
resolution: {integrity: sha512-ToG51AOCH+JTQf7b+8vuYQe5Iqwz7nZ7StpECAZ/VZcI1ZhQk13pvt9KkRTfRv1xNvwJ2qib4e3+RifQlo8VPQ==}
|
||||
dependencies:
|
||||
'@types/react': 17.0.2
|
||||
moment: 2.29.4
|
||||
dev: true
|
||||
|
||||
/dmg-builder@23.6.0:
|
||||
resolution: {integrity: sha512-jFZvY1JohyHarIAlTbfQOk+HnceGjjAdFjVn3n8xlDWKsYNqbO4muca6qXEZTfGXeQMG7TYim6CeS5XKSfSsGA==}
|
||||
dependencies:
|
||||
@@ -1408,7 +1464,7 @@ packages:
|
||||
engines: {node: '>=0.10.0'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
jake: 10.8.5
|
||||
jake: 10.8.7
|
||||
dev: true
|
||||
|
||||
/electron-builder@23.6.0:
|
||||
@@ -1427,7 +1483,7 @@ packages:
|
||||
lazy-val: 1.0.5
|
||||
read-config-file: 6.2.0
|
||||
simple-update-notifier: 1.1.0
|
||||
yargs: 17.7.1
|
||||
yargs: 17.7.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
@@ -1462,14 +1518,14 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/electron@23.2.0:
|
||||
resolution: {integrity: sha512-De9e21cri0QYct/w6tTNOnKyCt9RVKUw5F8PEN4FPzGR9tr6IT53uyt42uH754uJWrZeLMCAdoXy6/0GmMmYZA==}
|
||||
/electron@25.2.0:
|
||||
resolution: {integrity: sha512-I/rhcW2sV2fyiveVSBr2N7v5ZiCtdGY0UiNCDZgk2fpSC+irQjbeh7JT2b4vWmJ2ogOXBjqesrN9XszTIG6DHg==}
|
||||
engines: {node: '>= 12.20.55'}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
'@electron/get': 2.0.2
|
||||
'@types/node': 16.18.22
|
||||
'@types/node': 18.15.11
|
||||
extract-zip: 2.0.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -1500,7 +1556,7 @@ packages:
|
||||
es-set-tostringtag: 2.0.1
|
||||
es-to-primitive: 1.2.1
|
||||
function.prototype.name: 1.1.5
|
||||
get-intrinsic: 1.2.0
|
||||
get-intrinsic: 1.2.1
|
||||
get-symbol-description: 1.0.0
|
||||
globalthis: 1.0.3
|
||||
gopd: 1.0.1
|
||||
@@ -1520,7 +1576,7 @@ packages:
|
||||
object-inspect: 1.12.3
|
||||
object-keys: 1.1.1
|
||||
object.assign: 4.1.4
|
||||
regexp.prototype.flags: 1.4.3
|
||||
regexp.prototype.flags: 1.5.0
|
||||
safe-regex-test: 1.0.0
|
||||
string.prototype.trim: 1.2.7
|
||||
string.prototype.trimend: 1.0.6
|
||||
@@ -1534,7 +1590,7 @@ packages:
|
||||
resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dependencies:
|
||||
get-intrinsic: 1.2.0
|
||||
get-intrinsic: 1.2.1
|
||||
has: 1.0.3
|
||||
has-tostringtag: 1.0.0
|
||||
dev: true
|
||||
@@ -1621,14 +1677,14 @@ packages:
|
||||
resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==}
|
||||
dependencies:
|
||||
debug: 3.2.7
|
||||
is-core-module: 2.11.0
|
||||
is-core-module: 2.12.1
|
||||
resolve: 1.22.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/eslint-module-utils@2.7.4(@typescript-eslint/parser@5.57.1)(eslint-import-resolver-node@0.3.7)(eslint@8.38.0):
|
||||
resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==}
|
||||
/eslint-module-utils@2.8.0(@typescript-eslint/parser@5.57.1)(eslint-import-resolver-node@0.3.7)(eslint@8.38.0):
|
||||
resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==}
|
||||
engines: {node: '>=4'}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': '*'
|
||||
@@ -1674,9 +1730,9 @@ packages:
|
||||
doctrine: 2.1.0
|
||||
eslint: 8.38.0
|
||||
eslint-import-resolver-node: 0.3.7
|
||||
eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.57.1)(eslint-import-resolver-node@0.3.7)(eslint@8.38.0)
|
||||
eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.57.1)(eslint-import-resolver-node@0.3.7)(eslint@8.38.0)
|
||||
has: 1.0.3
|
||||
is-core-module: 2.11.0
|
||||
is-core-module: 2.12.1
|
||||
is-glob: 4.0.3
|
||||
minimatch: 3.1.2
|
||||
object.values: 1.1.6
|
||||
@@ -1759,16 +1815,16 @@ packages:
|
||||
estraverse: 4.3.0
|
||||
dev: true
|
||||
|
||||
/eslint-scope@7.1.1:
|
||||
resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==}
|
||||
/eslint-scope@7.2.0:
|
||||
resolution: {integrity: sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
dependencies:
|
||||
esrecurse: 4.3.0
|
||||
estraverse: 5.3.0
|
||||
dev: true
|
||||
|
||||
/eslint-visitor-keys@3.4.0:
|
||||
resolution: {integrity: sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==}
|
||||
/eslint-visitor-keys@3.4.1:
|
||||
resolution: {integrity: sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
dev: true
|
||||
|
||||
@@ -1778,10 +1834,10 @@ packages:
|
||||
hasBin: true
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.4.0(eslint@8.38.0)
|
||||
'@eslint-community/regexpp': 4.5.0
|
||||
'@eslint/eslintrc': 2.0.2
|
||||
'@eslint-community/regexpp': 4.5.1
|
||||
'@eslint/eslintrc': 2.0.3
|
||||
'@eslint/js': 8.38.0
|
||||
'@humanwhocodes/config-array': 0.11.8
|
||||
'@humanwhocodes/config-array': 0.11.10
|
||||
'@humanwhocodes/module-importer': 1.0.1
|
||||
'@nodelib/fs.walk': 1.2.8
|
||||
ajv: 6.12.6
|
||||
@@ -1790,9 +1846,9 @@ packages:
|
||||
debug: 4.3.4
|
||||
doctrine: 3.0.0
|
||||
escape-string-regexp: 4.0.0
|
||||
eslint-scope: 7.1.1
|
||||
eslint-visitor-keys: 3.4.0
|
||||
espree: 9.5.1
|
||||
eslint-scope: 7.2.0
|
||||
eslint-visitor-keys: 3.4.1
|
||||
espree: 9.5.2
|
||||
esquery: 1.5.0
|
||||
esutils: 2.0.3
|
||||
fast-deep-equal: 3.1.3
|
||||
@@ -1806,14 +1862,14 @@ packages:
|
||||
imurmurhash: 0.1.4
|
||||
is-glob: 4.0.3
|
||||
is-path-inside: 3.0.3
|
||||
js-sdsl: 4.4.0
|
||||
js-sdsl: 4.4.1
|
||||
js-yaml: 4.1.0
|
||||
json-stable-stringify-without-jsonify: 1.0.1
|
||||
levn: 0.4.1
|
||||
lodash.merge: 4.6.2
|
||||
minimatch: 3.1.2
|
||||
natural-compare: 1.4.0
|
||||
optionator: 0.9.1
|
||||
optionator: 0.9.3
|
||||
strip-ansi: 6.0.1
|
||||
strip-json-comments: 3.1.1
|
||||
text-table: 0.2.0
|
||||
@@ -1821,13 +1877,13 @@ packages:
|
||||
- supports-color
|
||||
dev: true
|
||||
|
||||
/espree@9.5.1:
|
||||
resolution: {integrity: sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==}
|
||||
/espree@9.5.2:
|
||||
resolution: {integrity: sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
dependencies:
|
||||
acorn: 8.8.2
|
||||
acorn-jsx: 5.3.2(acorn@8.8.2)
|
||||
eslint-visitor-keys: 3.4.0
|
||||
acorn: 8.9.0
|
||||
acorn-jsx: 5.3.2(acorn@8.9.0)
|
||||
eslint-visitor-keys: 3.4.1
|
||||
dev: true
|
||||
|
||||
/esquery@1.5.0:
|
||||
@@ -1897,15 +1953,14 @@ packages:
|
||||
|
||||
/fast-deep-equal@3.1.3:
|
||||
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
|
||||
/fast-diff@1.2.0:
|
||||
resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==}
|
||||
/fast-diff@1.3.0:
|
||||
resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==}
|
||||
dev: true
|
||||
|
||||
/fast-glob@3.2.12:
|
||||
resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==}
|
||||
/fast-glob@3.3.0:
|
||||
resolution: {integrity: sha512-ChDuvbOypPuNjO8yIDf36x7BlZX1smcUMTTcyoIjycexOxd6DFsKsg21qVBzEmr3G7fUKIRy2/psii+CIUt7FA==}
|
||||
engines: {node: '>=8.6.0'}
|
||||
dependencies:
|
||||
'@nodelib/fs.stat': 2.0.5
|
||||
@@ -1917,7 +1972,6 @@ packages:
|
||||
|
||||
/fast-json-stable-stringify@2.1.0:
|
||||
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
|
||||
/fast-levenshtein@2.0.6:
|
||||
@@ -2073,11 +2127,12 @@ packages:
|
||||
engines: {node: 6.* || 8.* || >= 10.*}
|
||||
dev: true
|
||||
|
||||
/get-intrinsic@1.2.0:
|
||||
resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==}
|
||||
/get-intrinsic@1.2.1:
|
||||
resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==}
|
||||
dependencies:
|
||||
function-bind: 1.1.1
|
||||
has: 1.0.3
|
||||
has-proto: 1.0.1
|
||||
has-symbols: 1.0.3
|
||||
dev: true
|
||||
|
||||
@@ -2093,11 +2148,13 @@ packages:
|
||||
engines: {node: '>= 0.4'}
|
||||
dependencies:
|
||||
call-bind: 1.0.2
|
||||
get-intrinsic: 1.2.0
|
||||
get-intrinsic: 1.2.1
|
||||
dev: true
|
||||
|
||||
/get-tsconfig@4.5.0:
|
||||
resolution: {integrity: sha512-MjhiaIWCJ1sAU4pIQ5i5OfOuHHxVo1oYeNsWTON7jxYkod8pHocXeh+SSbmu5OZZZK73B6cbJ2XADzXehLyovQ==}
|
||||
/get-tsconfig@4.6.2:
|
||||
resolution: {integrity: sha512-E5XrT4CbbXcXWy+1jChlZmrmCwd5KGx502kDCXJJ7y898TtWW9FwoG5HfOLVRKmlmDGkWN2HM9Ho+/Y8F0sJDg==}
|
||||
dependencies:
|
||||
resolve-pkg-maps: 1.0.0
|
||||
dev: true
|
||||
|
||||
/get-value@2.0.6:
|
||||
@@ -2139,7 +2196,7 @@ packages:
|
||||
es6-error: 4.1.1
|
||||
matcher: 3.0.0
|
||||
roarr: 2.15.4
|
||||
semver: 7.3.8
|
||||
semver: 7.5.3
|
||||
serialize-error: 7.0.1
|
||||
dev: true
|
||||
optional: true
|
||||
@@ -2164,7 +2221,7 @@ packages:
|
||||
dependencies:
|
||||
array-union: 2.1.0
|
||||
dir-glob: 3.0.1
|
||||
fast-glob: 3.2.12
|
||||
fast-glob: 3.3.0
|
||||
ignore: 5.2.4
|
||||
merge2: 1.4.1
|
||||
slash: 3.0.0
|
||||
@@ -2173,7 +2230,7 @@ packages:
|
||||
/gopd@1.0.1:
|
||||
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==}
|
||||
dependencies:
|
||||
get-intrinsic: 1.2.0
|
||||
get-intrinsic: 1.2.1
|
||||
dev: true
|
||||
|
||||
/got@11.8.6:
|
||||
@@ -2185,7 +2242,7 @@ packages:
|
||||
'@types/cacheable-request': 6.0.3
|
||||
'@types/responselike': 1.0.0
|
||||
cacheable-lookup: 5.0.4
|
||||
cacheable-request: 7.0.2
|
||||
cacheable-request: 7.0.4
|
||||
decompress-response: 6.0.0
|
||||
http2-wrapper: 1.0.3
|
||||
lowercase-keys: 2.0.0
|
||||
@@ -2217,7 +2274,7 @@ packages:
|
||||
/has-property-descriptors@1.0.0:
|
||||
resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==}
|
||||
dependencies:
|
||||
get-intrinsic: 1.2.0
|
||||
get-intrinsic: 1.2.1
|
||||
dev: true
|
||||
|
||||
/has-proto@1.0.1:
|
||||
@@ -2372,7 +2429,7 @@ packages:
|
||||
resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dependencies:
|
||||
get-intrinsic: 1.2.0
|
||||
get-intrinsic: 1.2.1
|
||||
has: 1.0.3
|
||||
side-channel: 1.0.4
|
||||
dev: true
|
||||
@@ -2395,7 +2452,7 @@ packages:
|
||||
resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==}
|
||||
dependencies:
|
||||
call-bind: 1.0.2
|
||||
get-intrinsic: 1.2.0
|
||||
get-intrinsic: 1.2.1
|
||||
is-typed-array: 1.1.10
|
||||
dev: true
|
||||
|
||||
@@ -2429,8 +2486,8 @@ packages:
|
||||
ci-info: 3.8.0
|
||||
dev: true
|
||||
|
||||
/is-core-module@2.11.0:
|
||||
resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==}
|
||||
/is-core-module@2.12.1:
|
||||
resolution: {integrity: sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==}
|
||||
dependencies:
|
||||
has: 1.0.3
|
||||
dev: true
|
||||
@@ -2621,8 +2678,8 @@ packages:
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/jake@10.8.5:
|
||||
resolution: {integrity: sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==}
|
||||
/jake@10.8.7:
|
||||
resolution: {integrity: sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
@@ -2632,8 +2689,8 @@ packages:
|
||||
minimatch: 3.1.2
|
||||
dev: true
|
||||
|
||||
/js-sdsl@4.4.0:
|
||||
resolution: {integrity: sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==}
|
||||
/js-sdsl@4.4.1:
|
||||
resolution: {integrity: sha512-6Gsx8R0RucyePbWqPssR8DyfuXmLBooYN5cZFZKjHGnQuaf7pEzhtpceagJxVu4LqhYY5EYA7nko3FmeHZ1KbA==}
|
||||
dev: true
|
||||
|
||||
/js-yaml@4.1.0:
|
||||
@@ -2649,7 +2706,6 @@ packages:
|
||||
|
||||
/json-schema-traverse@0.4.1:
|
||||
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
|
||||
/json-stable-stringify-without-jsonify@1.0.1:
|
||||
@@ -2848,8 +2904,8 @@ packages:
|
||||
yallist: 4.0.0
|
||||
dev: true
|
||||
|
||||
/minipass@4.2.5:
|
||||
resolution: {integrity: sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==}
|
||||
/minipass@5.0.0:
|
||||
resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==}
|
||||
engines: {node: '>=8'}
|
||||
dev: true
|
||||
|
||||
@@ -2875,6 +2931,10 @@ packages:
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/moment@2.29.4:
|
||||
resolution: {integrity: sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==}
|
||||
dev: true
|
||||
|
||||
/ms@2.0.0:
|
||||
resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==}
|
||||
dev: true
|
||||
@@ -2883,6 +2943,10 @@ packages:
|
||||
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
||||
dev: true
|
||||
|
||||
/ms@2.1.3:
|
||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||
dev: true
|
||||
|
||||
/nanomatch@1.2.13:
|
||||
resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -2978,16 +3042,16 @@ packages:
|
||||
wrappy: 1.0.2
|
||||
dev: true
|
||||
|
||||
/optionator@0.9.1:
|
||||
resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==}
|
||||
/optionator@0.9.3:
|
||||
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
dependencies:
|
||||
'@aashutoshrathi/word-wrap': 1.2.6
|
||||
deep-is: 0.1.4
|
||||
fast-levenshtein: 2.0.6
|
||||
levn: 0.4.1
|
||||
prelude-ls: 1.2.1
|
||||
type-check: 0.4.0
|
||||
word-wrap: 1.2.3
|
||||
dev: true
|
||||
|
||||
/p-cancelable@2.1.1:
|
||||
@@ -3071,7 +3135,7 @@ packages:
|
||||
resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
|
||||
engines: {node: '>=6.0.0'}
|
||||
dependencies:
|
||||
fast-diff: 1.2.0
|
||||
fast-diff: 1.3.0
|
||||
dev: true
|
||||
|
||||
/prettier@2.8.7:
|
||||
@@ -3095,7 +3159,6 @@ packages:
|
||||
/punycode@2.3.0:
|
||||
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
|
||||
engines: {node: '>=6'}
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
|
||||
/queue-microtask@1.2.3:
|
||||
@@ -3126,8 +3189,8 @@ packages:
|
||||
safe-regex: 1.1.0
|
||||
dev: true
|
||||
|
||||
/regexp.prototype.flags@1.4.3:
|
||||
resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==}
|
||||
/regexp.prototype.flags@1.5.0:
|
||||
resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dependencies:
|
||||
call-bind: 1.0.2
|
||||
@@ -3154,6 +3217,10 @@ packages:
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/resolve-pkg-maps@1.0.0:
|
||||
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
|
||||
dev: true
|
||||
|
||||
/resolve-url@0.2.1:
|
||||
resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==}
|
||||
deprecated: https://github.com/lydell/resolve-url#deprecated
|
||||
@@ -3163,7 +3230,7 @@ packages:
|
||||
resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
is-core-module: 2.11.0
|
||||
is-core-module: 2.12.1
|
||||
path-parse: 1.0.7
|
||||
supports-preserve-symlinks-flag: 1.0.0
|
||||
dev: true
|
||||
@@ -3214,7 +3281,7 @@ packages:
|
||||
resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==}
|
||||
dependencies:
|
||||
call-bind: 1.0.2
|
||||
get-intrinsic: 1.2.0
|
||||
get-intrinsic: 1.2.1
|
||||
is-regex: 1.1.4
|
||||
dev: true
|
||||
|
||||
@@ -3253,8 +3320,8 @@ packages:
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/semver@7.3.8:
|
||||
resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==}
|
||||
/semver@7.5.3:
|
||||
resolution: {integrity: sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
@@ -3295,7 +3362,7 @@ packages:
|
||||
resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==}
|
||||
dependencies:
|
||||
call-bind: 1.0.2
|
||||
get-intrinsic: 1.2.0
|
||||
get-intrinsic: 1.2.1
|
||||
object-inspect: 1.12.3
|
||||
dev: true
|
||||
|
||||
@@ -3390,6 +3457,12 @@ packages:
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/standalone-electron-types@1.0.0:
|
||||
resolution: {integrity: sha512-0HOi/tlTz3mjWhsAz4uRbpQcHMZ+ifj1JzWW9nugykOHClBBG77ps8QinrzX1eow4Iw2pnC+RFaSYRgufF4BOg==}
|
||||
dependencies:
|
||||
'@types/node': 18.15.11
|
||||
dev: true
|
||||
|
||||
/stat-mode@1.0.0:
|
||||
resolution: {integrity: sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==}
|
||||
engines: {node: '>= 6'}
|
||||
@@ -3475,13 +3548,13 @@ packages:
|
||||
engines: {node: '>= 0.4'}
|
||||
dev: true
|
||||
|
||||
/tar@6.1.13:
|
||||
resolution: {integrity: sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==}
|
||||
/tar@6.1.15:
|
||||
resolution: {integrity: sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
chownr: 2.0.0
|
||||
fs-minipass: 2.1.0
|
||||
minipass: 4.2.5
|
||||
minipass: 5.0.0
|
||||
minizlib: 2.1.2
|
||||
mkdirp: 1.0.4
|
||||
yallist: 4.0.0
|
||||
@@ -3651,7 +3724,6 @@ packages:
|
||||
|
||||
/uri-js@4.4.1:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
punycode: 2.3.0
|
||||
dev: true
|
||||
@@ -3711,11 +3783,6 @@ packages:
|
||||
isexe: 2.0.0
|
||||
dev: true
|
||||
|
||||
/word-wrap@1.2.3:
|
||||
resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/wrap-ansi@7.0.0:
|
||||
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -3729,6 +3796,19 @@ packages:
|
||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||
dev: true
|
||||
|
||||
/ws@8.13.0:
|
||||
resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==}
|
||||
engines: {node: '>=10.0.0'}
|
||||
peerDependencies:
|
||||
bufferutil: ^4.0.1
|
||||
utf-8-validate: '>=5.0.2'
|
||||
peerDependenciesMeta:
|
||||
bufferutil:
|
||||
optional: true
|
||||
utf-8-validate:
|
||||
optional: true
|
||||
dev: false
|
||||
|
||||
/xmlbuilder@15.1.1:
|
||||
resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==}
|
||||
engines: {node: '>=8.0'}
|
||||
@@ -3749,8 +3829,8 @@ packages:
|
||||
engines: {node: '>=12'}
|
||||
dev: true
|
||||
|
||||
/yargs@17.7.1:
|
||||
resolution: {integrity: sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==}
|
||||
/yargs@17.7.2:
|
||||
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
cliui: 8.0.1
|
||||
@@ -3773,3 +3853,14 @@ packages:
|
||||
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
github.com/OpenAsar/arrpc/061d473dc742266fc7f61587ed18e666543fed1e:
|
||||
resolution: {tarball: https://codeload.github.com/OpenAsar/arrpc/tar.gz/061d473dc742266fc7f61587ed18e666543fed1e}
|
||||
name: arrpc
|
||||
version: 3.1.0
|
||||
dependencies:
|
||||
ws: 8.13.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
dev: false
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { BuildContext, BuildOptions, context } from "esbuild";
|
||||
|
||||
import vencordDep from "./vencordDep.mjs";
|
||||
|
||||
const isDev = process.argv.includes("--dev");
|
||||
|
||||
const CommonOpts: BuildOptions = {
|
||||
@@ -35,21 +37,24 @@ await Promise.all([
|
||||
createContext({
|
||||
...NodeCommonOpts,
|
||||
entryPoints: ["src/main/index.ts"],
|
||||
outfile: "dist/js/main.js"
|
||||
outfile: "dist/js/main.js",
|
||||
footer: { js: "//# sourceURL=VCDMain" }
|
||||
}),
|
||||
createContext({
|
||||
...NodeCommonOpts,
|
||||
entryPoints: ["src/preload/index.ts"],
|
||||
outfile: "dist/js/preload.js"
|
||||
outfile: "dist/js/preload.js",
|
||||
footer: { js: "//# sourceURL=VCDPreload" }
|
||||
}),
|
||||
createContext({
|
||||
...NodeCommonOpts,
|
||||
entryPoints: ["src/updater/preload.ts"],
|
||||
outfile: "dist/js/updaterPreload.js"
|
||||
outfile: "dist/js/updaterPreload.js",
|
||||
footer: { js: "//# sourceURL=VCDUpdaterPreload" }
|
||||
}),
|
||||
createContext({
|
||||
...CommonOpts,
|
||||
globalName: "VencordDesktop",
|
||||
globalName: "Vesktop",
|
||||
entryPoints: ["src/renderer/index.ts"],
|
||||
outfile: "dist/js/renderer.js",
|
||||
format: "iife",
|
||||
@@ -57,7 +62,14 @@ await Promise.all([
|
||||
jsxFactory: "VencordCreateElement",
|
||||
jsxFragment: "VencordFragment",
|
||||
// Work around https://github.com/evanw/esbuild/issues/2460
|
||||
tsconfig: "./scripts/build/tsconfig.esbuild.json"
|
||||
tsconfig: "./scripts/build/tsconfig.esbuild.json",
|
||||
external: ["@vencord/types/*"],
|
||||
plugins: [vencordDep],
|
||||
// TODO: remove legacy name once main Vencord codebase has migrated and some time has passed.
|
||||
// this 0 is very important. we run this script via webFrame.executeJavaScript and the last
|
||||
// expression will be the return value. Without the 0, the return value would be Vesktop which
|
||||
// leads to "An object could not be cloned"
|
||||
footer: { js: ";window.VencordDesktop=Vesktop;0 \n//# sourceURL=VCDRenderer" }
|
||||
})
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
|
||||
38
scripts/build/vencordDep.mts
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { globalExternalsWithRegExp } from "@fal-works/esbuild-plugin-global-externals";
|
||||
|
||||
const names = {
|
||||
webpack: "Vencord.Webpack",
|
||||
"webpack/common": "Vencord.Webpack.Common",
|
||||
utils: "Vencord.Util",
|
||||
api: "Vencord.Api",
|
||||
"api/settings": "Vencord",
|
||||
components: "Vencord.Components"
|
||||
};
|
||||
|
||||
export default globalExternalsWithRegExp({
|
||||
getModuleInfo(modulePath) {
|
||||
const path = modulePath.replace("@vencord/types/", "");
|
||||
let varName = names[path];
|
||||
if (!varName) {
|
||||
const altMapping = names[path.split("/")[0]];
|
||||
if (!altMapping) throw new Error("Unknown module path: " + modulePath);
|
||||
|
||||
varName =
|
||||
altMapping +
|
||||
"." +
|
||||
// @ts-ignore
|
||||
path.split("/")[1].replaceAll("/", ".");
|
||||
}
|
||||
return {
|
||||
varName,
|
||||
type: "cjs"
|
||||
};
|
||||
},
|
||||
modulePathFilter: /^@vencord\/types.+$/
|
||||
});
|
||||
@@ -1,20 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
VERSION=$(git describe --tags --abbrev=0 | tr -d 'v')
|
||||
SHASUM=$(sha256sum "dist/VencordDesktop-$VERSION.tar.gz" | awk '{ print $1 }')
|
||||
|
||||
git clone ssh://aur@aur.archlinux.org/vencord-desktop-bin.git aurpkg
|
||||
|
||||
cd aurpkg
|
||||
|
||||
sed -i "s/^pkgver=.*$/pkgver=$VERSION/" PKGBUILD
|
||||
sed -i "s/^sha256sums=('.*'/sha256sums=('$SHASUM'/" PKGBUILD
|
||||
makepkg --printsrcinfo > .SRCINFO
|
||||
|
||||
git commit -a -m "Bump version to $VERSION"
|
||||
git push
|
||||
|
||||
cd ..
|
||||
rm -rf aurpkg
|
||||
@@ -1,13 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
for i in \
|
||||
"makepkg_6.0.2-3_amd64.deb" \
|
||||
"libalpm13_13.0.2-3_amd64.deb" \
|
||||
"pacman-package-manager_6.0.2-3_amd64.deb"; do
|
||||
wget -O/tmp/$i https://fr.archive.ubuntu.com/ubuntu/pool/universe/p/pacman-package-manager/$i
|
||||
dpkg -i /tmp/$i || true
|
||||
done
|
||||
|
||||
apt-get -f install -oDpkg::Use-Pty=0 -qq
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
|
||||
10
src/globals.d.ts
vendored
@@ -1,15 +1,13 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
declare global {
|
||||
export var VencordDesktopNative: typeof import("preload/VencordDesktopNative").VencordDesktopNative;
|
||||
export var VencordDesktop: typeof import("renderer/index");
|
||||
// TODO
|
||||
export var Vencord: any;
|
||||
export var vcdLS: typeof localStorage;
|
||||
export var VesktopNative: typeof import("preload/VesktopNative").VesktopNative;
|
||||
export var Vesktop: typeof import("renderer/index");
|
||||
export var VCDP: any;
|
||||
|
||||
export var IS_DEV: boolean;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { BrowserWindow } from "electron";
|
||||
import { join } from "path";
|
||||
import { ICON_PATH, STATIC_DIR } from "shared/paths";
|
||||
import { ICON_PATH, VIEW_DIR } from "shared/paths";
|
||||
|
||||
import { makeLinksOpenExternally } from "./utils/makeLinksOpenExternally";
|
||||
|
||||
@@ -14,12 +14,15 @@ export function createAboutWindow() {
|
||||
const about = new BrowserWindow({
|
||||
center: true,
|
||||
autoHideMenuBar: true,
|
||||
icon: ICON_PATH
|
||||
icon: ICON_PATH,
|
||||
webPreferences: {
|
||||
preload: join(__dirname, "updaterPreload.js")
|
||||
}
|
||||
});
|
||||
|
||||
makeLinksOpenExternally(about);
|
||||
|
||||
about.loadFile(join(STATIC_DIR, "about.html"));
|
||||
about.loadFile(join(VIEW_DIR, "about.html"));
|
||||
|
||||
return about;
|
||||
}
|
||||
|
||||
50
src/main/appBadge.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { app, NativeImage, nativeImage } from "electron";
|
||||
import { join } from "path";
|
||||
import { BADGE_DIR } from "shared/paths";
|
||||
|
||||
const imgCache = new Map<number, NativeImage>();
|
||||
function loadBadge(index: number) {
|
||||
const cached = imgCache.get(index);
|
||||
if (cached) return cached;
|
||||
|
||||
const img = nativeImage.createFromPath(join(BADGE_DIR, `${index}.ico`));
|
||||
imgCache.set(index, img);
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
let lastIndex: null | number = -1;
|
||||
|
||||
export function setBadgeCount(count: number) {
|
||||
switch (process.platform) {
|
||||
case "darwin":
|
||||
case "linux":
|
||||
if (count === -1) count = 0;
|
||||
app.setBadgeCount(count);
|
||||
break;
|
||||
case "win32":
|
||||
const [index, description] = getBadgeIndexAndDescription(count);
|
||||
if (lastIndex === index) break;
|
||||
|
||||
lastIndex = index;
|
||||
|
||||
// circular import shenanigans
|
||||
const { mainWin } = require("./mainWindow") as typeof import("./mainWindow");
|
||||
mainWin.setOverlayIcon(index === null ? null : loadBadge(index), description);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function getBadgeIndexAndDescription(count: number): [number | null, string] {
|
||||
if (count === -1) return [11, "Unread Messages"];
|
||||
if (count === 0) return [null, "No Notifications"];
|
||||
|
||||
const index = Math.max(1, Math.min(count, 10));
|
||||
return [index, `${index} Notification`];
|
||||
}
|
||||
40
src/main/arrpc.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import Server from "arrpc";
|
||||
|
||||
import { mainWin } from "./mainWindow";
|
||||
import { Settings } from "./settings";
|
||||
|
||||
let server: any;
|
||||
|
||||
const inviteCodeRegex = /^(\w|-)+$/;
|
||||
|
||||
export async function initArRPC() {
|
||||
if (server || !Settings.store.arRPC) return;
|
||||
|
||||
try {
|
||||
// This module starts a server as a side effect, so it needs to be lazy imported
|
||||
const { send: sendToBridge } = await import("arrpc/src/bridge");
|
||||
|
||||
server = await new Server();
|
||||
server.on("activity", sendToBridge);
|
||||
server.on("invite", (invite: string, callback: (valid: boolean) => void) => {
|
||||
invite = String(invite);
|
||||
if (!inviteCodeRegex.test(invite)) return callback(false);
|
||||
|
||||
mainWin.webContents
|
||||
// Safety: Result of JSON.stringify should always be safe to equal
|
||||
// Also, just to be super super safe, invite is regex validated above
|
||||
.executeJavaScript(`Vesktop.openInviteModal(${JSON.stringify(invite)})`)
|
||||
.then(callback);
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("Failed to start arRPC server", e);
|
||||
}
|
||||
}
|
||||
|
||||
Settings.addChangeListener("arRPC", initArRPC);
|
||||
49
src/main/autoStart.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { app } from "electron";
|
||||
import { existsSync, mkdirSync, rmSync, writeFileSync } from "fs";
|
||||
import { join } from "path";
|
||||
|
||||
interface AutoStart {
|
||||
isEnabled(): boolean;
|
||||
enable(): void;
|
||||
disable(): void;
|
||||
}
|
||||
|
||||
function makeAutoStartLinux(): AutoStart {
|
||||
const configDir = process.env.XDG_CONFIG_HOME || join(process.env.HOME!, ".config");
|
||||
const dir = join(configDir, "autostart");
|
||||
const file = join(dir, "vencord.desktop");
|
||||
|
||||
return {
|
||||
isEnabled: () => existsSync(file),
|
||||
enable() {
|
||||
const desktopFile = `
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
Version=1.0
|
||||
Name=Vencord
|
||||
Comment=Vencord autostart script
|
||||
Exec=${process.execPath}
|
||||
Terminal=false
|
||||
StartupNotify=false
|
||||
`.trim();
|
||||
|
||||
mkdirSync(dir, { recursive: true });
|
||||
writeFileSync(file, desktopFile);
|
||||
},
|
||||
disable: () => rmSync(file, { force: true })
|
||||
};
|
||||
}
|
||||
|
||||
const autoStartWindowsMac: AutoStart = {
|
||||
isEnabled: () => app.getLoginItemSettings().openAtLogin,
|
||||
enable: () => app.setLoginItemSettings({ openAtLogin: true }),
|
||||
disable: () => app.setLoginItemSettings({ openAtLogin: false })
|
||||
};
|
||||
|
||||
export const autoStart = process.platform === "linux" ? makeAutoStartLinux() : autoStartWindowsMac;
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
@@ -17,7 +17,7 @@ export const VENCORD_SETTINGS_FILE = join(VENCORD_SETTINGS_DIR, "settings.json")
|
||||
export const VENCORD_FILES_DIR =
|
||||
(require("./settings") as typeof import("./settings")).Settings.store.vencordDir || join(DATA_DIR, "vencordDist");
|
||||
|
||||
export const USER_AGENT = `VencordDesktop/${app.getVersion()} (https://github.com/Vencord/Electron)`;
|
||||
export const USER_AGENT = `Vesktop/${app.getVersion()} (https://github.com/Vencord/Vesktop)`;
|
||||
|
||||
// dimensions shamelessly stolen from Discord Desktop :3
|
||||
export const MIN_WIDTH = 940;
|
||||
|
||||
72
src/main/firstLaunch.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { app } from "electron";
|
||||
import { BrowserWindow } from "electron/main";
|
||||
import { copyFileSync, mkdirSync, readdirSync } from "fs";
|
||||
import { join } from "path";
|
||||
import { SplashProps } from "shared/browserWinProperties";
|
||||
import { VIEW_DIR } from "shared/paths";
|
||||
|
||||
import { autoStart } from "./autoStart";
|
||||
import { DATA_DIR } from "./constants";
|
||||
import { createWindows } from "./mainWindow";
|
||||
import { Settings } from "./settings";
|
||||
import { makeLinksOpenExternally } from "./utils/makeLinksOpenExternally";
|
||||
|
||||
interface Data {
|
||||
minimizeToTray: boolean;
|
||||
discordBranch: "stable" | "canary" | "ptb";
|
||||
autoStart: boolean;
|
||||
importSettings: boolean;
|
||||
richPresence: boolean;
|
||||
}
|
||||
|
||||
export function createFirstLaunchTour() {
|
||||
const win = new BrowserWindow({
|
||||
...SplashProps,
|
||||
frame: true,
|
||||
autoHideMenuBar: true,
|
||||
height: 470,
|
||||
width: 550
|
||||
});
|
||||
|
||||
makeLinksOpenExternally(win);
|
||||
|
||||
win.loadFile(join(VIEW_DIR, "first-launch.html"));
|
||||
win.webContents.addListener("console-message", (_e, _l, msg) => {
|
||||
if (msg === "cancel") return app.exit();
|
||||
|
||||
if (!msg.startsWith("form:")) return;
|
||||
const data = JSON.parse(msg.slice(5)) as Data;
|
||||
|
||||
Settings.store.minimizeToTray = data.minimizeToTray;
|
||||
Settings.store.discordBranch = data.discordBranch;
|
||||
Settings.store.firstLaunch = false;
|
||||
Settings.store.arRPC = data.richPresence;
|
||||
|
||||
if (data.autoStart) autoStart.enable();
|
||||
|
||||
if (data.importSettings) {
|
||||
const from = join(app.getPath("userData"), "..", "Vencord", "settings");
|
||||
const to = join(DATA_DIR, "settings");
|
||||
try {
|
||||
const files = readdirSync(from);
|
||||
mkdirSync(to, { recursive: true });
|
||||
|
||||
for (const file of files) {
|
||||
copyFileSync(join(from, file), join(to, file));
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to import settings:", e);
|
||||
}
|
||||
}
|
||||
|
||||
win.close();
|
||||
|
||||
createWindows();
|
||||
});
|
||||
}
|
||||
@@ -1,22 +1,21 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import "./ipc";
|
||||
|
||||
import { app, BrowserWindow } from "electron";
|
||||
import { join } from "path";
|
||||
import { checkUpdates } from "updater/main";
|
||||
|
||||
import { ICON_PATH } from "../shared/paths";
|
||||
import { once } from "../shared/utils/once";
|
||||
import { DATA_DIR, VENCORD_FILES_DIR } from "./constants";
|
||||
import { createMainWindow } from "./mainWindow";
|
||||
import { DATA_DIR } from "./constants";
|
||||
import { createFirstLaunchTour } from "./firstLaunch";
|
||||
import { createWindows, mainWin } from "./mainWindow";
|
||||
import { registerScreenShareHandler } from "./screenShare";
|
||||
import { Settings } from "./settings";
|
||||
import { createSplashWindow } from "./splash";
|
||||
import { ensureVencordFiles } from "./utils/vencordLoader";
|
||||
|
||||
if (IS_DEV) {
|
||||
require("source-map-support").install();
|
||||
}
|
||||
@@ -24,16 +23,22 @@ if (IS_DEV) {
|
||||
// Make the Vencord files use our DATA_DIR
|
||||
process.env.VENCORD_USER_DATA_DIR = DATA_DIR;
|
||||
|
||||
const runVencordMain = once(() => require(join(VENCORD_FILES_DIR, "vencordDesktopMain.js")));
|
||||
function init() {
|
||||
// work around chrome 66 disabling autoplay by default
|
||||
app.commandLine.appendSwitch("autoplay-policy", "no-user-gesture-required");
|
||||
|
||||
let mainWin: BrowserWindow | null = null;
|
||||
// WinRetrieveSuggestionsOnlyOnDemand: Work around electron 13 bug w/ async spellchecking on Windows.
|
||||
// HardwareMediaKeyHandling,MediaSessionService: Prevent Discord from registering as a media service.
|
||||
//
|
||||
// WidgetLayering (Vencord Added): Fix DevTools context menus https://github.com/electron/electron/issues/38790
|
||||
app.commandLine.appendSwitch(
|
||||
"disable-features",
|
||||
"WinRetrieveSuggestionsOnlyOnDemand,HardwareMediaKeyHandling,MediaSessionService,WidgetLayering"
|
||||
);
|
||||
|
||||
if (!app.requestSingleInstanceLock()) {
|
||||
console.log("Vencord Desktop is already running. Quitting...");
|
||||
app.quit();
|
||||
} else {
|
||||
app.on("second-instance", () => {
|
||||
if (mainWin) {
|
||||
app.on("second-instance", (_event, _cmdLine, _cwd, data: any) => {
|
||||
if (data.IS_DEV) app.quit();
|
||||
else if (mainWin) {
|
||||
if (mainWin.isMinimized()) mainWin.restore();
|
||||
if (!mainWin.isVisible()) mainWin.show();
|
||||
mainWin.focus();
|
||||
@@ -45,7 +50,8 @@ if (!app.requestSingleInstanceLock()) {
|
||||
if (process.platform === "win32") app.setAppUserModelId("dev.vencord.desktop");
|
||||
else if (process.platform === "darwin") app.dock.setIcon(ICON_PATH);
|
||||
|
||||
createWindows();
|
||||
registerScreenShareHandler();
|
||||
bootstrap();
|
||||
|
||||
app.on("activate", () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindows();
|
||||
@@ -53,22 +59,24 @@ if (!app.requestSingleInstanceLock()) {
|
||||
});
|
||||
}
|
||||
|
||||
async function createWindows() {
|
||||
const splash = createSplashWindow();
|
||||
if (!app.requestSingleInstanceLock({ IS_DEV })) {
|
||||
if (IS_DEV) {
|
||||
console.log("Vesktop is already running. Quitting previous instance...");
|
||||
init();
|
||||
} else {
|
||||
console.log("Vesktop is already running. Quitting...");
|
||||
app.quit();
|
||||
}
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
|
||||
await ensureVencordFiles();
|
||||
runVencordMain();
|
||||
|
||||
mainWin = createMainWindow();
|
||||
|
||||
mainWin.once("ready-to-show", () => {
|
||||
splash.destroy();
|
||||
mainWin!.show();
|
||||
|
||||
if (Settings.store.maximized) {
|
||||
mainWin!.maximize();
|
||||
}
|
||||
});
|
||||
async function bootstrap() {
|
||||
if (!Object.hasOwn(Settings.store, "firstLaunch")) {
|
||||
createFirstLaunchTour();
|
||||
} else {
|
||||
createWindows();
|
||||
}
|
||||
}
|
||||
|
||||
app.on("window-all-closed", () => {
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { app, dialog, ipcMain, shell } from "electron";
|
||||
import { app, dialog, ipcMain, session, shell } from "electron";
|
||||
import { existsSync, readFileSync, watch } from "fs";
|
||||
import { open, readFile } from "fs/promises";
|
||||
import { release } from "os";
|
||||
import { join } from "path";
|
||||
import { debounce } from "shared/utils/debounce";
|
||||
|
||||
import { IpcEvents } from "../shared/IpcEvents";
|
||||
import { setBadgeCount } from "./appBadge";
|
||||
import { autoStart } from "./autoStart";
|
||||
import { VENCORD_FILES_DIR, VENCORD_QUICKCSS_FILE } from "./constants";
|
||||
import { mainWin } from "./mainWindow";
|
||||
import { Settings } from "./settings";
|
||||
@@ -39,6 +42,16 @@ ipcMain.on(IpcEvents.GET_VERSION, e => {
|
||||
e.returnValue = app.getVersion();
|
||||
});
|
||||
|
||||
ipcMain.on(IpcEvents.SUPPORTS_WINDOWS_TRANSPARENCY, e => {
|
||||
e.returnValue = process.platform === "win32" && Number(release().split(".").pop()) >= 22621;
|
||||
});
|
||||
|
||||
ipcMain.on(IpcEvents.AUTOSTART_ENABLED, e => {
|
||||
e.returnValue = autoStart.isEnabled();
|
||||
});
|
||||
ipcMain.handle(IpcEvents.ENABLE_AUTOSTART, autoStart.enable);
|
||||
ipcMain.handle(IpcEvents.DISABLE_AUTOSTART, autoStart.disable);
|
||||
|
||||
ipcMain.handle(IpcEvents.SET_SETTINGS, (_, settings: typeof Settings.store, path?: string) => {
|
||||
Settings.setData(settings, path);
|
||||
});
|
||||
@@ -52,14 +65,33 @@ ipcMain.handle(IpcEvents.SHOW_ITEM_IN_FOLDER, (_, path) => {
|
||||
shell.showItemInFolder(path);
|
||||
});
|
||||
|
||||
ipcMain.handle(IpcEvents.FOCUS, e => {
|
||||
e.sender.focus();
|
||||
ipcMain.handle(IpcEvents.FOCUS, () => {
|
||||
if (process.platform === "win32") mainWin.minimize(); // Windows is weird
|
||||
|
||||
mainWin.restore();
|
||||
mainWin.show();
|
||||
});
|
||||
|
||||
ipcMain.handle(IpcEvents.CLOSE, e => {
|
||||
e.sender.close();
|
||||
});
|
||||
|
||||
ipcMain.handle(IpcEvents.SPELLCHECK_SET_LANGUAGES, (_, languages: string[]) => {
|
||||
const ses = session.defaultSession;
|
||||
|
||||
const available = ses.availableSpellCheckerLanguages;
|
||||
const applicable = languages.filter(l => available.includes(l)).slice(0, 3);
|
||||
if (applicable.length) ses.setSpellCheckerLanguages(applicable);
|
||||
});
|
||||
|
||||
ipcMain.handle(IpcEvents.SPELLCHECK_REPLACE_MISSPELLING, (e, word: string) => {
|
||||
e.sender.replaceMisspelling(word);
|
||||
});
|
||||
|
||||
ipcMain.handle(IpcEvents.SPELLCHECK_ADD_TO_DICTIONARY, (e, word: string) => {
|
||||
e.sender.session.addWordToSpellCheckerDictionary(word);
|
||||
});
|
||||
|
||||
ipcMain.handle(IpcEvents.SELECT_VENCORD_DIR, async () => {
|
||||
const res = await dialog.showOpenDialog(mainWin!, {
|
||||
properties: ["openDirectory"]
|
||||
@@ -74,6 +106,8 @@ ipcMain.handle(IpcEvents.SELECT_VENCORD_DIR, async () => {
|
||||
return dir;
|
||||
});
|
||||
|
||||
ipcMain.handle(IpcEvents.SET_BADGE_COUNT, (_, count: number) => setBadgeCount(count));
|
||||
|
||||
function readCss() {
|
||||
return readFile(VENCORD_QUICKCSS_FILE, "utf-8").catch(() => "");
|
||||
}
|
||||
|
||||
@@ -1,18 +1,33 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { app, BrowserWindow, BrowserWindowConstructorOptions, Menu, Tray } from "electron";
|
||||
import {
|
||||
app,
|
||||
BrowserWindow,
|
||||
BrowserWindowConstructorOptions,
|
||||
dialog,
|
||||
Menu,
|
||||
MenuItemConstructorOptions,
|
||||
Tray
|
||||
} from "electron";
|
||||
import { rm } from "fs/promises";
|
||||
import { join } from "path";
|
||||
import { IpcEvents } from "shared/IpcEvents";
|
||||
import { isTruthy } from "shared/utils/guards";
|
||||
import { once } from "shared/utils/once";
|
||||
import type { SettingsStore } from "shared/utils/SettingsStore";
|
||||
|
||||
import { ICON_PATH } from "../shared/paths";
|
||||
import { createAboutWindow } from "./about";
|
||||
import { DEFAULT_HEIGHT, DEFAULT_WIDTH, MIN_HEIGHT, MIN_WIDTH } from "./constants";
|
||||
import { initArRPC } from "./arrpc";
|
||||
import { DATA_DIR, DEFAULT_HEIGHT, DEFAULT_WIDTH, MIN_HEIGHT, MIN_WIDTH, VENCORD_FILES_DIR } from "./constants";
|
||||
import { Settings, VencordSettings } from "./settings";
|
||||
import { createSplashWindow } from "./splash";
|
||||
import { makeLinksOpenExternally } from "./utils/makeLinksOpenExternally";
|
||||
import { downloadVencordFiles } from "./utils/vencordLoader";
|
||||
import { downloadVencordFiles, ensureVencordFiles } from "./utils/vencordLoader";
|
||||
|
||||
let isQuitting = false;
|
||||
let tray: Tray;
|
||||
@@ -23,6 +38,27 @@ app.on("before-quit", () => {
|
||||
|
||||
export let mainWin: BrowserWindow;
|
||||
|
||||
function makeSettingsListenerHelpers<O extends object>(o: SettingsStore<O>) {
|
||||
const listeners = new Map<(data: any) => void, PropertyKey>();
|
||||
|
||||
const addListener: typeof o.addChangeListener = (path, cb) => {
|
||||
listeners.set(cb, path);
|
||||
o.addChangeListener(path, cb);
|
||||
};
|
||||
const removeAllListeners = () => {
|
||||
for (const [listener, path] of listeners) {
|
||||
o.removeChangeListener(path as any, listener);
|
||||
}
|
||||
|
||||
listeners.clear();
|
||||
};
|
||||
|
||||
return [addListener, removeAllListeners] as const;
|
||||
}
|
||||
|
||||
const [addSettingsListener, removeSettingsListeners] = makeSettingsListenerHelpers(Settings);
|
||||
const [addVencordSettingsListener, removeVencordSettingsListeners] = makeSettingsListenerHelpers(VencordSettings);
|
||||
|
||||
function initTray(win: BrowserWindow) {
|
||||
const trayMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
@@ -44,6 +80,12 @@ function initTray(win: BrowserWindow) {
|
||||
app.quit();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Reset Vesktop",
|
||||
async click() {
|
||||
await clearData(win);
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "separator"
|
||||
},
|
||||
@@ -55,7 +97,7 @@ function initTray(win: BrowserWindow) {
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Quit Vencord Desktop",
|
||||
label: "Quit Vesktop",
|
||||
click() {
|
||||
isQuitting = true;
|
||||
app.quit();
|
||||
@@ -64,7 +106,7 @@ function initTray(win: BrowserWindow) {
|
||||
]);
|
||||
|
||||
tray = new Tray(ICON_PATH);
|
||||
tray.setToolTip("Vencord Desktop");
|
||||
tray.setToolTip("Vesktop");
|
||||
tray.setContextMenu(trayMenu);
|
||||
tray.on("click", () => win.show());
|
||||
|
||||
@@ -77,98 +119,112 @@ function initTray(win: BrowserWindow) {
|
||||
});
|
||||
}
|
||||
|
||||
const enum MessageBoxChoice {
|
||||
Default,
|
||||
Cancel
|
||||
}
|
||||
|
||||
async function clearData(win: BrowserWindow) {
|
||||
const { response } = await dialog.showMessageBox(win, {
|
||||
message: "Are you sure you want to reset Vesktop?",
|
||||
detail: "This will log you out, clear caches and reset all your settings!\n\nVesktop will automatically restart after this operation.",
|
||||
buttons: ["Yes", "No"],
|
||||
cancelId: MessageBoxChoice.Cancel,
|
||||
defaultId: MessageBoxChoice.Default,
|
||||
type: "warning"
|
||||
});
|
||||
|
||||
if (response === MessageBoxChoice.Cancel) return;
|
||||
|
||||
win.close();
|
||||
|
||||
await win.webContents.session.clearStorageData();
|
||||
await win.webContents.session.clearCache();
|
||||
await win.webContents.session.clearCodeCaches({});
|
||||
await rm(DATA_DIR, { force: true, recursive: true });
|
||||
|
||||
app.relaunch();
|
||||
app.quit();
|
||||
}
|
||||
|
||||
function initMenuBar(win: BrowserWindow) {
|
||||
const isWindows = process.platform === "win32";
|
||||
const isDarwin = process.platform === "darwin";
|
||||
const wantCtrlQ = !isWindows || VencordSettings.store.winCtrlQ;
|
||||
|
||||
const subMenu = [
|
||||
{
|
||||
label: "About Vesktop",
|
||||
click: createAboutWindow
|
||||
},
|
||||
{
|
||||
label: "Force Update Vencord",
|
||||
async click() {
|
||||
await downloadVencordFiles();
|
||||
app.relaunch();
|
||||
app.quit();
|
||||
},
|
||||
toolTip: "Vesktop will automatically restart after this operation"
|
||||
},
|
||||
{
|
||||
label: "Reset Vesktop",
|
||||
async click() {
|
||||
await clearData(win);
|
||||
},
|
||||
toolTip: "Vesktop will automatically restart after this operation"
|
||||
},
|
||||
{
|
||||
label: "Relaunch",
|
||||
accelerator: "CmdOrCtrl+Shift+R",
|
||||
click() {
|
||||
app.relaunch();
|
||||
app.quit();
|
||||
}
|
||||
},
|
||||
isDarwin && {
|
||||
label: "Hide",
|
||||
role: "hide"
|
||||
},
|
||||
isDarwin && {
|
||||
label: "Hide others",
|
||||
role: "hideOthers"
|
||||
},
|
||||
{
|
||||
label: "Quit",
|
||||
accelerator: wantCtrlQ ? "CmdOrCtrl+Q" : void 0,
|
||||
visible: !isWindows,
|
||||
role: "quit",
|
||||
click() {
|
||||
app.quit();
|
||||
}
|
||||
},
|
||||
isWindows && {
|
||||
label: "Quit",
|
||||
accelerator: "Alt+F4",
|
||||
role: "quit",
|
||||
click() {
|
||||
app.quit();
|
||||
}
|
||||
},
|
||||
// See https://github.com/electron/electron/issues/14742 and https://github.com/electron/electron/issues/5256
|
||||
{
|
||||
label: "Zoom in (hidden, hack for Qwertz and others)",
|
||||
accelerator: "CmdOrCtrl+=",
|
||||
role: "zoomIn",
|
||||
visible: false
|
||||
}
|
||||
] satisfies Array<MenuItemConstructorOptions | false>;
|
||||
|
||||
const menu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: "Vencord Desktop",
|
||||
submenu: [
|
||||
{
|
||||
label: "About Vencord Desktop",
|
||||
click: createAboutWindow
|
||||
},
|
||||
{
|
||||
label: "Force Update Vencord",
|
||||
async click() {
|
||||
await downloadVencordFiles();
|
||||
app.relaunch();
|
||||
app.quit();
|
||||
},
|
||||
toolTip: "Vencord Desktop will automatically restart after this operation"
|
||||
},
|
||||
{
|
||||
label: "Toggle Developer Tools",
|
||||
accelerator: "CmdOrCtrl+Shift+I",
|
||||
click() {
|
||||
BrowserWindow.getFocusedWindow()!.webContents.toggleDevTools();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Toggle Developer Tools (Hidden)",
|
||||
accelerator: "F12",
|
||||
visible: false,
|
||||
click() {
|
||||
BrowserWindow.getFocusedWindow()!.webContents.toggleDevTools();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Reload Window",
|
||||
accelerator: "CmdOrCtrl+R",
|
||||
click() {
|
||||
BrowserWindow.getFocusedWindow()!.webContents.reload();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Relaunch",
|
||||
accelerator: "CmdOrCtrl+Shift+R",
|
||||
click() {
|
||||
app.relaunch();
|
||||
app.quit();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Quit",
|
||||
accelerator: wantCtrlQ ? "CmdOrCtrl+Q" : void 0,
|
||||
visible: !isWindows,
|
||||
click() {
|
||||
app.quit();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Quit",
|
||||
accelerator: isWindows ? "Alt+F4" : void 0,
|
||||
visible: isWindows,
|
||||
click() {
|
||||
app.quit();
|
||||
}
|
||||
}
|
||||
]
|
||||
label: "Vesktop",
|
||||
role: "appMenu",
|
||||
submenu: subMenu.filter(isTruthy)
|
||||
},
|
||||
{
|
||||
label: "Zoom",
|
||||
submenu: [
|
||||
{
|
||||
label: "Zoom in",
|
||||
accelerator: "CmdOrCtrl+Plus",
|
||||
role: "zoomIn"
|
||||
},
|
||||
// Fix for zoom in on keyboards with dedicated + like QWERTZ (or numpad)
|
||||
// See https://github.com/electron/electron/issues/14742 and https://github.com/electron/electron/issues/5256
|
||||
{
|
||||
label: "Zoom in",
|
||||
accelerator: "CmdOrCtrl+=",
|
||||
role: "zoomIn",
|
||||
visible: false
|
||||
},
|
||||
{
|
||||
label: "Zoom out",
|
||||
accelerator: "CmdOrCtrl+-",
|
||||
role: "zoomOut"
|
||||
}
|
||||
]
|
||||
}
|
||||
{ role: "fileMenu" },
|
||||
{ role: "editMenu" },
|
||||
{ role: "viewMenu" },
|
||||
{ role: "windowMenu" }
|
||||
]);
|
||||
|
||||
Menu.setApplicationMenu(menu);
|
||||
@@ -214,11 +270,11 @@ function initWindowBoundsListeners(win: BrowserWindow) {
|
||||
}
|
||||
|
||||
function initSettingsListeners(win: BrowserWindow) {
|
||||
Settings.addChangeListener("tray", enable => {
|
||||
addSettingsListener("tray", enable => {
|
||||
if (enable) initTray(win);
|
||||
else tray?.destroy();
|
||||
});
|
||||
Settings.addChangeListener("disableMinSize", disable => {
|
||||
addSettingsListener("disableMinSize", disable => {
|
||||
if (disable) {
|
||||
// 0 no work
|
||||
win.setMinimumSize(1, 1);
|
||||
@@ -233,7 +289,7 @@ function initSettingsListeners(win: BrowserWindow) {
|
||||
}
|
||||
});
|
||||
|
||||
VencordSettings.addChangeListener("macosTranslucency", enabled => {
|
||||
addVencordSettingsListener("macosTranslucency", enabled => {
|
||||
if (enabled) {
|
||||
win.setVibrancy("sidebar");
|
||||
win.setBackgroundColor("#ffffff00");
|
||||
@@ -244,42 +300,74 @@ function initSettingsListeners(win: BrowserWindow) {
|
||||
});
|
||||
}
|
||||
|
||||
export function createMainWindow() {
|
||||
function initSpellCheck(win: BrowserWindow) {
|
||||
win.webContents.on("context-menu", (_, data) => {
|
||||
win.webContents.send(IpcEvents.SPELLCHECK_RESULT, data.misspelledWord, data.dictionarySuggestions);
|
||||
});
|
||||
}
|
||||
|
||||
function createMainWindow() {
|
||||
// Clear up previous settings listeners
|
||||
removeSettingsListeners();
|
||||
removeVencordSettingsListeners();
|
||||
|
||||
const { staticTitle, transparencyOption } = Settings.store;
|
||||
const { frameless, macosTranslucency } = VencordSettings.store;
|
||||
const win = (mainWin = new BrowserWindow({
|
||||
show: false,
|
||||
autoHideMenuBar: true,
|
||||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
sandbox: false,
|
||||
contextIsolation: true,
|
||||
devTools: true,
|
||||
preload: join(__dirname, "preload.js")
|
||||
preload: join(__dirname, "preload.js"),
|
||||
spellcheck: true
|
||||
},
|
||||
icon: ICON_PATH,
|
||||
frame: VencordSettings.store.frameless !== true,
|
||||
...(VencordSettings.store.macosTranslucency
|
||||
frame: frameless !== true,
|
||||
...(transparencyOption && transparencyOption !== "none"
|
||||
? {
|
||||
backgroundColor: "#00000000",
|
||||
backgroundMaterial: Settings.store.transparencyOption,
|
||||
transparent: true
|
||||
}
|
||||
: {}),
|
||||
...(staticTitle ? { title: "Vencord" } : {}),
|
||||
...(macosTranslucency
|
||||
? {
|
||||
vibrancy: "sidebar",
|
||||
backgroundColor: "#ffffff00"
|
||||
}
|
||||
: {}),
|
||||
...(process.platform === "darwin" ? { titleBarStyle: "hiddenInset" } : {}),
|
||||
...getWindowBoundsOptions()
|
||||
}));
|
||||
win.setMenuBarVisibility(false);
|
||||
|
||||
win.on("close", e => {
|
||||
if (isQuitting || Settings.store.minimizeToTray === false || Settings.store.tray === false) return;
|
||||
const useTray = Settings.store.minimizeToTray && Settings.store.tray;
|
||||
if (isQuitting || (process.platform !== "darwin" && !useTray)) return;
|
||||
|
||||
e.preventDefault();
|
||||
win.hide();
|
||||
|
||||
if (process.platform === "darwin") app.hide();
|
||||
else win.hide();
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (Settings.store.staticTitle) win.on("page-title-updated", e => e.preventDefault());
|
||||
|
||||
initWindowBoundsListeners(win);
|
||||
if (Settings.store.tray ?? true) initTray(win);
|
||||
initMenuBar(win);
|
||||
makeLinksOpenExternally(win);
|
||||
initSettingsListeners(win);
|
||||
initSpellCheck(win);
|
||||
|
||||
win.webContents.setUserAgent(
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36"
|
||||
);
|
||||
|
||||
const subdomain =
|
||||
Settings.store.discordBranch === "canary" || Settings.store.discordBranch === "ptb"
|
||||
@@ -290,3 +378,25 @@ export function createMainWindow() {
|
||||
|
||||
return win;
|
||||
}
|
||||
|
||||
const runVencordMain = once(() => require(join(VENCORD_FILES_DIR, "vencordDesktopMain.js")));
|
||||
|
||||
export async function createWindows() {
|
||||
const splash = createSplashWindow();
|
||||
|
||||
await ensureVencordFiles();
|
||||
runVencordMain();
|
||||
|
||||
mainWin = createMainWindow();
|
||||
|
||||
mainWin.once("ready-to-show", () => {
|
||||
splash.destroy();
|
||||
mainWin!.show();
|
||||
|
||||
if (Settings.store.maximized) {
|
||||
mainWin!.maximize();
|
||||
}
|
||||
});
|
||||
|
||||
initArRPC();
|
||||
}
|
||||
|
||||
55
src/main/screenShare.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { desktopCapturer, ipcMain, session, Streams } from "electron";
|
||||
import type { StreamPick } from "renderer/components/ScreenSharePicker";
|
||||
import { IpcEvents } from "shared/IpcEvents";
|
||||
|
||||
export function registerScreenShareHandler() {
|
||||
ipcMain.handle(IpcEvents.CAPTURER_GET_LARGE_THUMBNAIL, async (_, id: string) => {
|
||||
const sources = await desktopCapturer.getSources({
|
||||
types: ["window", "screen"],
|
||||
thumbnailSize: {
|
||||
width: 1920,
|
||||
height: 1080
|
||||
}
|
||||
});
|
||||
return sources.find(s => s.id === id)?.thumbnail.toDataURL();
|
||||
});
|
||||
|
||||
session.defaultSession.setDisplayMediaRequestHandler(async (request, callback) => {
|
||||
const sources = await desktopCapturer.getSources({
|
||||
types: ["window", "screen"],
|
||||
thumbnailSize: {
|
||||
width: 176,
|
||||
height: 99
|
||||
}
|
||||
});
|
||||
|
||||
const data = sources.map(({ id, name, thumbnail }) => ({
|
||||
id,
|
||||
name,
|
||||
url: thumbnail.toDataURL()
|
||||
}));
|
||||
|
||||
const choice = await request.frame
|
||||
.executeJavaScript(`Vesktop.Components.ScreenShare.openScreenSharePicker(${JSON.stringify(data)})`)
|
||||
.then(e => e as StreamPick)
|
||||
.catch(() => null);
|
||||
|
||||
if (!choice) return callback({});
|
||||
|
||||
const source = sources.find(s => s.id === choice.id);
|
||||
if (!source) return callback({});
|
||||
|
||||
const streams: Streams = {
|
||||
video: source
|
||||
};
|
||||
if (choice.audio && process.platform === "win32") streams.audio = "loopback";
|
||||
|
||||
callback(streams);
|
||||
});
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { readFileSync, writeFileSync } from "fs";
|
||||
import { join } from "path";
|
||||
import { mkdirSync, readFileSync, writeFileSync } from "fs";
|
||||
import { dirname, join } from "path";
|
||||
import type { Settings as TSettings } from "shared/settings";
|
||||
import { SettingsStore } from "shared/utils/SettingsStore";
|
||||
|
||||
@@ -25,10 +25,13 @@ function loadSettings<T extends object = any>(file: string, name: string) {
|
||||
} catch {}
|
||||
|
||||
const store = new SettingsStore(settings);
|
||||
store.addGlobalChangeListener(o => writeFileSync(file, JSON.stringify(o, null, 4)));
|
||||
store.addGlobalChangeListener(o => {
|
||||
mkdirSync(dirname(file), { recursive: true });
|
||||
writeFileSync(file, JSON.stringify(o, null, 4));
|
||||
});
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
export const Settings = loadSettings<TSettings>(SETTINGS_FILE, "Vencord Desktop");
|
||||
export const Settings = loadSettings<TSettings>(SETTINGS_FILE, "Vesktop");
|
||||
export const VencordSettings = loadSettings<any>(VENCORD_SETTINGS_FILE, "Vencord");
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { BrowserWindow } from "electron";
|
||||
import { join } from "path";
|
||||
import { SplashProps } from "shared/browserWinProperties";
|
||||
import { STATIC_DIR } from "shared/paths";
|
||||
import { VIEW_DIR } from "shared/paths";
|
||||
|
||||
export function createSplashWindow() {
|
||||
const splash = new BrowserWindow(SplashProps);
|
||||
|
||||
splash.loadFile(join(STATIC_DIR, "splash.html"));
|
||||
splash.loadFile(join(VIEW_DIR, "splash.html"));
|
||||
|
||||
return splash;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import type { Settings } from "shared/settings";
|
||||
import type { LiteralUnion } from "type-fest";
|
||||
|
||||
import { IpcEvents } from "../shared/IpcEvents";
|
||||
import { invoke, sendSync } from "./typedIpcs";
|
||||
|
||||
export const VencordDesktopNative = {
|
||||
app: {
|
||||
relaunch: () => invoke<void>(IpcEvents.RELAUNCH),
|
||||
getVersion: () => sendSync<void>(IpcEvents.GET_VERSION)
|
||||
},
|
||||
fileManager: {
|
||||
showItemInFolder: (path: string) => invoke<void>(IpcEvents.SHOW_ITEM_IN_FOLDER, path),
|
||||
selectVencordDir: () => invoke<LiteralUnion<"cancelled" | "invalid", string>>(IpcEvents.SELECT_VENCORD_DIR)
|
||||
},
|
||||
settings: {
|
||||
get: () => sendSync<Settings>(IpcEvents.GET_SETTINGS),
|
||||
set: (settings: Settings, path?: string) => invoke<void>(IpcEvents.SET_SETTINGS, settings, path)
|
||||
},
|
||||
win: {
|
||||
focus: () => invoke<void>(IpcEvents.FOCUS)
|
||||
}
|
||||
};
|
||||
59
src/preload/VesktopNative.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { ipcRenderer } from "electron";
|
||||
import type { Settings } from "shared/settings";
|
||||
import type { LiteralUnion } from "type-fest";
|
||||
|
||||
import { IpcEvents } from "../shared/IpcEvents";
|
||||
import { invoke, sendSync } from "./typedIpc";
|
||||
|
||||
type SpellCheckerResultCallback = (word: string, suggestions: string[]) => void;
|
||||
|
||||
const spellCheckCallbacks = new Set<SpellCheckerResultCallback>();
|
||||
|
||||
ipcRenderer.on(IpcEvents.SPELLCHECK_RESULT, (_, w: string, s: string[]) => {
|
||||
spellCheckCallbacks.forEach(cb => cb(w, s));
|
||||
});
|
||||
|
||||
export const VesktopNative = {
|
||||
app: {
|
||||
relaunch: () => invoke<void>(IpcEvents.RELAUNCH),
|
||||
getVersion: () => sendSync<void>(IpcEvents.GET_VERSION),
|
||||
setBadgeCount: (count: number) => invoke<void>(IpcEvents.SET_BADGE_COUNT, count),
|
||||
supportsWindowsTransparency: () => sendSync<boolean>(IpcEvents.SUPPORTS_WINDOWS_TRANSPARENCY)
|
||||
},
|
||||
autostart: {
|
||||
isEnabled: () => sendSync<boolean>(IpcEvents.AUTOSTART_ENABLED),
|
||||
enable: () => invoke<void>(IpcEvents.ENABLE_AUTOSTART),
|
||||
disable: () => invoke<void>(IpcEvents.DISABLE_AUTOSTART)
|
||||
},
|
||||
fileManager: {
|
||||
showItemInFolder: (path: string) => invoke<void>(IpcEvents.SHOW_ITEM_IN_FOLDER, path),
|
||||
selectVencordDir: () => invoke<LiteralUnion<"cancelled" | "invalid", string>>(IpcEvents.SELECT_VENCORD_DIR)
|
||||
},
|
||||
settings: {
|
||||
get: () => sendSync<Settings>(IpcEvents.GET_SETTINGS),
|
||||
set: (settings: Settings, path?: string) => invoke<void>(IpcEvents.SET_SETTINGS, settings, path)
|
||||
},
|
||||
spellcheck: {
|
||||
setLanguages: (languages: readonly string[]) => invoke<void>(IpcEvents.SPELLCHECK_SET_LANGUAGES, languages),
|
||||
onSpellcheckResult(cb: SpellCheckerResultCallback) {
|
||||
spellCheckCallbacks.add(cb);
|
||||
},
|
||||
offSpellcheckResult(cb: SpellCheckerResultCallback) {
|
||||
spellCheckCallbacks.delete(cb);
|
||||
},
|
||||
replaceMisspelling: (word: string) => invoke<void>(IpcEvents.SPELLCHECK_REPLACE_MISSPELLING, word),
|
||||
addToDictionary: (word: string) => invoke<void>(IpcEvents.SPELLCHECK_ADD_TO_DICTIONARY, word)
|
||||
},
|
||||
win: {
|
||||
focus: () => invoke<void>(IpcEvents.FOCUS)
|
||||
},
|
||||
capturer: {
|
||||
getLargeThumbnail: (id: string) => invoke<string>(IpcEvents.CAPTURER_GET_LARGE_THUMBNAIL, id)
|
||||
}
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
@@ -8,9 +8,11 @@ import { contextBridge, ipcRenderer, webFrame } from "electron";
|
||||
import { readFileSync, watch } from "fs";
|
||||
|
||||
import { IpcEvents } from "../shared/IpcEvents";
|
||||
import { VencordDesktopNative } from "./VencordDesktopNative";
|
||||
import { VesktopNative } from "./VesktopNative";
|
||||
|
||||
contextBridge.exposeInMainWorld("VencordDesktopNative", VencordDesktopNative);
|
||||
contextBridge.exposeInMainWorld("VesktopNative", VesktopNative);
|
||||
// TODO: remove legacy alias once main Vencord codebase has migrated and some time has passed
|
||||
contextBridge.exposeInMainWorld("VencordDesktopNative", VesktopNative);
|
||||
|
||||
require(ipcRenderer.sendSync(IpcEvents.GET_VENCORD_PRELOAD_FILE));
|
||||
|
||||
@@ -39,5 +41,6 @@ if (IS_DEV) {
|
||||
document.getElementById("vcd-css-core")!.textContent = readFileSync(rendererCss, "utf-8");
|
||||
});
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
VesktopNative.spellcheck.setLanguages(window.navigator.languages);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
43
src/renderer/appBadge.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { filters, waitFor } from "@vencord/types/webpack";
|
||||
import { RelationshipStore } from "@vencord/types/webpack/common";
|
||||
|
||||
import { Settings } from "./settings";
|
||||
|
||||
let GuildReadStateStore: any;
|
||||
let NotificationSettingsStore: any;
|
||||
|
||||
export function setBadge() {
|
||||
if (Settings.store.appBadge === false) return;
|
||||
|
||||
const mentionCount = GuildReadStateStore.getTotalMentionCount();
|
||||
const pendingRequests = RelationshipStore.getPendingCount();
|
||||
const hasUnread = GuildReadStateStore.hasAnyUnread();
|
||||
const disableUnreadBadge = NotificationSettingsStore.getDisableUnreadBadge();
|
||||
|
||||
let totalCount = mentionCount + pendingRequests;
|
||||
if (!totalCount && hasUnread && !disableUnreadBadge) totalCount = -1;
|
||||
|
||||
VesktopNative.app.setBadgeCount(totalCount);
|
||||
}
|
||||
|
||||
let toFind = 3;
|
||||
|
||||
function waitForAndSubscribeToStore(name: string, cb?: (m: any) => void) {
|
||||
waitFor(filters.byStoreName(name), store => {
|
||||
cb?.(store);
|
||||
store.addChangeListener(setBadge);
|
||||
|
||||
toFind--;
|
||||
if (toFind === 0) setBadge();
|
||||
});
|
||||
}
|
||||
|
||||
waitForAndSubscribeToStore("GuildReadStateStore", store => (GuildReadStateStore = store));
|
||||
waitForAndSubscribeToStore("NotificationSettingsStore", store => (NotificationSettingsStore = store));
|
||||
waitForAndSubscribeToStore("RelationshipStore");
|
||||
274
src/renderer/components/ScreenSharePicker.tsx
Normal file
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import "./screenSharePicker.css";
|
||||
|
||||
import { closeModal, Modals, openModal, useAwaiter } from "@vencord/types/utils";
|
||||
import { findStoreLazy } from "@vencord/types/webpack";
|
||||
import { Button, Card, Forms, Switch, Text, useState } from "@vencord/types/webpack/common";
|
||||
import type { Dispatch, SetStateAction } from "react";
|
||||
import { addPatch } from "renderer/patches/shared";
|
||||
import { isWindows } from "renderer/utils";
|
||||
|
||||
const StreamResolutions = ["480", "720", "1080", "1440"] as const;
|
||||
const StreamFps = ["15", "30", "60"] as const;
|
||||
|
||||
const MediaEngineStore = findStoreLazy("MediaEngineStore");
|
||||
|
||||
export type StreamResolution = (typeof StreamResolutions)[number];
|
||||
export type StreamFps = (typeof StreamFps)[number];
|
||||
|
||||
interface StreamSettings {
|
||||
resolution: StreamResolution;
|
||||
fps: StreamFps;
|
||||
audio: boolean;
|
||||
}
|
||||
|
||||
export interface StreamPick extends StreamSettings {
|
||||
id: string;
|
||||
}
|
||||
|
||||
interface Source {
|
||||
id: string;
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
let currentSettings: StreamSettings | null = null;
|
||||
|
||||
addPatch({
|
||||
patches: [
|
||||
{
|
||||
find: "this.localWant=",
|
||||
replacement: {
|
||||
match: /this.localWant=/,
|
||||
replace: "$self.patchStreamQuality(this);$&"
|
||||
}
|
||||
}
|
||||
],
|
||||
patchStreamQuality(opts: any) {
|
||||
if (!currentSettings) return;
|
||||
|
||||
const framerate = Number(currentSettings.fps);
|
||||
const height = Number(currentSettings.resolution);
|
||||
const width = Math.round(height * (16 / 9));
|
||||
|
||||
Object.assign(opts, {
|
||||
bitrateMin: 500000,
|
||||
bitrateMax: 8000000,
|
||||
bitrateTarget: 600000
|
||||
});
|
||||
Object.assign(opts.capture, {
|
||||
framerate,
|
||||
width,
|
||||
height,
|
||||
pixelCount: height * width
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export function openScreenSharePicker(screens: Source[]) {
|
||||
return new Promise<StreamPick>((resolve, reject) => {
|
||||
const key = openModal(
|
||||
props => (
|
||||
<ModalComponent
|
||||
screens={screens}
|
||||
modalProps={props}
|
||||
submit={resolve}
|
||||
close={() => {
|
||||
props.onClose();
|
||||
reject("Aborted");
|
||||
}}
|
||||
/>
|
||||
),
|
||||
{
|
||||
onCloseRequest() {
|
||||
closeModal(key);
|
||||
reject("Aborted");
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function ScreenPicker({ screens, chooseScreen }: { screens: Source[]; chooseScreen: (id: string) => void }) {
|
||||
return (
|
||||
<div className="vcd-screen-picker-grid">
|
||||
{screens.map(({ id, name, url }) => (
|
||||
<label key={id}>
|
||||
<input type="radio" name="screen" value={id} onChange={() => chooseScreen(id)} />
|
||||
|
||||
<img src={url} alt="" />
|
||||
<Text variant="text-sm/normal">{name}</Text>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function StreamSettings({
|
||||
source,
|
||||
settings,
|
||||
setSettings
|
||||
}: {
|
||||
source: Source;
|
||||
settings: StreamSettings;
|
||||
setSettings: Dispatch<SetStateAction<StreamSettings>>;
|
||||
}) {
|
||||
const [thumb] = useAwaiter(() => VesktopNative.capturer.getLargeThumbnail(source.id), {
|
||||
fallbackValue: source.url,
|
||||
deps: [source.id]
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Forms.FormTitle>What you're streaming</Forms.FormTitle>
|
||||
<Card className="vcd-screen-picker-card vcd-screen-picker-preview">
|
||||
<img src={thumb} alt="" />
|
||||
<Text variant="text-sm/normal">{source.name}</Text>
|
||||
</Card>
|
||||
|
||||
<Forms.FormTitle>Stream Settings</Forms.FormTitle>
|
||||
|
||||
<Card className="vcd-screen-picker-card">
|
||||
<div className="vcd-screen-picker-quality">
|
||||
<section>
|
||||
<Forms.FormTitle>Resolution</Forms.FormTitle>
|
||||
<div className="vcd-screen-picker-radios">
|
||||
{StreamResolutions.map(res => (
|
||||
<label className="vcd-screen-picker-radio" data-checked={settings.resolution === res}>
|
||||
<Text variant="text-sm/bold">{res}</Text>
|
||||
<input
|
||||
type="radio"
|
||||
name="resolution"
|
||||
value={res}
|
||||
checked={settings.resolution === res}
|
||||
onChange={() => setSettings(s => ({ ...s, resolution: res }))}
|
||||
/>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<Forms.FormTitle>Frame Rate</Forms.FormTitle>
|
||||
<div className="vcd-screen-picker-radios">
|
||||
{StreamFps.map(fps => (
|
||||
<label className="vcd-screen-picker-radio" data-checked={settings.fps === fps}>
|
||||
<Text variant="text-sm/bold">{fps}</Text>
|
||||
<input
|
||||
type="radio"
|
||||
name="fps"
|
||||
value={fps}
|
||||
checked={settings.fps === fps}
|
||||
onChange={() => setSettings(s => ({ ...s, fps }))}
|
||||
/>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
{isWindows && (
|
||||
<Switch
|
||||
value={settings.audio}
|
||||
onChange={checked => setSettings(s => ({ ...s, audio: checked }))}
|
||||
hideBorder
|
||||
className="vcd-screen-picker-audio"
|
||||
>
|
||||
Stream With Audio
|
||||
</Switch>
|
||||
)}
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ModalComponent({
|
||||
screens,
|
||||
modalProps,
|
||||
submit,
|
||||
close
|
||||
}: {
|
||||
screens: Source[];
|
||||
modalProps: any;
|
||||
submit: (data: StreamPick) => void;
|
||||
close: () => void;
|
||||
}) {
|
||||
const [selected, setSelected] = useState<string>();
|
||||
const [settings, setSettings] = useState<StreamSettings>({
|
||||
resolution: "1080",
|
||||
fps: "60",
|
||||
audio: true
|
||||
});
|
||||
|
||||
return (
|
||||
<Modals.ModalRoot {...modalProps}>
|
||||
<Modals.ModalHeader className="vcd-screen-picker-header">
|
||||
<Forms.FormTitle tag="h2">ScreenShare</Forms.FormTitle>
|
||||
<Modals.ModalCloseButton onClick={close} />
|
||||
</Modals.ModalHeader>
|
||||
|
||||
<Modals.ModalContent className="vcd-screen-picker-modal">
|
||||
{!selected ? (
|
||||
<ScreenPicker screens={screens} chooseScreen={setSelected} />
|
||||
) : (
|
||||
<StreamSettings
|
||||
source={screens.find(s => s.id === selected)!}
|
||||
settings={settings}
|
||||
setSettings={setSettings}
|
||||
/>
|
||||
)}
|
||||
</Modals.ModalContent>
|
||||
|
||||
<Modals.ModalFooter className="vcd-screen-picker-footer">
|
||||
<Button
|
||||
disabled={!selected}
|
||||
onClick={() => {
|
||||
currentSettings = settings;
|
||||
|
||||
// If there are 2 connections, the second one is the existing stream.
|
||||
// In that case, we patch its quality
|
||||
const conn = [...MediaEngineStore.getMediaEngine().connections][1];
|
||||
if (conn && conn.videoStreamParameters.length > 0) {
|
||||
const height = Number(settings.resolution);
|
||||
const width = Math.round(height * (16 / 9));
|
||||
Object.assign(conn.videoStreamParameters[0], {
|
||||
maxFrameRate: Number(settings.fps),
|
||||
maxPixelCount: width * height,
|
||||
maxBitrate: 8000000,
|
||||
maxResolution: {
|
||||
type: "fixed",
|
||||
width,
|
||||
height
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
submit({
|
||||
id: selected!,
|
||||
...settings
|
||||
});
|
||||
|
||||
close();
|
||||
}}
|
||||
>
|
||||
Go Live
|
||||
</Button>
|
||||
|
||||
{selected ? (
|
||||
<Button color={Button.Colors.TRANSPARENT} onClick={() => setSelected(void 0)}>
|
||||
Back
|
||||
</Button>
|
||||
) : (
|
||||
<Button color={Button.Colors.TRANSPARENT} onClick={close}>
|
||||
Cancel
|
||||
</Button>
|
||||
)}
|
||||
</Modals.ModalFooter>
|
||||
</Modals.ModalRoot>
|
||||
);
|
||||
}
|
||||
@@ -1,35 +1,33 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import "./settings.css";
|
||||
|
||||
import { Margins } from "@vencord/types/utils";
|
||||
import { Button, Forms, Select, Switch, Text, useState } from "@vencord/types/webpack/common";
|
||||
import { setBadge } from "renderer/appBadge";
|
||||
import { useSettings } from "renderer/settings";
|
||||
|
||||
import { Common, Util } from "../vencord";
|
||||
|
||||
const { Margins } = Util;
|
||||
|
||||
export default function SettingsUi() {
|
||||
const Settings = useSettings();
|
||||
const {
|
||||
Forms: { FormSection, FormText, FormDivider, FormSwitch, FormTitle },
|
||||
Text,
|
||||
Select,
|
||||
Button
|
||||
} = Common;
|
||||
const supportsWindowsTransparency = VesktopNative.app.supportsWindowsTransparency();
|
||||
|
||||
const { autostart } = VesktopNative;
|
||||
const [autoStartEnabled, setAutoStartEnabled] = useState(autostart.isEnabled());
|
||||
|
||||
const switches: [keyof typeof Settings, string, string, boolean?, (() => boolean)?][] = [
|
||||
["tray", "Tray Icon", "Add a tray icon for Vencord Desktop", true],
|
||||
["tray", "Tray Icon", "Add a tray icon for Vesktop", true],
|
||||
[
|
||||
"minimizeToTray",
|
||||
"Minimize to tray",
|
||||
"Hitting X will make Vencord Desktop minimize to the tray instead of closing",
|
||||
"Hitting X will make Vesktop minimize to the tray instead of closing",
|
||||
true,
|
||||
() => Settings.tray ?? true
|
||||
],
|
||||
["arRPC", "Rich Presence", "Enables Rich Presence via arRPC", false],
|
||||
[
|
||||
"disableMinSize",
|
||||
"Disable minimum window size",
|
||||
@@ -38,17 +36,18 @@ export default function SettingsUi() {
|
||||
[
|
||||
"openLinksWithElectron",
|
||||
"Open Links in app (experimental)",
|
||||
"Opens links in a new Vencord Desktop window instead of your web browser"
|
||||
]
|
||||
"Opens links in a new Vesktop window instead of your web browser"
|
||||
],
|
||||
["staticTitle", "Static Title", 'Makes the window title "Vencord" instead of changing to the current page']
|
||||
];
|
||||
|
||||
return (
|
||||
<FormSection>
|
||||
<Forms.FormSection>
|
||||
<Text variant="heading-lg/semibold" style={{ color: "var(--header-primary)" }} tag="h2">
|
||||
Vencord Desktop Settings
|
||||
Vesktop Settings
|
||||
</Text>
|
||||
|
||||
<FormTitle className={Margins.top16}>Discord Branch</FormTitle>
|
||||
<Forms.FormTitle className={Margins.top16 + " " + Margins.bottom8}>Discord Branch</Forms.FormTitle>
|
||||
<Select
|
||||
placeholder="Stable"
|
||||
options={[
|
||||
@@ -62,29 +61,89 @@ export default function SettingsUi() {
|
||||
serialize={s => s}
|
||||
/>
|
||||
|
||||
<FormDivider className={Margins.top16 + " " + Margins.bottom16} />
|
||||
<Forms.FormDivider className={Margins.top16 + " " + Margins.bottom16} />
|
||||
|
||||
<Switch
|
||||
value={autoStartEnabled}
|
||||
onChange={async v => {
|
||||
await autostart[v ? "enable" : "disable"]();
|
||||
setAutoStartEnabled(v);
|
||||
}}
|
||||
note="Automatically start Vesktop on computer start-up"
|
||||
>
|
||||
Start With System
|
||||
</Switch>
|
||||
|
||||
<Switch
|
||||
value={Settings.appBadge ?? true}
|
||||
onChange={v => {
|
||||
Settings.appBadge = v;
|
||||
if (v) setBadge();
|
||||
else VesktopNative.app.setBadgeCount(0);
|
||||
}}
|
||||
note="Show mention badge on the app icon"
|
||||
>
|
||||
Notification Badge
|
||||
</Switch>
|
||||
|
||||
{switches.map(([key, text, note, def, predicate]) => (
|
||||
<FormSwitch
|
||||
value={(Settings[key] ?? def ?? false) && (!predicate || predicate())}
|
||||
<Switch
|
||||
value={(Settings[key as any] ?? def ?? false) && predicate?.() !== false}
|
||||
disabled={predicate && !predicate()}
|
||||
onChange={v => (Settings[key] = v)}
|
||||
onChange={v => (Settings[key as any] = v)}
|
||||
note={note}
|
||||
key={key}
|
||||
>
|
||||
{text}
|
||||
</FormSwitch>
|
||||
</Switch>
|
||||
))}
|
||||
|
||||
<FormTitle>Vencord Location</FormTitle>
|
||||
<FormText>
|
||||
{supportsWindowsTransparency && (
|
||||
<>
|
||||
<Forms.FormTitle className={Margins.top16 + " " + Margins.bottom8}>
|
||||
Transparency Options
|
||||
</Forms.FormTitle>
|
||||
<Forms.FormText className={Margins.bottom8}>
|
||||
Requires a full restart. You will need a theme that supports transparency for this to work.
|
||||
</Forms.FormText>
|
||||
|
||||
<Select
|
||||
placeholder="None"
|
||||
options={[
|
||||
{
|
||||
label: "None",
|
||||
value: "none",
|
||||
default: true
|
||||
},
|
||||
{
|
||||
label: "Mica (incorporates system theme + desktop wallpaper to paint the background)",
|
||||
value: "mica"
|
||||
},
|
||||
{ label: "Tabbed (variant of Mica with stronger background tinting)", value: "tabbed" },
|
||||
{
|
||||
label: "Acrylic (blurs the window behind Vesktop for a translucent background)",
|
||||
value: "acrylic"
|
||||
}
|
||||
]}
|
||||
closeOnSelect={true}
|
||||
select={v => (Settings.transparencyOption = v)}
|
||||
isSelected={v => v === Settings.transparencyOption}
|
||||
serialize={s => s}
|
||||
/>
|
||||
|
||||
<Forms.FormDivider className={Margins.top16 + " " + Margins.bottom16} />
|
||||
</>
|
||||
)}
|
||||
|
||||
<Forms.FormTitle>Vencord Location</Forms.FormTitle>
|
||||
<Forms.FormText>
|
||||
Vencord files are loaded from{" "}
|
||||
{Settings.vencordDir ? (
|
||||
<a
|
||||
href="about:blank"
|
||||
onClick={e => {
|
||||
e.preventDefault();
|
||||
VencordDesktopNative.fileManager.showItemInFolder(Settings.vencordDir!);
|
||||
VesktopNative.fileManager.showItemInFolder(Settings.vencordDir!);
|
||||
}}
|
||||
>
|
||||
{Settings.vencordDir}
|
||||
@@ -92,12 +151,12 @@ export default function SettingsUi() {
|
||||
) : (
|
||||
"the default location"
|
||||
)}
|
||||
</FormText>
|
||||
</Forms.FormText>
|
||||
<div className="vcd-location-btns">
|
||||
<Button
|
||||
size={Button.Sizes.SMALL}
|
||||
onClick={async () => {
|
||||
const choice = await VencordDesktopNative.fileManager.selectVencordDir();
|
||||
const choice = await VesktopNative.fileManager.selectVencordDir();
|
||||
switch (choice) {
|
||||
case "cancelled":
|
||||
case "invalid":
|
||||
@@ -117,6 +176,6 @@ export default function SettingsUi() {
|
||||
Reset
|
||||
</Button>
|
||||
</div>
|
||||
</FormSection>
|
||||
</Forms.FormSection>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
export * as ScreenShare from "./ScreenSharePicker";
|
||||
export { default as Settings } from "./Settings";
|
||||
|
||||
124
src/renderer/components/screenSharePicker.css
Normal file
@@ -0,0 +1,124 @@
|
||||
.vcd-screen-picker-modal {
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-header h1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-footer {
|
||||
display: flex;
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 2em 1em;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-grid input {
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-selected img {
|
||||
border: 2px solid var(--brand-experiment);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-grid label {
|
||||
overflow: hidden;
|
||||
padding: 4px 0px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-grid label:hover {
|
||||
outline: 2px solid var(--brand-experiment);
|
||||
}
|
||||
|
||||
|
||||
.vcd-screen-picker-grid div {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
font-weight: 600;
|
||||
margin-inline: 0.5em;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-card {
|
||||
padding: 0.5em;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-preview img {
|
||||
width: 100%;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-preview {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-radio input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-radio {
|
||||
background-color: var(--background-secondary);
|
||||
border: 1px solid var(--primary-800);
|
||||
padding: 0.3em;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-radio h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-radio[data-checked="true"] {
|
||||
background-color: var(--brand-experiment);
|
||||
border-color: var(--brand-experiment);
|
||||
}
|
||||
|
||||
.vcd-screen-picker-radio[data-checked="true"] h2 {
|
||||
color: var(--interactive-active);
|
||||
}
|
||||
|
||||
.vcd-screen-picker-quality {
|
||||
display: flex;
|
||||
gap: 1em;
|
||||
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-quality section {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-radios {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-radios label {
|
||||
flex: 1 1 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-radios label:first-child {
|
||||
border-radius: 3px 0 0 3px;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-radios label:last-child {
|
||||
border-radius: 0 3px 3px 0;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-audio {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import "./hideGarbage.css";
|
||||
|
||||
import { waitFor } from "@vencord/types/webpack";
|
||||
|
||||
import { isFirstRun, localStorage } from "./utils";
|
||||
|
||||
// Make clicking Notifications focus the window
|
||||
@@ -14,18 +16,18 @@ Object.defineProperty(Notification.prototype, "onclick", {
|
||||
set(onClick) {
|
||||
originalSetOnClick.call(this, function (this: unknown) {
|
||||
onClick.apply(this, arguments);
|
||||
VencordDesktopNative.win.focus();
|
||||
VesktopNative.win.focus();
|
||||
});
|
||||
},
|
||||
configurable: true
|
||||
});
|
||||
|
||||
// Enable Desktop Notifications by default
|
||||
if (isFirstRun) {
|
||||
// Hide "Download Discord Desktop now!!!!" banner
|
||||
localStorage.setItem("hideNag", "true");
|
||||
|
||||
Vencord.Webpack.waitFor("setDesktopType", m => {
|
||||
// Enable Desktop Notifications by default
|
||||
waitFor("setDesktopType", m => {
|
||||
m.setDesktopType("all");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,12 +1,48 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import "./fixes";
|
||||
import "./appBadge";
|
||||
import "./patches";
|
||||
|
||||
console.log("read if cute :3");
|
||||
|
||||
export * as Components from "./components";
|
||||
export { Settings } from "./settings";
|
||||
import { findByPropsLazy } from "@vencord/types/webpack";
|
||||
import { FluxDispatcher } from "@vencord/types/webpack/common";
|
||||
|
||||
import { Settings } from "./settings";
|
||||
export { Settings };
|
||||
|
||||
const InviteActions = findByPropsLazy("resolveInvite");
|
||||
|
||||
export async function openInviteModal(code: string) {
|
||||
const { invite } = await InviteActions.resolveInvite(code, "Desktop Modal");
|
||||
if (!invite) return false;
|
||||
|
||||
VesktopNative.win.focus();
|
||||
|
||||
FluxDispatcher.dispatch({
|
||||
type: "INVITE_MODAL_OPEN",
|
||||
invite,
|
||||
code,
|
||||
context: "APP"
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const arRPC = Vencord.Plugins.plugins["WebRichPresence (arRPC)"];
|
||||
|
||||
arRPC.required = !!Settings.store.arRPC;
|
||||
|
||||
Settings.addChangeListener("arRPC", v => {
|
||||
arRPC.required = !!v;
|
||||
if (v && !arRPC.started) Vencord.Plugins.startPlugin(arRPC);
|
||||
else if (arRPC.started) {
|
||||
Vencord.Plugins.stopPlugin(arRPC);
|
||||
}
|
||||
});
|
||||
|
||||
9
src/renderer/patches/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
// TODO: Possibly auto generate glob if we have more patches in the future
|
||||
import "./spellCheck";
|
||||
import "./platformClass";
|
||||
22
src/renderer/patches/platformClass.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { addPatch } from "./shared";
|
||||
|
||||
addPatch({
|
||||
patches: [
|
||||
{
|
||||
find: "platform-web",
|
||||
replacement: {
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
match: /(?<=" platform-overlay"\):)\i/,
|
||||
replace: "$self.getPlatformClass()"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
getPlatformClass: () => (navigator.platform.toLowerCase().startsWith("mac") ? "platform-osx" : "platform-web")
|
||||
});
|
||||
30
src/renderer/patches/shared.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { Patch } from "@vencord/types/utils/types";
|
||||
|
||||
window.VCDP = {};
|
||||
|
||||
interface PatchData {
|
||||
patches: Omit<Patch, "plugin">[];
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export function addPatch<P extends PatchData>(p: P) {
|
||||
const { patches, ...globals } = p;
|
||||
|
||||
for (const patch of patches as Patch[]) {
|
||||
if (!Array.isArray(patch.replacement)) patch.replacement = [patch.replacement];
|
||||
for (const r of patch.replacement) {
|
||||
if (typeof r.replace === "string") r.replace = r.replace.replaceAll("$self", "VCDP");
|
||||
}
|
||||
|
||||
patch.plugin = "Vesktop";
|
||||
Vencord.Plugins.patches.push(patch);
|
||||
}
|
||||
|
||||
Object.assign(VCDP, globals);
|
||||
}
|
||||
83
src/renderer/patches/spellCheck.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { addContextMenuPatch } from "@vencord/types/api/ContextMenu";
|
||||
import { findStoreLazy } from "@vencord/types/webpack";
|
||||
import { ContextMenu, FluxDispatcher, Menu } from "@vencord/types/webpack/common";
|
||||
|
||||
import { addPatch } from "./shared";
|
||||
|
||||
let word: string;
|
||||
let corrections: string[];
|
||||
|
||||
const SpellCheckStore = findStoreLazy("SpellcheckStore");
|
||||
|
||||
// Make spellcheck suggestions work
|
||||
addPatch({
|
||||
patches: [
|
||||
{
|
||||
find: ".enableSpellCheck)",
|
||||
replacement: {
|
||||
// if (isDesktop) { DiscordNative.onSpellcheck(openMenu(props)) } else { e.preventDefault(); openMenu(props) }
|
||||
match: /else\{(.{1,3})\.preventDefault\(\);(.{1,3}\(.{1,3}\))\}(?<=:(.{1,3})\.enableSpellCheck\).+?)/,
|
||||
// ... else { $self.onSlateContext(() => openMenu(props)) }
|
||||
replace: "else {$self.onSlateContext($1, $3?.enableSpellCheck, () => $2)}"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
||||
onSlateContext(e: MouseEvent, hasSpellcheck: boolean | undefined, openMenu: () => void) {
|
||||
if (!hasSpellcheck) {
|
||||
e.preventDefault();
|
||||
openMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
const cb = (w: string, c: string[]) => {
|
||||
VesktopNative.spellcheck.offSpellcheckResult(cb);
|
||||
word = w;
|
||||
corrections = c;
|
||||
openMenu();
|
||||
};
|
||||
VesktopNative.spellcheck.onSpellcheckResult(cb);
|
||||
}
|
||||
});
|
||||
|
||||
addContextMenuPatch("textarea-context", children => () => {
|
||||
const hasCorrections = Boolean(word && corrections?.length);
|
||||
|
||||
children.push(
|
||||
<Menu.MenuGroup>
|
||||
{hasCorrections && (
|
||||
<>
|
||||
{corrections.map(c => (
|
||||
<Menu.MenuItem
|
||||
id={"vcd-spellcheck-suggestion-" + c}
|
||||
label={c}
|
||||
action={() => VesktopNative.spellcheck.replaceMisspelling(c)}
|
||||
/>
|
||||
))}
|
||||
<Menu.MenuSeparator />
|
||||
<Menu.MenuItem
|
||||
id="vcd-spellcheck-learn"
|
||||
label={`Add ${word} to dictionary`}
|
||||
action={() => VesktopNative.spellcheck.addToDictionary(word)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<Menu.MenuCheckboxItem
|
||||
id="vcd-spellcheck-enabled"
|
||||
label="Enable Spellcheck"
|
||||
checked={SpellCheckStore.isEnabled()}
|
||||
action={() => {
|
||||
FluxDispatcher.dispatch({ type: "SPELLCHECK_TOGGLE" });
|
||||
// Haven't found a good way to update state, so just close for now 🤷♀️
|
||||
ContextMenu.close();
|
||||
}}
|
||||
/>
|
||||
</Menu.MenuGroup>
|
||||
);
|
||||
});
|
||||
@@ -1,20 +1,19 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { useEffect, useReducer } from "@vencord/types/webpack/common";
|
||||
import { SettingsStore } from "shared/utils/SettingsStore";
|
||||
|
||||
import { Common } from "./vencord";
|
||||
|
||||
export const Settings = new SettingsStore(VencordDesktopNative.settings.get());
|
||||
Settings.addGlobalChangeListener((o, p) => VencordDesktopNative.settings.set(o, p));
|
||||
export const Settings = new SettingsStore(VesktopNative.settings.get());
|
||||
Settings.addGlobalChangeListener((o, p) => VesktopNative.settings.set(o, p));
|
||||
|
||||
export function useSettings() {
|
||||
const [, update] = Common.React.useReducer(x => x + 1, 0);
|
||||
const [, update] = useReducer(x => x + 1, 0);
|
||||
|
||||
Common.React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
Settings.addGlobalChangeListener(update);
|
||||
|
||||
return () => Settings.removeGlobalChangeListener(update);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
export const localStorage = (window.vcdLS = window.localStorage);
|
||||
export const { localStorage } = window;
|
||||
|
||||
export const isFirstRun = (() => {
|
||||
const key = "VCD_FIRST_RUN";
|
||||
@@ -12,3 +12,7 @@ export const isFirstRun = (() => {
|
||||
localStorage.setItem(key, "false");
|
||||
return true;
|
||||
})();
|
||||
|
||||
const { platform } = navigator;
|
||||
|
||||
export const isWindows = platform.startsWith("Win");
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
// FIXME: this is terrible
|
||||
|
||||
const { Webpack, Plugins, Util } = Vencord;
|
||||
const { Common } = Webpack;
|
||||
const { plugins } = Plugins;
|
||||
|
||||
export { Common, Plugins, plugins, Util, Webpack };
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
@@ -10,10 +10,12 @@ export const enum IpcEvents {
|
||||
GET_RENDERER_SCRIPT = "VCD_GET_RENDERER_SCRIPT",
|
||||
GET_RENDERER_CSS_FILE = "VCD_GET_RENDERER_CSS_FILE",
|
||||
|
||||
RELAUNCH = "VCD_RELAUNCH",
|
||||
FOCUS = "VCD_FOCUS",
|
||||
|
||||
GET_VERSION = "VCD_GET_VERSION",
|
||||
SUPPORTS_WINDOWS_TRANSPARENCY = "VCD_SUPPORTS_WINDOWS_TRANSPARENCY",
|
||||
|
||||
RELAUNCH = "VCD_RELAUNCH",
|
||||
CLOSE = "VCD_CLOSE",
|
||||
FOCUS = "VCD_FOCUS",
|
||||
|
||||
SHOW_ITEM_IN_FOLDER = "VCD_SHOW_ITEM_IN_FOLDER",
|
||||
GET_SETTINGS = "VCD_GET_SETTINGS",
|
||||
@@ -25,5 +27,16 @@ export const enum IpcEvents {
|
||||
UPDATER_DOWNLOAD = "VCD_UPDATER_DOWNLOAD",
|
||||
UPDATE_IGNORE = "VCD_UPDATE_IGNORE",
|
||||
|
||||
CLOSE = "VCD_CLOSE"
|
||||
SPELLCHECK_SET_LANGUAGES = "VCD_SPELLCHECK_SET_LANGUAGES",
|
||||
SPELLCHECK_RESULT = "VCD_SPELLCHECK_RESULT",
|
||||
SPELLCHECK_REPLACE_MISSPELLING = "VCD_SPELLCHECK_REPLACE_MISSPELLING",
|
||||
SPELLCHECK_ADD_TO_DICTIONARY = "VCD_SPELLCHECK_ADD_TO_DICTIONARY",
|
||||
|
||||
SET_BADGE_COUNT = "VCD_SET_BADGE_COUNT",
|
||||
|
||||
CAPTURER_GET_LARGE_THUMBNAIL = "VCD_CAPTURER_GET_LARGE_THUMBNAIL",
|
||||
|
||||
AUTOSTART_ENABLED = "VCD_AUTOSTART_ENABLED",
|
||||
ENABLE_AUTOSTART = "VCD_ENABLE_AUTOSTART",
|
||||
DISABLE_AUTOSTART = "VCD_DISABLE_AUTOSTART"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { join } from "path";
|
||||
|
||||
export const STATIC_DIR = /* @__PURE__ */ join(__dirname, "..", "..", "static");
|
||||
export const VIEW_DIR = /* @__PURE__ */ join(STATIC_DIR, "views");
|
||||
export const BADGE_DIR = /* @__PURE__ */ join(STATIC_DIR, "badges");
|
||||
export const ICON_PATH = /* @__PURE__ */ join(STATIC_DIR, "icon.png");
|
||||
|
||||
8
src/shared/settings.d.ts
vendored
@@ -1,12 +1,13 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import type { Rectangle } from "electron";
|
||||
|
||||
export interface Settings {
|
||||
transparencyOption?: "none" | "mica" | "tabbed" | "acrylic";
|
||||
maximized?: boolean;
|
||||
minimized?: boolean;
|
||||
windowBounds?: Rectangle;
|
||||
@@ -17,4 +18,9 @@ export interface Settings {
|
||||
tray?: boolean;
|
||||
minimizeToTray?: boolean;
|
||||
skippedUpdate?: string;
|
||||
staticTitle?: boolean;
|
||||
arRPC?: boolean;
|
||||
appBadge?: boolean;
|
||||
|
||||
firstLaunch?: boolean;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
|
||||
13
src/shared/utils/guards.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
export function isTruthy<T>(item: T): item is Exclude<T, 0 | "" | false | null | undefined> {
|
||||
return Boolean(item);
|
||||
}
|
||||
|
||||
export function isNonNullish<T>(item: T): item is Exclude<T, null | undefined> {
|
||||
return item != null;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
type Func = (...args: any[]) => any;
|
||||
|
||||
export function monkeyPatch<O extends object>(
|
||||
object: O,
|
||||
key: keyof O,
|
||||
replacement: (original: Func, ...args: any[]) => any
|
||||
): void {
|
||||
const original = object[key] as Func;
|
||||
|
||||
const replacer = (object[key] = function (this: unknown, ...args: any[]) {
|
||||
return replacement.call(this, original, ...args);
|
||||
} as any);
|
||||
|
||||
Object.defineProperties(replacer, Object.getOwnPropertyDescriptors(original));
|
||||
replacer.toString = () => original.toString();
|
||||
replacer.$$original = original;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { app, BrowserWindow, ipcMain, shell } from "electron";
|
||||
import { Settings } from "main/settings";
|
||||
import { makeLinksOpenExternally } from "main/utils/makeLinksOpenExternally";
|
||||
import { githubGet, ReleaseData } from "main/utils/vencordLoader";
|
||||
import { join } from "path";
|
||||
import { SplashProps } from "shared/browserWinProperties";
|
||||
import { IpcEvents } from "shared/IpcEvents";
|
||||
import { STATIC_DIR } from "shared/paths";
|
||||
import { VIEW_DIR } from "shared/paths";
|
||||
|
||||
export interface UpdateData {
|
||||
currentVersion: string;
|
||||
@@ -22,11 +22,18 @@ let updateData: UpdateData;
|
||||
|
||||
ipcMain.handle(IpcEvents.UPDATER_GET_DATA, () => updateData);
|
||||
ipcMain.handle(IpcEvents.UPDATER_DOWNLOAD, () => {
|
||||
const portable = !!process.env.PORTABLE_EXECUTABLE_FILE;
|
||||
|
||||
const { assets } = updateData.release;
|
||||
const url = (() => {
|
||||
switch (process.platform) {
|
||||
case "win32":
|
||||
return assets.find(a => a.name.endsWith(".exe"))!.browser_download_url;
|
||||
return assets.find(a => {
|
||||
if (!a.name.endsWith(".exe")) return false;
|
||||
|
||||
const isSetup = a.name.includes("Setup");
|
||||
return portable ? !isSetup : isSetup;
|
||||
})!.browser_download_url;
|
||||
case "darwin":
|
||||
return assets.find(a => a.name.endsWith(".dmg"))!.browser_download_url;
|
||||
case "linux":
|
||||
@@ -67,18 +74,18 @@ function isOutdated(oldVersion: string, newVersion: string) {
|
||||
export async function checkUpdates() {
|
||||
// if (IS_DEV) return;
|
||||
try {
|
||||
const raw = await githubGet("/repos/Vencord/Desktop/releases/latest");
|
||||
const raw = await githubGet("/repos/Vencord/Vesktop/releases/latest");
|
||||
const data = JSON.parse(raw.toString("utf-8")) as ReleaseData;
|
||||
|
||||
const oldVersion = app.getVersion();
|
||||
const newVersion = data.tag_name.replace(/^v/, "");
|
||||
if (Settings.store.skippedUpdate !== newVersion && isOutdated(oldVersion, newVersion)) {
|
||||
updateData = {
|
||||
currentVersion: oldVersion,
|
||||
latestVersion: newVersion,
|
||||
release: data
|
||||
};
|
||||
updateData = {
|
||||
currentVersion: oldVersion,
|
||||
latestVersion: newVersion,
|
||||
release: data
|
||||
};
|
||||
|
||||
if (Settings.store.skippedUpdate !== newVersion && isOutdated(oldVersion, newVersion)) {
|
||||
openNewUpdateWindow();
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -88,11 +95,18 @@ export async function checkUpdates() {
|
||||
|
||||
function openNewUpdateWindow() {
|
||||
const win = new BrowserWindow({
|
||||
...SplashProps,
|
||||
width: 500,
|
||||
autoHideMenuBar: true,
|
||||
alwaysOnTop: true,
|
||||
webPreferences: {
|
||||
preload: join(__dirname, "updaterPreload.js")
|
||||
preload: join(__dirname, "updaterPreload.js"),
|
||||
nodeIntegration: false,
|
||||
contextIsolation: true,
|
||||
sandbox: true
|
||||
}
|
||||
});
|
||||
|
||||
win.loadFile(join(STATIC_DIR, "updater.html"));
|
||||
makeLinksOpenExternally(win);
|
||||
|
||||
win.loadFile(join(VIEW_DIR, "updater.html"));
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: GPL-3.0
|
||||
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2023 Vendicated and Vencord contributors
|
||||
*/
|
||||
|
||||
import { contextBridge } from "electron";
|
||||
import { invoke } from "preload/typedIpcs";
|
||||
import { invoke } from "preload/typedIpc";
|
||||
import { IpcEvents } from "shared/IpcEvents";
|
||||
|
||||
import type { UpdateData } from "./main";
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
padding: 2em;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell,
|
||||
"Open Sans", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>About Vencord Desktop</h1>
|
||||
<p>
|
||||
Vencord Desktop is a free/libre cross platform desktop app aiming to give you a snappier Discord experience with
|
||||
Vencord pre-installed
|
||||
</p>
|
||||
|
||||
<h2>Links</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://vencord.dev">Vencord Website</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/Vencord/Desktop" target="_blank">Source Code</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/Vencord/Desktop/issues" target="_blank">Report bugs / Request features</a>
|
||||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
BIN
static/badges/1.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
static/badges/10.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
static/badges/11.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
static/badges/2.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
static/badges/3.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
static/badges/4.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
static/badges/5.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
static/badges/6.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
static/badges/7.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
static/badges/8.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
static/badges/9.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
71
static/views/about.html
Normal file
@@ -0,0 +1,71 @@
|
||||
<head>
|
||||
<link rel="stylesheet" href="./style.css" type="text/css" />
|
||||
|
||||
<style>
|
||||
body {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1 id="title">Vesktop</h1>
|
||||
<p>
|
||||
Vesktop is a free/libre cross platform desktop app aiming to give you a snappier Discord experience with Vencord
|
||||
pre-installed
|
||||
</p>
|
||||
|
||||
<section>
|
||||
<h2>Links</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://vencord.dev" target="_blank">Vencord Website</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/Vencord/Vesktop" target="_blank">Source Code</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/Vencord/Vesktop/issues" target="_blank">Report bugs / Request features</a>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Acknowledgements</h2>
|
||||
<p>These awesome libraries empower Vesktop</p>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://github.com/electron/electron" target="_blank">Electron</a>
|
||||
- Build cross-platform desktop apps with JavaScript, HTML, and CSS
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/electron-userland/electron-builder" target="_blank">Electron Builder</a>
|
||||
- A complete solution to package and build a ready for distribution Electron app with “auto update”
|
||||
support out of the box
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/OpenAsar/arrpc" target="_blank">arrpc</a>
|
||||
- An open implementation of Discord's Rich Presence server
|
||||
</li>
|
||||
<li>
|
||||
And many
|
||||
<a href="https://github.com/Vencord/Vesktop/blob/main/pnpm-lock.yaml" target="_blank"
|
||||
>more awesome open source libraries</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</body>
|
||||
|
||||
<script type="module">
|
||||
const data = await Updater.getData();
|
||||
if (data.currentVersion) {
|
||||
const title = document.getElementById("title");
|
||||
|
||||
title.textContent += ` v${data.currentVersion}`;
|
||||
}
|
||||
</script>
|
||||
170
static/views/first-launch.html
Normal file
@@ -0,0 +1,170 @@
|
||||
<head>
|
||||
<link rel="stylesheet" href="./style.css" type="text/css" />
|
||||
|
||||
<style>
|
||||
body {
|
||||
height: 100vh;
|
||||
|
||||
padding: 1.5em;
|
||||
padding-bottom: 1em;
|
||||
|
||||
border: 1px solid var(--fg-semi-trans);
|
||||
border-top: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
select {
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
padding: 0.3em;
|
||||
margin: -0.3em;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0.4em 0 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 1em 0 2em;
|
||||
}
|
||||
|
||||
form {
|
||||
display: grid;
|
||||
gap: 1em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
label {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
label:has(input[type="checkbox"]),
|
||||
select {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
label:not(:last-child)::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: -10px;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
background-color: var(--fg-secondary);
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
label div {
|
||||
display: grid;
|
||||
gap: 0.2em;
|
||||
}
|
||||
|
||||
label h2 {
|
||||
margin: 0;
|
||||
font-weight: normal;
|
||||
font-size: 1.1rem;
|
||||
line-height: 1rem;
|
||||
}
|
||||
|
||||
label span {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 400;
|
||||
color: var(--fg-secondary);
|
||||
}
|
||||
|
||||
#buttons {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
gap: 0.5em;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 0.6em;
|
||||
background: red;
|
||||
color: white;
|
||||
border-radius: 6px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: 200ms filter;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
filter: brightness(0.8);
|
||||
}
|
||||
|
||||
#submit {
|
||||
background: green;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Welcome to Vesktop</h1>
|
||||
<p>Let's customise your experience!</p>
|
||||
|
||||
<form>
|
||||
<label>
|
||||
<h2>Discord Branch</h2>
|
||||
<select name="discordBranch">
|
||||
<option value="stable">stable</option>
|
||||
<option value="canary">canary</option>
|
||||
<option value="ptb">ptb</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<div>
|
||||
<h2>Start with System</h2>
|
||||
<span>Automatically open Vesktop when your computer starts</span>
|
||||
</div>
|
||||
<input type="checkbox" name="autoStart" />
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<div>
|
||||
<h2>Rich Presence</h2>
|
||||
<span
|
||||
>Enable Rich presence (game activity) via
|
||||
<a href="https://github.com/OpenAsar/arrpc" target="_blank">arRPC</a></span
|
||||
>
|
||||
</div>
|
||||
<input type="checkbox" name="richPresence" checked />
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<div>
|
||||
<h2>Import Settings</h2>
|
||||
<span>Import Settings from existing Vencord install (if found)</span>
|
||||
</div>
|
||||
<input type="checkbox" name="importSettings" checked />
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<div>
|
||||
<h2>Minimise to Tray</h2>
|
||||
<span>Minimise to Tray when closing</span>
|
||||
</div>
|
||||
<input type="checkbox" name="minimizeToTray" checked />
|
||||
</label>
|
||||
</form>
|
||||
<div id="buttons">
|
||||
<button id="cancel">Quit</button>
|
||||
<button id="submit">Submit</button>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script>
|
||||
cancel.onclick = () => console.info("cancel");
|
||||
submit.onclick = e => {
|
||||
const form = document.querySelector("form");
|
||||
const formData = new FormData(form);
|
||||
const data = Object.fromEntries(formData.entries());
|
||||
console.info("form:" + JSON.stringify(data));
|
||||
e.preventDefault();
|
||||
};
|
||||
</script>
|
||||
@@ -1,16 +1,11 @@
|
||||
<head>
|
||||
<link rel="stylesheet" href="./style.css" type="text/css" />
|
||||
|
||||
<style>
|
||||
* {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell,
|
||||
"Open Sans", "Helvetica Neue", sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
@@ -18,13 +13,11 @@
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: hsl(223 6.7% 20.6%);
|
||||
border-radius: 8px;
|
||||
border: 1px solid hsl(220 6.5% 18%);
|
||||
border: 1px solid var(--fg-semi-trans);
|
||||
}
|
||||
|
||||
p {
|
||||
color: rgb(219, 222, 225);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -43,6 +36,6 @@
|
||||
alt="shiggy"
|
||||
role="presentation"
|
||||
/>
|
||||
<p>Loading Vencord Desktop...</p>
|
||||
<p>Loading Vesktop...</p>
|
||||
</div>
|
||||
</body>
|
||||
30
static/views/style.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--bg: white;
|
||||
--fg: black;
|
||||
--fg-secondary: #313338;
|
||||
--fg-semi-trans: rgb(0 0 0 / 0.2);
|
||||
--link: #006ce7;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--bg: hsl(223 6.7% 20.6%);
|
||||
--fg: white;
|
||||
--fg-secondary: #b5bac1;
|
||||
--fg-semi-trans: rgb(255 255 255 / 0.2);
|
||||
--link: #00a8fc;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell,
|
||||
"Open Sans", "Helvetica Neue", sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: var(--bg);
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--link);
|
||||
}
|
||||
@@ -1,22 +1,13 @@
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell,
|
||||
"Open Sans", "Helvetica Neue", sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: rgb(219, 222, 225);
|
||||
}
|
||||
<link rel="stylesheet" href="./style.css" type="text/css" />
|
||||
|
||||
<style>
|
||||
.wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
background-color: #313338;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #248046;
|
||||
min-height: 100%;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
@@ -34,7 +25,7 @@
|
||||
button {
|
||||
cursor: pointer;
|
||||
padding: 0.5em;
|
||||
color: white;
|
||||
color: var(--fg);
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
font-weight: bold;
|
||||
@@ -60,12 +51,15 @@
|
||||
<div class="wrapper">
|
||||
<section>
|
||||
<h1>Update Available</h1>
|
||||
<p>There's a new update for Vencord Desktop! Update now to get new fixes and features!</p>
|
||||
<p>There's a new update for Vesktop! Update now to get new fixes and features!</p>
|
||||
<p>
|
||||
Current: <span id="current"></span>
|
||||
<br />
|
||||
Latest: <span id="latest"></span>
|
||||
</p>
|
||||
|
||||
<h2>Changelog</h2>
|
||||
<p id="changelog">Loading...</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -113,3 +107,17 @@
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script type="module">
|
||||
import { micromark } from "https://esm.sh/micromark@3?bundle";
|
||||
import { gfm, gfmHtml } from "https://esm.sh/micromark-extension-gfm@2?bundle";
|
||||
|
||||
const changelog = (await Updater.getData()).release.body;
|
||||
if (changelog)
|
||||
document.getElementById("changelog").innerHTML = micromark(changelog, {
|
||||
extensions: [gfm()],
|
||||
htmlExtensions: [gfmHtml()]
|
||||
})
|
||||
.replace(/h1>/g, "h3>")
|
||||
.replace(/<a /g, '<a target="_blank" ');
|
||||
</script>
|
||||
@@ -10,7 +10,12 @@
|
||||
"target": "ESNEXT",
|
||||
"jsx": "preserve",
|
||||
|
||||
"baseUrl": "./src/"
|
||||
// we have duplicate electron types but it's w/e
|
||||
"skipLibCheck": true,
|
||||
|
||||
"baseUrl": "./src/",
|
||||
|
||||
"typeRoots": ["./node_modules/@types", "./node_modules/@vencord"]
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
|
||||