diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index a9aec1f..6692098 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -13,10 +13,11 @@ body:
Make sure both Vesktop and Vencord are fully up to date. You can update Vencord by right-clicking the Vesktop tray icon and pressing "Update Vencord"
- Do not report any of the following issues:
+ **DO NOT REPORT** any of the following issues:
- Purely graphical glitches like flickering, scaling issues, etc: Issue with your gpu. Nothing we can do, update drivers or disable hardware acceleration
- Vencord related issues: This is the Vesktop repo, not Vencord
- - Screenshare not starting / black screening on Linux: Issue with your desktop environment, specifically its xdg-desktop-portal
+ - **SCREENSHARE NOT STARTING** / black screening on Linux: Issue with your desktop environment, specifically its xdg-desktop-portal.
+ If you're on flatpak, try using native version. If that also doesn't work, you have to fix your systen. Inspect errors and google around.
Linux users: Please only report issues with supported packages (flatpak and any builds from the README / releases).
We do not support other packages, like the AUR or Nix packages, so please first make sure your issue is reproducible with official releases,
diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml
index ab2db83..49480ff 100644
--- a/.github/ISSUE_TEMPLATE/feature-request.yml
+++ b/.github/ISSUE_TEMPLATE/feature-request.yml
@@ -1,7 +1,7 @@
name: 🛠️ Feature Request
-description: Create a feature request for Vesktop
-labels: [bug]
-title: "[Bug]
"
+description: Request a feature for Vesktop
+labels: [enhancement]
+title: "[Feature Request] "
body:
- type: markdown
diff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml
index 5287c23..2ebc5a3 100644
--- a/.github/workflows/meta.yml
+++ b/.github/workflows/meta.yml
@@ -11,28 +11,28 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
- - uses: pnpm/action-setup@v2 # Install pnpm using packageManager key in package.json
+ - uses: actions/checkout@v4
+ - uses: pnpm/action-setup@v4 # Install pnpm using packageManager key in package.json
- - name: Use Node.js 18.18.2
- uses: actions/setup-node@v3
- with:
- node-version: 18.18.2
+ - name: Use Node.js 20
+ uses: actions/setup-node@v4
+ with:
+ node-version: 20
- - name: Install dependencies
- run: pnpm i
+ - name: Install dependencies
+ run: pnpm i
- - name: Update metainfo
- run: pnpm updateMeta
+ - name: Update metainfo
+ run: pnpm updateMeta
- - name: Commit and merge in changes
- run: |
- git config user.name "github-actions[bot]"
- git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- git checkout -b ci/meta-update
- git add meta/dev.vencord.Vesktop.metainfo.xml
- git commit -m "Insert release changes for ${{ github.event.release.tag_name }}"
- git push origin ci/meta-update
- gh pr create -B main -H ci/meta-update -t "Metainfo for ${{ github.event.release.tag_name }}" -b "This PR updates the metainfo for release ${{ github.event.release.tag_name }}. @lewisakura @Vendicated"
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
\ No newline at end of file
+ - name: Commit and merge in changes
+ run: |
+ git config user.name "github-actions[bot]"
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
+ git checkout -b ci/meta-update
+ git add meta/dev.vencord.Vesktop.metainfo.xml
+ git commit -m "Insert release changes for ${{ github.event.release.tag_name }}"
+ git push origin ci/meta-update
+ gh pr create -B main -H ci/meta-update -t "Metainfo for ${{ github.event.release.tag_name }}" -b "This PR updates the metainfo for release ${{ github.event.release.tag_name }}. @lewisakura @Vendicated"
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 6968b73..9de1bc5 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -22,13 +22,13 @@ jobs:
platform: windows
steps:
- - uses: actions/checkout@v3
- - uses: pnpm/action-setup@v2 # Install pnpm using packageManager key in package.json
+ - uses: actions/checkout@v4
+ - uses: pnpm/action-setup@v4 # Install pnpm using packageManager key in package.json
- - name: Use Node.js 18.18.2
- uses: actions/setup-node@v3
+ - name: Use Node.js 20
+ uses: actions/setup-node@v4
with:
- node-version: 18.18.2
+ node-version: 20
cache: "pnpm"
- name: Install dependencies
@@ -43,7 +43,7 @@ jobs:
pnpm electron-builder --${{ matrix.platform }} --publish always
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
+
- name: Run Electron Builder
if: ${{ matrix.platform == 'mac' }}
run: |
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 6d88280..daa62a5 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -11,13 +11,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
- - uses: pnpm/action-setup@v2 # Install pnpm using packageManager key in package.json
+ - uses: actions/checkout@v4
+ - uses: pnpm/action-setup@v4 # Install pnpm using packageManager key in package.json
- - name: Use Node.js 18.18.2
- uses: actions/setup-node@v3
+ - name: Use Node.js 20
+ uses: actions/setup-node@v4
with:
- node-version: 18.18.2
+ node-version: 20
cache: "pnpm"
- name: Install dependencies
diff --git a/.github/workflows/winget-submission.yml b/.github/workflows/winget-submission.yml
index 7066d3b..080e484 100644
--- a/.github/workflows/winget-submission.yml
+++ b/.github/workflows/winget-submission.yml
@@ -13,10 +13,10 @@ on:
jobs:
winget:
name: Publish winget package
- runs-on: ubuntu-latest
+ runs-on: windows-latest
steps:
- name: Submit package to Winget Community Repo
- uses: vedantmgoyal2009/winget-releaser@e68d386d5d6a1cef8cb0fb5e62b77ebcb83e7d58 # v2
+ uses: vedantmgoyal2009/winget-releaser@4614300d5812e5df91cb02ef0edbece623d5dea8
with:
identifier: Vencord.Vesktop
token: ${{ secrets.WINGET_PAT }}
diff --git a/README.md b/README.md
index 8ea22d2..af62292 100644
--- a/README.md
+++ b/README.md
@@ -21,15 +21,14 @@ Vesktop is a custom Discord desktop app
If you don't know the difference, pick the Installer.
-- [Installer](https://vencord.dev/download/vesktop/amd64/windows)
-- [Portable](https://vencord.dev/download/vesktop/amd64/windows-portable)
+- [Installer](https://vencord.dev/download/vesktop/universal/windows)
+- Portable:
+ - [x64 / amd64](https://vencord.dev/download/vesktop/amd64/windows-portable)
+ - [arm64](https://vencord.dev/download/vesktop/arm64/windows-portable)
### Mac
-If you don't know the difference, pick the Intel build.
-
-- [Intel build (amd64)](https://vencord.dev/download/vesktop/amd64/dmg)
-- [Apple Silicon (arm64)](https://vencord.dev/download/vesktop/arm64/dmg)
+[Vesktop.dmg](https://vencord.dev/download/vesktop/universal/dmg)
### Linux
diff --git a/meta/dev.vencord.Vesktop.metainfo.xml b/meta/dev.vencord.Vesktop.metainfo.xml
index 889b9fc..853d520 100644
--- a/meta/dev.vencord.Vesktop.metainfo.xml
+++ b/meta/dev.vencord.Vesktop.metainfo.xml
@@ -28,6 +28,34 @@
+
+ https://github.com/Vencord/Vesktop/releases/tag/v1.5.3
+
+ Features
+
+ added arm64 Windows support
+ windows & macOS builds are now universal
+ added option to configure spellcheck languages
+ will auto-update from now on
+ updated electron to 31 & Chromium to 126
+ macOS: Added customized dmg background by @khcrysalis
+ Windows Portable: store settings in portable folder by @MrGarlic1
+ linux audioshare: added granular selection, more options, better ui by @Curve
+ changed default screen-sharing quality to 720p 30 FPS by @Tiagoquix
+
+ Fixes
+
+ macOS: Added workaround for making things in draggable area clickable by @HAHALOSAH
+ fixed Screenshare UI for non-linux systems by @PolisanTheEasyNick
+ fixed opening on screen that was disconnected by @MrGarlic1
+ mac: hide native window controls with custom titlebar enabled by @MrGarlic1
+ fixed some broken patches by @D3SOX
+ fixed framerate in constraints by @kittykel
+ fixed some first launch switches not applying
+ fixed potential sandbox escape via custom vencord location
+
+
+
https://github.com/Vencord/Vesktop/releases/tag/v1.5.2
@@ -182,7 +210,7 @@
https://github.com/Vencord/Vesktop
InstantMessaging
- AudioVideo
+ Network
pointing
diff --git a/package.json b/package.json
index 5bbec49..3e4f73e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "vesktop",
- "version": "1.5.2",
+ "version": "1.5.3",
"private": true,
"description": "",
"keywords": [],
@@ -24,10 +24,11 @@
"updateMeta": "tsx scripts/utils/updateMeta.mts"
},
"dependencies": {
- "arrpc": "github:OpenAsar/arrpc#6960a8fd4d65d566da93dbdb8a7ca474aa0a3c9c"
+ "arrpc": "github:OpenAsar/arrpc#c62ec6a04c8d870530aa6944257fe745f6c59a24",
+ "electron-updater": "^6.2.1"
},
"optionalDependencies": {
- "@vencord/venmic": "^3.5.0"
+ "@vencord/venmic": "^6.1.0"
},
"devDependencies": {
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
@@ -37,7 +38,7 @@
"@typescript-eslint/parser": "^7.2.0",
"@vencord/types": "^1.8.4",
"dotenv": "^16.4.5",
- "electron": "^29.1.1",
+ "electron": "^31.1.0",
"electron-builder": "^24.13.3",
"esbuild": "^0.20.1",
"eslint": "^8.57.0",
@@ -65,6 +66,7 @@
"productName": "Vesktop",
"files": [
"!*",
+ "!node_modules",
"dist/js",
"static",
"package.json",
@@ -118,8 +120,7 @@
{
"target": "default",
"arch": [
- "x64",
- "arm64"
+ "universal"
]
}
],
@@ -158,12 +159,29 @@
},
"win": {
"target": [
- "nsis",
- "zip"
+ {
+ "target": "nsis",
+ "arch": [
+ "x64",
+ "arm64"
+ ]
+ },
+ {
+ "target": "zip",
+ "arch": [
+ "x64",
+ "arm64"
+ ]
+ }
]
},
"publish": {
"provider": "github"
}
+ },
+ "pnpm": {
+ "patchedDependencies": {
+ "arrpc@3.4.0": "patches/arrpc@3.4.0.patch"
+ }
}
}
diff --git a/patches/arrpc@3.4.0.patch b/patches/arrpc@3.4.0.patch
new file mode 100644
index 0000000..8dfd9f6
--- /dev/null
+++ b/patches/arrpc@3.4.0.patch
@@ -0,0 +1,14 @@
+diff --git a/src/process/index.js b/src/process/index.js
+index 97ea6514b54dd9c5df588c78f0397d31ab5f882a..c2bdbd6aaa5611bc6ff1d993beeb380b1f5ec575 100644
+--- a/src/process/index.js
++++ b/src/process/index.js
+@@ -5,8 +5,7 @@ import fs from 'node:fs';
+ import { dirname, join } from 'path';
+ import { fileURLToPath } from 'url';
+
+-const __dirname = dirname(fileURLToPath(import.meta.url));
+-const DetectableDB = JSON.parse(fs.readFileSync(join(__dirname, 'detectable.json'), 'utf8'));
++const DetectableDB = require('./detectable.json');
+
+ import * as Natives from './native/index.js';
+ const Native = Natives[process.platform];
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6221301..ea1758f 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -4,17 +4,25 @@ settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
+patchedDependencies:
+ arrpc@3.4.0:
+ hash: biyukfa6dww2wxujy4eyvkhrti
+ path: patches/arrpc@3.4.0.patch
+
importers:
.:
dependencies:
arrpc:
- specifier: github:OpenAsar/arrpc#6960a8fd4d65d566da93dbdb8a7ca474aa0a3c9c
- version: https://codeload.github.com/OpenAsar/arrpc/tar.gz/6960a8fd4d65d566da93dbdb8a7ca474aa0a3c9c
+ specifier: github:OpenAsar/arrpc#c62ec6a04c8d870530aa6944257fe745f6c59a24
+ version: https://codeload.github.com/OpenAsar/arrpc/tar.gz/c62ec6a04c8d870530aa6944257fe745f6c59a24(patch_hash=biyukfa6dww2wxujy4eyvkhrti)
+ electron-updater:
+ specifier: ^6.2.1
+ version: 6.2.1
optionalDependencies:
'@vencord/venmic':
- specifier: ^3.5.0
- version: 3.5.0
+ specifier: ^6.1.0
+ version: 6.1.0
devDependencies:
'@fal-works/esbuild-plugin-global-externals':
specifier: ^2.1.2
@@ -38,8 +46,8 @@ importers:
specifier: ^16.4.5
version: 16.4.5
electron:
- specifier: ^29.1.1
- version: 29.1.1
+ specifier: ^31.1.0
+ version: 31.1.0
electron-builder:
specifier: ^24.13.3
version: 24.13.3(electron-builder-squirrel-windows@24.13.3(dmg-builder@24.13.3))
@@ -424,6 +432,7 @@ packages:
'@humanwhocodes/config-array@0.11.14':
resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==}
engines: {node: '>=10.10.0'}
+ deprecated: Use @eslint/config-array instead
'@humanwhocodes/module-importer@1.0.1':
resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==}
@@ -431,6 +440,7 @@ packages:
'@humanwhocodes/object-schema@2.0.2':
resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==}
+ deprecated: Use @eslint/object-schema instead
'@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
@@ -603,8 +613,8 @@ packages:
'@vencord/types@1.8.4':
resolution: {integrity: sha512-ogLqIOHVO+5zxKUVxAfGIAUZoEfIomrlg6f0cZ/2yd5vBAn1fA9Gi/NASoKfHZuJt8ZcYw329bgn0ah/VufqMg==}
- '@vencord/venmic@3.5.0':
- resolution: {integrity: sha512-kPvrPcIeMkuqQriuiQAJ9rEBeqGR2nmFBuUtbZRGyiNRF9RDAfWSJYqhHVm6F7wbcqrSZio6FazZuBo0LvjJRw==}
+ '@vencord/venmic@6.1.0':
+ resolution: {integrity: sha512-YiCtzml/W8tYbGhu3jm5jfbbEnl2slKKARNK0jO+8qV979k9eFnfIRTxvhMN/SWq1h8ZNJdXVwvXpffQwq0RuA==}
engines: {node: '>=14.15'}
os: [linux]
@@ -727,9 +737,9 @@ packages:
resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==}
engines: {node: '>= 0.4'}
- arrpc@https://codeload.github.com/OpenAsar/arrpc/tar.gz/6960a8fd4d65d566da93dbdb8a7ca474aa0a3c9c:
- resolution: {tarball: https://codeload.github.com/OpenAsar/arrpc/tar.gz/6960a8fd4d65d566da93dbdb8a7ca474aa0a3c9c}
- version: 3.3.1
+ arrpc@https://codeload.github.com/OpenAsar/arrpc/tar.gz/c62ec6a04c8d870530aa6944257fe745f6c59a24:
+ resolution: {tarball: https://codeload.github.com/OpenAsar/arrpc/tar.gz/c62ec6a04c8d870530aa6944257fe745f6c59a24}
+ version: 3.4.0
hasBin: true
assert-plus@1.0.0:
@@ -1080,8 +1090,11 @@ packages:
electron-publish@24.13.1:
resolution: {integrity: sha512-2ZgdEqJ8e9D17Hwp5LEq5mLQPjqU3lv/IALvgp+4W8VeNhryfGhYEQC/PgDPMrnWUp+l60Ou5SJLsu+k4mhQ8A==}
- electron@29.1.1:
- resolution: {integrity: sha512-cXN15NgCi7MkzGo5/23ZQbii+0UfhmUiDjACunmzcUofYCjF42XhFbL7JZnwgI0qtBCCeJU8qZNZt9lU91gUFw==}
+ electron-updater@6.2.1:
+ resolution: {integrity: sha512-83eKIPW14qwZqUUM6wdsIRwVKZyjmHxQ4/8G+1C6iS5PdDt7b1umYQyj1/qPpH510GmHEQe4q0kCPe3qmb3a0Q==}
+
+ electron@31.1.0:
+ resolution: {integrity: sha512-TBOwqLxSxnx6+pH6GMri7R3JPH2AkuGJHfWZS0p1HsmN+Qr1T9b0IRJnnehSd/3NZAmAre4ft9Ljec7zjyKFJA==}
engines: {node: '>= 12.20.55'}
hasBin: true
@@ -1441,6 +1454,7 @@ packages:
glob@7.2.3:
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
+ deprecated: Glob versions prior to v9 are no longer supported
global-agent@3.0.0:
resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==}
@@ -1561,6 +1575,7 @@ packages:
inflight@1.0.6:
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
+ deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
inherits@2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
@@ -1789,9 +1804,15 @@ packages:
lodash.difference@4.5.0:
resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==}
+ lodash.escaperegexp@4.1.2:
+ resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==}
+
lodash.flatten@4.4.0:
resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==}
+ lodash.isequal@4.5.0:
+ resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==}
+
lodash.isplainobject@4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
@@ -2155,6 +2176,7 @@ packages:
rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
+ deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true
roarr@2.15.4:
@@ -2371,6 +2393,9 @@ packages:
text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
+ tiny-typed-emitter@2.1.0:
+ resolution: {integrity: sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==}
+
tmp-promise@3.0.3:
resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==}
@@ -3031,7 +3056,7 @@ snapshots:
standalone-electron-types: 1.0.0
type-fest: 3.13.1
- '@vencord/venmic@3.5.0':
+ '@vencord/venmic@6.1.0':
dependencies:
cmake-js: 7.3.0
node-addon-api: 8.0.0
@@ -3220,7 +3245,7 @@ snapshots:
is-array-buffer: 3.0.4
is-shared-array-buffer: 1.0.3
- arrpc@https://codeload.github.com/OpenAsar/arrpc/tar.gz/6960a8fd4d65d566da93dbdb8a7ca474aa0a3c9c:
+ arrpc@https://codeload.github.com/OpenAsar/arrpc/tar.gz/c62ec6a04c8d870530aa6944257fe745f6c59a24(patch_hash=biyukfa6dww2wxujy4eyvkhrti):
dependencies:
ws: 8.13.0
transitivePeerDependencies:
@@ -3651,7 +3676,20 @@ snapshots:
transitivePeerDependencies:
- supports-color
- electron@29.1.1:
+ electron-updater@6.2.1:
+ dependencies:
+ builder-util-runtime: 9.2.4
+ fs-extra: 10.1.0
+ js-yaml: 4.1.0
+ lazy-val: 1.0.5
+ lodash.escaperegexp: 4.1.2
+ lodash.isequal: 4.5.0
+ semver: 7.6.0
+ tiny-typed-emitter: 2.1.0
+ transitivePeerDependencies:
+ - supports-color
+
+ electron@31.1.0:
dependencies:
'@electron/get': 2.0.3
'@types/node': 20.11.26
@@ -4512,8 +4550,12 @@ snapshots:
lodash.difference@4.5.0: {}
+ lodash.escaperegexp@4.1.2: {}
+
lodash.flatten@4.4.0: {}
+ lodash.isequal@4.5.0: {}
+
lodash.isplainobject@4.0.6: {}
lodash.merge@4.6.2: {}
@@ -5125,6 +5167,8 @@ snapshots:
text-table@0.2.0: {}
+ tiny-typed-emitter@2.1.0: {}
+
tmp-promise@3.0.3:
dependencies:
tmp: 0.2.3
diff --git a/scripts/build/build.mts b/scripts/build/build.mts
index 27f45cc..243381b 100644
--- a/scripts/build/build.mts
+++ b/scripts/build/build.mts
@@ -63,12 +63,6 @@ await Promise.all([
outfile: "dist/js/preload.js",
footer: { js: "//# sourceURL=VCDPreload" }
}),
- createContext({
- ...NodeCommonOpts,
- entryPoints: ["src/updater/preload.ts"],
- outfile: "dist/js/updaterPreload.js",
- footer: { js: "//# sourceURL=VCDUpdaterPreload" }
- }),
createContext({
...CommonOpts,
globalName: "Vesktop",
diff --git a/src/main/constants.ts b/src/main/constants.ts
index 1a02d5e..40d91a5 100644
--- a/src/main/constants.ts
+++ b/src/main/constants.ts
@@ -5,11 +5,22 @@
*/
import { app } from "electron";
-import { existsSync, readdirSync, renameSync, rmdirSync } from "fs";
-import { join } from "path";
+import { existsSync, mkdirSync, readdirSync, renameSync, rmdirSync } from "fs";
+import { dirname, join } from "path";
+
+const vesktopDir = dirname(process.execPath);
+
+export const PORTABLE =
+ process.platform === "win32" &&
+ !process.execPath.toLowerCase().endsWith("electron.exe") &&
+ !existsSync(join(vesktopDir, "Uninstall Vesktop.exe"));
const LEGACY_DATA_DIR = join(app.getPath("appData"), "VencordDesktop", "VencordDesktop");
-export const DATA_DIR = process.env.VENCORD_USER_DATA_DIR || join(app.getPath("userData"));
+export const DATA_DIR =
+ process.env.VENCORD_USER_DATA_DIR || (PORTABLE ? join(vesktopDir, "Data") : join(app.getPath("userData")));
+
+mkdirSync(DATA_DIR, { recursive: true });
+
// TODO: remove eventually
if (existsSync(LEGACY_DATA_DIR)) {
try {
@@ -26,7 +37,8 @@ if (existsSync(LEGACY_DATA_DIR)) {
console.error("Migration failed", e);
}
}
-app.setPath("sessionData", join(DATA_DIR, "sessionData"));
+const SESSION_DATA_DIR = join(DATA_DIR, "sessionData");
+app.setPath("sessionData", SESSION_DATA_DIR);
export const VENCORD_SETTINGS_DIR = join(DATA_DIR, "settings");
export const VENCORD_QUICKCSS_FILE = join(VENCORD_SETTINGS_DIR, "quickCss.css");
@@ -36,7 +48,8 @@ export const VENCORD_THEMES_DIR = join(DATA_DIR, "themes");
// needs to be inline require because of circular dependency
// as otherwise "DATA_DIR" (which is used by ./settings) will be uninitialised
export const VENCORD_FILES_DIR =
- (require("./settings") as typeof import("./settings")).Settings.store.vencordDir || join(DATA_DIR, "vencordDist");
+ (require("./settings") as typeof import("./settings")).State.store.vencordDir ||
+ join(SESSION_DATA_DIR, "vencordFiles");
export const USER_AGENT = `Vesktop/${app.getVersion()} (https://github.com/Vencord/Vesktop)`;
@@ -49,10 +62,10 @@ export const DEFAULT_HEIGHT = 720;
export const DISCORD_HOSTNAMES = ["discord.com", "canary.discord.com", "ptb.discord.com"];
const BrowserUserAgents = {
- darwin: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
- linux: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",
+ darwin: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
+ linux: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
windows:
- "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36"
};
export const BrowserUserAgent = BrowserUserAgents[process.platform] || BrowserUserAgents.windows;
diff --git a/src/main/firstLaunch.ts b/src/main/firstLaunch.ts
index d1bbceb..dee4882 100644
--- a/src/main/firstLaunch.ts
+++ b/src/main/firstLaunch.ts
@@ -18,11 +18,11 @@ import { Settings, State } from "./settings";
import { makeLinksOpenExternally } from "./utils/makeLinksOpenExternally";
interface Data {
- minimizeToTray: boolean;
discordBranch: "stable" | "canary" | "ptb";
- autoStart: boolean;
- importSettings: boolean;
- richPresence: boolean;
+ minimizeToTray?: "on";
+ autoStart?: "on";
+ importSettings?: "on";
+ richPresence?: "on";
}
export function createFirstLaunchTour() {
@@ -44,10 +44,11 @@ export function createFirstLaunchTour() {
if (!msg.startsWith("form:")) return;
const data = JSON.parse(msg.slice(5)) as Data;
+ console.log(data);
State.store.firstLaunch = false;
- Settings.store.minimizeToTray = data.minimizeToTray;
Settings.store.discordBranch = data.discordBranch;
- Settings.store.arRPC = data.richPresence;
+ Settings.store.minimizeToTray = !!data.minimizeToTray;
+ Settings.store.arRPC = !!data.richPresence;
if (data.autoStart) autoStart.enable();
diff --git a/src/main/index.ts b/src/main/index.ts
index 87ef60c..2e0d6f7 100644
--- a/src/main/index.ts
+++ b/src/main/index.ts
@@ -7,7 +7,7 @@
import "./ipc";
import { app, BrowserWindow, nativeTheme } from "electron";
-import { checkUpdates } from "updater/main";
+import { autoUpdater } from "electron-updater";
import { DATA_DIR } from "./constants";
import { createFirstLaunchTour } from "./firstLaunch";
@@ -19,6 +19,8 @@ import { isDeckGameMode } from "./utils/steamOS";
if (IS_DEV) {
require("source-map-support").install();
+} else {
+ autoUpdater.checkForUpdatesAndNotify();
}
// Make the Vencord files use our DATA_DIR
@@ -42,7 +44,13 @@ function init() {
// disable renderer backgrounding to prevent the app from unloading when in the background
// https://github.com/electron/electron/issues/2822
+ // https://github.com/GoogleChrome/chrome-launcher/blob/5a27dd574d47a75fec0fb50f7b774ebf8a9791ba/docs/chrome-flags-for-tools.md#task-throttling
app.commandLine.appendSwitch("disable-renderer-backgrounding");
+ app.commandLine.appendSwitch("disable-background-timer-throttling");
+ app.commandLine.appendSwitch("disable-backgrounding-occluded-windows");
+ if (process.platform === "win32") {
+ disabledFeatures.push("CalculateNativeWinOcclusion");
+ }
// work around chrome 66 disabling autoplay by default
app.commandLine.appendSwitch("autoplay-policy", "no-user-gesture-required");
@@ -50,12 +58,7 @@ function init() {
// HardwareMediaKeyHandling,MediaSessionService: Prevent Discord from registering as a media service.
//
// WidgetLayering (Vencord Added): Fix DevTools context menus https://github.com/electron/electron/issues/38790
- disabledFeatures.push(
- "WinRetrieveSuggestionsOnlyOnDemand",
- "HardwareMediaKeyHandling",
- "MediaSessionService",
- "WidgetLayering"
- );
+ disabledFeatures.push("WinRetrieveSuggestionsOnlyOnDemand", "HardwareMediaKeyHandling", "MediaSessionService");
app.commandLine.appendSwitch("enable-features", [...new Set(enabledFeatures)].filter(Boolean).join(","));
app.commandLine.appendSwitch("disable-features", [...new Set(disabledFeatures)].filter(Boolean).join(","));
@@ -73,7 +76,6 @@ function init() {
});
app.whenReady().then(async () => {
- checkUpdates();
if (process.platform === "win32") app.setAppUserModelId("dev.vencord.vesktop");
registerScreenShareHandler();
diff --git a/src/main/ipc.ts b/src/main/ipc.ts
index 5d5f32f..09f039f 100644
--- a/src/main/ipc.ts
+++ b/src/main/ipc.ts
@@ -19,7 +19,7 @@ import { setBadgeCount } from "./appBadge";
import { autoStart } from "./autoStart";
import { VENCORD_FILES_DIR, VENCORD_QUICKCSS_FILE, VENCORD_THEMES_DIR } from "./constants";
import { mainWin } from "./mainWindow";
-import { Settings } from "./settings";
+import { Settings, State } from "./settings";
import { handle, handleSync } from "./utils/ipcWrappers";
import { PopoutWindows } from "./utils/popout";
import { isDeckGameMode, showGamePage } from "./utils/steamOS";
@@ -109,7 +109,14 @@ handle(IpcEvents.SPELLCHECK_ADD_TO_DICTIONARY, (e, word: string) => {
e.sender.session.addWordToSpellCheckerDictionary(word);
});
-handle(IpcEvents.SELECT_VENCORD_DIR, async () => {
+handleSync(IpcEvents.GET_VENCORD_DIR, e => (e.returnValue = State.store.vencordDir));
+
+handle(IpcEvents.SELECT_VENCORD_DIR, async (_e, value?: null) => {
+ if (value === null) {
+ delete State.store.vencordDir;
+ return "ok";
+ }
+
const res = await dialog.showOpenDialog(mainWin!, {
properties: ["openDirectory"]
});
@@ -118,7 +125,9 @@ handle(IpcEvents.SELECT_VENCORD_DIR, async () => {
const dir = res.filePaths[0];
if (!isValidVencordInstall(dir)) return "invalid";
- return dir;
+ State.store.vencordDir = dir;
+
+ return "ok";
});
handle(IpcEvents.SET_BADGE_COUNT, (_, count: number) => setBadgeCount(count));
diff --git a/src/main/mainWindow.ts b/src/main/mainWindow.ts
index 60f86c3..790b8a9 100644
--- a/src/main/mainWindow.ts
+++ b/src/main/mainWindow.ts
@@ -92,7 +92,7 @@ function initTray(win: BrowserWindow) {
click: createAboutWindow
},
{
- label: "Update Vencord",
+ label: "Repair Vencord",
async click() {
await downloadVencordFiles();
app.relaunch();
@@ -109,14 +109,14 @@ function initTray(win: BrowserWindow) {
type: "separator"
},
{
- label: "Relaunch",
+ label: "Restart",
click() {
app.relaunch();
app.quit();
}
},
{
- label: "Quit Vesktop",
+ label: "Quit",
click() {
isQuitting = true;
app.quit();
@@ -404,7 +404,9 @@ function createMainWindow() {
contextIsolation: true,
devTools: true,
preload: join(__dirname, "preload.js"),
- spellcheck: true
+ spellcheck: true,
+ // disable renderer backgrounding to prevent the app from unloading when in the background
+ backgroundThrottling: false
},
icon: ICON_PATH,
frame: !noFrame,
@@ -429,6 +431,7 @@ function createMainWindow() {
autoHideMenuBar: enableMenu
}));
win.setMenuBarVisibility(false);
+ if (process.platform === "darwin" && customTitleBar) win.setWindowButtonVisibility(false);
win.on("close", e => {
const useTray = !isDeckGameMode && Settings.store.minimizeToTray !== false && Settings.store.tray !== false;
diff --git a/src/main/mediaPermissions.ts b/src/main/mediaPermissions.ts
index 1f6cf46..f7765be 100644
--- a/src/main/mediaPermissions.ts
+++ b/src/main/mediaPermissions.ts
@@ -12,11 +12,13 @@ export function registerMediaPermissionsHandler() {
session.defaultSession.setPermissionRequestHandler(async (_webContents, permission, callback, details) => {
let granted = true;
- if (details.mediaTypes?.includes("audio")) {
- granted = await systemPreferences.askForMediaAccess("microphone");
- }
- if (details.mediaTypes?.includes("video")) {
- granted &&= await systemPreferences.askForMediaAccess("camera");
+ if ("mediaTypes" in details) {
+ if (details.mediaTypes?.includes("audio")) {
+ granted &&= await systemPreferences.askForMediaAccess("microphone");
+ }
+ if (details.mediaTypes?.includes("video")) {
+ granted &&= await systemPreferences.askForMediaAccess("camera");
+ }
}
callback(granted);
diff --git a/src/main/settings.ts b/src/main/settings.ts
index f2c1b80..b2aeea9 100644
--- a/src/main/settings.ts
+++ b/src/main/settings.ts
@@ -41,14 +41,7 @@ export const VencordSettings = loadSettings(VENCORD_SETTINGS_FILE, "Vencord
if (Object.hasOwn(Settings.plain, "firstLaunch") && !existsSync(STATE_FILE)) {
console.warn("legacy state in settings.json detected. migrating to state.json");
const state = {} as TState;
- for (const prop of [
- "firstLaunch",
- "maximized",
- "minimized",
- "skippedUpdate",
- "steamOSLayoutVersion",
- "windowBounds"
- ] as const) {
+ for (const prop of ["firstLaunch", "maximized", "minimized", "steamOSLayoutVersion", "windowBounds"] as const) {
state[prop] = Settings.plain[prop];
delete Settings.plain[prop];
}
diff --git a/src/main/utils/vencordLoader.ts b/src/main/utils/vencordLoader.ts
index 1bac37a..c0bac6a 100644
--- a/src/main/utils/vencordLoader.ts
+++ b/src/main/utils/vencordLoader.ts
@@ -4,7 +4,8 @@
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
-import { existsSync, mkdirSync } from "fs";
+import { mkdirSync } from "fs";
+import { access, constants as FsConstants } from "fs/promises";
import { join } from "path";
import { USER_AGENT, VENCORD_FILES_DIR } from "../constants";
@@ -56,12 +57,18 @@ export async function downloadVencordFiles() {
);
}
-export function isValidVencordInstall(dir: string) {
- return FILES_TO_DOWNLOAD.every(f => existsSync(join(dir, f)));
+const existsAsync = (path: string) =>
+ access(path, FsConstants.F_OK)
+ .then(() => true)
+ .catch(() => false);
+
+export async function isValidVencordInstall(dir: string) {
+ return Promise.all(FILES_TO_DOWNLOAD.map(f => existsAsync(join(dir, f)))).then(arr => !arr.includes(false));
}
export async function ensureVencordFiles() {
- if (isValidVencordInstall(VENCORD_FILES_DIR)) return;
+ if (await isValidVencordInstall(VENCORD_FILES_DIR)) return;
+
mkdirSync(VENCORD_FILES_DIR, { recursive: true });
await downloadVencordFiles();
diff --git a/src/main/venmic.ts b/src/main/venmic.ts
index 404c0d2..885fd2d 100644
--- a/src/main/venmic.ts
+++ b/src/main/venmic.ts
@@ -4,13 +4,13 @@
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
-import type { PatchBay as PatchBayType } from "@vencord/venmic";
+import type { LinkData, Node, PatchBay as PatchBayType } from "@vencord/venmic";
import { app, ipcMain } from "electron";
import { join } from "path";
import { IpcEvents } from "shared/IpcEvents";
import { STATIC_DIR } from "shared/paths";
-type LinkData = Parameters[0];
+import { Settings } from "./settings";
let PatchBay: typeof PatchBayType | undefined;
let patchBayInstance: PatchBayType | undefined;
@@ -69,47 +69,64 @@ function getRendererAudioServicePid() {
ipcMain.handle(IpcEvents.VIRT_MIC_LIST, () => {
const audioPid = getRendererAudioServicePid();
- const list = obtainVenmic()
- ?.list()
- .filter(s => s["application.process.id"] !== audioPid)
- .map(s => s["application.name"]);
+ const { granularSelect } = Settings.store.audio ?? {};
- const uniqueTargets = [...new Set(list)];
+ const targets = obtainVenmic()
+ ?.list(granularSelect ? ["application.process.id"] : undefined)
+ .filter(s => s["application.process.id"] !== audioPid);
- return list ? { ok: true, targets: uniqueTargets, hasPipewirePulse } : { ok: false, isGlibCxxOutdated };
+ return targets ? { ok: true, targets, hasPipewirePulse } : { ok: false, isGlibCxxOutdated };
});
-ipcMain.handle(IpcEvents.VIRT_MIC_START, (_, targets: string[], workaround?: boolean) => {
+ipcMain.handle(IpcEvents.VIRT_MIC_START, (_, include: Node[]) => {
const pid = getRendererAudioServicePid();
+ const { ignoreDevices, ignoreInputMedia, ignoreVirtual, workaround } = Settings.store.audio ?? {};
const data: LinkData = {
- include: targets.map(target => ({ key: "application.name", value: target })),
- exclude: [{ key: "application.process.id", value: pid }]
+ include,
+ exclude: [{ "application.process.id": pid }],
+ ignore_devices: ignoreDevices
};
+ if (ignoreInputMedia ?? true) {
+ data.exclude.push({ "media.class": "Stream/Input/Audio" });
+ }
+
+ if (ignoreVirtual) {
+ data.exclude.push({ "node.virtual": "true" });
+ }
+
if (workaround) {
- data.workaround = [
- { key: "application.process.id", value: pid },
- { key: "media.name", value: "RecordStream" }
- ];
+ data.workaround = [{ "application.process.id": pid, "media.name": "RecordStream" }];
}
return obtainVenmic()?.link(data);
});
-ipcMain.handle(IpcEvents.VIRT_MIC_START_SYSTEM, (_, workaround?: boolean, onlyDefaultSpeakers?: boolean) => {
+ipcMain.handle(IpcEvents.VIRT_MIC_START_SYSTEM, (_, exclude: Node[]) => {
const pid = getRendererAudioServicePid();
+ const { workaround, ignoreDevices, ignoreInputMedia, ignoreVirtual, onlySpeakers, onlyDefaultSpeakers } =
+ Settings.store.audio ?? {};
+
const data: LinkData = {
- exclude: [{ key: "application.process.id", value: pid }],
+ include: [],
+ exclude: [{ "application.process.id": pid }, ...exclude],
+ only_speakers: onlySpeakers,
+ ignore_devices: ignoreDevices,
only_default_speakers: onlyDefaultSpeakers
};
+ if (ignoreInputMedia ?? true) {
+ data.exclude.push({ "media.class": "Stream/Input/Audio" });
+ }
+
+ if (ignoreVirtual) {
+ data.exclude.push({ "node.virtual": "true" });
+ }
+
if (workaround) {
- data.workaround = [
- { key: "application.process.id", value: pid },
- { key: "media.name", value: "RecordStream" }
- ];
+ data.workaround = [{ "application.process.id": pid, "media.name": "RecordStream" }];
}
return obtainVenmic()?.link(data);
diff --git a/src/preload/VesktopNative.ts b/src/preload/VesktopNative.ts
index 6d039e4..572c310 100644
--- a/src/preload/VesktopNative.ts
+++ b/src/preload/VesktopNative.ts
@@ -4,9 +4,9 @@
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
+import { Node } from "@vencord/venmic";
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";
@@ -33,7 +33,8 @@ export const VesktopNative = {
},
fileManager: {
showItemInFolder: (path: string) => invoke(IpcEvents.SHOW_ITEM_IN_FOLDER, path),
- selectVencordDir: () => invoke>(IpcEvents.SELECT_VENCORD_DIR)
+ getVencordDir: () => sendSync(IpcEvents.GET_VENCORD_DIR),
+ selectVencordDir: (value?: null) => invoke<"cancelled" | "invalid" | "ok">(IpcEvents.SELECT_VENCORD_DIR, value)
},
settings: {
get: () => sendSync(IpcEvents.GET_SETTINGS),
@@ -64,11 +65,10 @@ export const VesktopNative = {
virtmic: {
list: () =>
invoke<
- { ok: false; isGlibCxxOutdated: boolean } | { ok: true; targets: string[]; hasPipewirePulse: boolean }
+ { ok: false; isGlibCxxOutdated: boolean } | { ok: true; targets: Node[]; hasPipewirePulse: boolean }
>(IpcEvents.VIRT_MIC_LIST),
- start: (targets: string[], workaround?: boolean) => invoke(IpcEvents.VIRT_MIC_START, targets, workaround),
- startSystem: (workaround?: boolean, onlyDefaultSpeakers?: boolean) =>
- invoke(IpcEvents.VIRT_MIC_START_SYSTEM, workaround, onlyDefaultSpeakers),
+ start: (include: Node[]) => invoke(IpcEvents.VIRT_MIC_START, include),
+ startSystem: (exclude: Node[]) => invoke(IpcEvents.VIRT_MIC_START_SYSTEM, exclude),
stop: () => invoke(IpcEvents.VIRT_MIC_STOP)
},
arrpc: {
diff --git a/src/renderer/components/ScreenSharePicker.tsx b/src/renderer/components/ScreenSharePicker.tsx
index ac9fc0b..c7403b9 100644
--- a/src/renderer/components/ScreenSharePicker.tsx
+++ b/src/renderer/components/ScreenSharePicker.tsx
@@ -6,7 +6,7 @@
import "./screenSharePicker.css";
-import { closeModal, Logger, Margins, Modals, ModalSize, openModal, useAwaiter } from "@vencord/types/utils";
+import { closeModal, Logger, Modals, ModalSize, openModal, useAwaiter } from "@vencord/types/utils";
import { findStoreLazy, onceReady } from "@vencord/types/webpack";
import {
Button,
@@ -19,8 +19,10 @@ import {
UserStore,
useState
} from "@vencord/types/webpack/common";
+import { Node } from "@vencord/venmic";
import type { Dispatch, SetStateAction } from "react";
import { addPatch } from "renderer/patches/shared";
+import { useSettings } from "renderer/settings";
import { isLinux, isWindows } from "renderer/utils";
const StreamResolutions = ["480", "720", "1080", "1440"] as const;
@@ -31,14 +33,23 @@ const MediaEngineStore = findStoreLazy("MediaEngineStore");
export type StreamResolution = (typeof StreamResolutions)[number];
export type StreamFps = (typeof StreamFps)[number];
+type SpecialSource = "None" | "Entire System";
+
+type AudioSource = SpecialSource | Node;
+type AudioSources = SpecialSource | Node[];
+
+interface AudioItem {
+ name: string;
+ value: AudioSource;
+}
+
interface StreamSettings {
resolution: StreamResolution;
fps: StreamFps;
audio: boolean;
- audioSource?: string;
contentHint?: string;
- workaround?: boolean;
- onlyDefaultSpeakers?: boolean;
+ includeSources?: AudioSources;
+ excludeSources?: AudioSources;
}
export interface StreamPick extends StreamSettings {
@@ -118,13 +129,17 @@ export function openScreenSharePicker(screens: Source[], skipPicker: boolean) {
modalProps={props}
submit={async v => {
didSubmit = true;
- if (v.audioSource && v.audioSource !== "None") {
- if (v.audioSource === "Entire System") {
- await VesktopNative.virtmic.startSystem(v.workaround);
+
+ if (v.includeSources && v.includeSources !== "None") {
+ if (v.includeSources === "Entire System") {
+ await VesktopNative.virtmic.startSystem(
+ !v.excludeSources || isSpecialSource(v.excludeSources) ? [] : v.excludeSources
+ );
} else {
- await VesktopNative.virtmic.start([v.audioSource], v.workaround);
+ await VesktopNative.virtmic.start(v.includeSources);
}
}
+
resolve(v);
}}
close={() => {
@@ -159,6 +174,113 @@ function ScreenPicker({ screens, chooseScreen }: { screens: Source[]; chooseScre
);
}
+function AudioSettingsModal({
+ modalProps,
+ close,
+ setAudioSources
+}: {
+ modalProps: any;
+ close: () => void;
+ setAudioSources: (s: AudioSources) => void;
+}) {
+ const Settings = useSettings();
+
+ return (
+
+
+ Venmic Settings
+
+
+
+ (Settings.audio = { ...Settings.audio, workaround: v })}
+ value={Settings.audio?.workaround ?? false}
+ note={
+ <>
+ Work around an issue that causes the microphone to be shared instead of the correct audio.
+ Only enable if you're experiencing this issue.
+ >
+ }
+ >
+ Microphone Workaround
+
+ (Settings.audio = { ...Settings.audio, onlySpeakers: v })}
+ value={Settings.audio?.onlySpeakers ?? true}
+ note={
+ <>
+ When sharing entire desktop audio, only share apps that play to a speaker. You may want to
+ disable this when using "mix bussing".
+ >
+ }
+ >
+ Only Speakers
+
+ (Settings.audio = { ...Settings.audio, onlyDefaultSpeakers: v })}
+ value={Settings.audio?.onlyDefaultSpeakers ?? true}
+ note={
+ <>
+ When sharing entire desktop audio, only share apps that play to the default speakers.
+ You may want to disable this when using "mix bussing".
+ >
+ }
+ >
+ Only Default Speakers
+
+ (Settings.audio = { ...Settings.audio, ignoreInputMedia: v })}
+ value={Settings.audio?.ignoreInputMedia ?? true}
+ note={<>Exclude nodes that are intended to capture audio.>}
+ >
+ Ignore Inputs
+
+ (Settings.audio = { ...Settings.audio, ignoreVirtual: v })}
+ value={Settings.audio?.ignoreVirtual ?? false}
+ note={
+ <>
+ Exclude virtual nodes, such as nodes belonging to loopbacks. This might be useful when using
+ "mix bussing".
+ >
+ }
+ >
+ Ignore Virtual
+
+ (Settings.audio = { ...Settings.audio, ignoreDevices: v })}
+ value={Settings.audio?.ignoreDevices ?? true}
+ note={<>Exclude device nodes, such as nodes belonging to microphones or speakers.>}
+ >
+ Ignore Devices
+
+ {
+ Settings.audio = { ...Settings.audio, granularSelect: value };
+ setAudioSources("None");
+ }}
+ value={Settings.audio?.granularSelect ?? false}
+ note={<>Allow to select applications more granularly.>}
+ >
+ Granular Selection
+
+
+
+
+ Back
+
+
+
+ );
+}
+
function StreamSettings({
source,
settings,
@@ -170,6 +292,8 @@ function StreamSettings({
setSettings: Dispatch>;
skipPicker: boolean;
}) {
+ const Settings = useSettings();
+
const [thumb] = useAwaiter(
() => (skipPicker ? Promise.resolve(source.url) : VesktopNative.capturer.getLargeThumbnail(source.id)),
{
@@ -178,230 +302,346 @@ function StreamSettings({
}
);
+ const openSettings = () => {
+ const key = openModal(props => (
+ props.onClose()}
+ setAudioSources={sources =>
+ setSettings(s => ({ ...s, includeSources: sources, excludeSources: sources }))
+ }
+ />
+ ));
+ };
+
return (
-
-
-
What you're streaming
-
-
- {source.name}
-
+
+
What you're streaming
+
+
+ {source.name}
+
-
Stream Settings
+
Stream Settings
-
-
+
+
+ Choosing "Prefer Clarity" will result in a significantly lower framerate in exchange
+ for a much sharper and clearer image.
+
+
+
+ {isWindows && (
+
setSettings(s => ({ ...s, audio: checked }))}
+ hideBorder
+ className="vcd-screen-picker-audio"
+ >
+ Stream With Audio
+
+ )}
+
+
-
{isLinux && (
setSettings(s => ({ ...s, audioSource: source }))}
- setWorkaround={value => setSettings(s => ({ ...s, workaround: value }))}
- setOnlyDefaultSpeakers={value => setSettings(s => ({ ...s, onlyDefaultSpeakers: value }))}
+ openSettings={openSettings}
+ includeSources={settings.includeSources}
+ excludeSources={settings.excludeSources}
+ granularSelect={Settings.audio?.granularSelect}
+ setIncludeSources={sources => setSettings(s => ({ ...s, includeSources: sources }))}
+ setExcludeSources={sources => setSettings(s => ({ ...s, excludeSources: sources }))}
/>
)}
-
+
);
}
+function isSpecialSource(value?: AudioSource | AudioSources): value is SpecialSource {
+ return typeof value === "string";
+}
+
+function hasMatchingProps(value: Node, other: Node) {
+ return Object.keys(value).every(key => value[key] === other[key]);
+}
+
+function mapToAudioItem(node: AudioSource, granularSelect?: boolean): AudioItem[] {
+ if (isSpecialSource(node)) {
+ return [{ name: node, value: node }];
+ }
+
+ const rtn: AudioItem[] = [];
+
+ const name = node["application.name"];
+
+ if (name) {
+ rtn.push({ name: name, value: { "application.name": name } });
+ }
+
+ if (!granularSelect) {
+ return rtn;
+ }
+
+ const binary = node["application.process.binary"];
+
+ if (!name) {
+ rtn.push({ name: binary, value: { "application.process.binary": binary } });
+ }
+
+ const pid = node["application.process.id"];
+
+ const first = rtn[0];
+ const firstValues = first.value as Node;
+
+ rtn.push({
+ name: `${first.name} (${pid})`,
+ value: { ...firstValues, "application.process.id": pid }
+ });
+
+ const mediaName = node["media.name"];
+
+ if (mediaName) {
+ rtn.push({
+ name: `${first.name} [${mediaName}]`,
+ value: { ...firstValues, "media.name": mediaName }
+ });
+ }
+
+ const mediaClass = node["media.class"];
+
+ if (!mediaClass) {
+ return rtn;
+ }
+
+ rtn.push({
+ name: `${first.name} [${mediaClass}]`,
+ value: { ...firstValues, "media.class": mediaClass }
+ });
+
+ return rtn;
+}
+
+function isItemSelected(sources?: AudioSources) {
+ return (value: AudioSource) => {
+ if (!sources) {
+ return false;
+ }
+
+ if (isSpecialSource(sources) || isSpecialSource(value)) {
+ return sources === value;
+ }
+
+ return sources.some(source => hasMatchingProps(source, value));
+ };
+}
+
+function updateItems(setSources: (s: AudioSources) => void, sources?: AudioSources) {
+ return (value: AudioSource) => {
+ if (isSpecialSource(value)) {
+ setSources(value);
+ return;
+ }
+
+ if (isSpecialSource(sources)) {
+ setSources([value]);
+ return;
+ }
+
+ if (isItemSelected(sources)(value)) {
+ setSources(sources?.filter(x => !hasMatchingProps(x, value)) ?? "None");
+ return;
+ }
+
+ setSources([...(sources || []), value]);
+ };
+}
+
function AudioSourcePickerLinux({
- audioSource,
- workaround,
- onlyDefaultSpeakers,
- setAudioSource,
- setWorkaround,
- setOnlyDefaultSpeakers
+ includeSources,
+ excludeSources,
+ granularSelect,
+ openSettings,
+ setIncludeSources,
+ setExcludeSources
}: {
- audioSource?: string;
- workaround?: boolean;
- onlyDefaultSpeakers?: boolean;
- setAudioSource(s: string): void;
- setWorkaround(b: boolean): void;
- setOnlyDefaultSpeakers(b: boolean): void;
+ includeSources?: AudioSources;
+ excludeSources?: AudioSources;
+ granularSelect?: boolean;
+ openSettings: () => void;
+ setIncludeSources: (s: AudioSources) => void;
+ setExcludeSources: (s: AudioSources) => void;
}) {
const [sources, _, loading] = useAwaiter(() => VesktopNative.virtmic.list(), {
fallbackValue: { ok: true, targets: [], hasPipewirePulse: true }
});
- const allSources = sources.ok ? ["None", "Entire System", ...sources.targets] : null;
const hasPipewirePulse = sources.ok ? sources.hasPipewirePulse : true;
-
const [ignorePulseWarning, setIgnorePulseWarning] = useState(false);
+ if (!sources.ok && sources.isGlibCxxOutdated) {
+ return (
+
+ Failed to retrieve Audio Sources because your C++ library is too old to run
+
+ venmic
+
+ . See{" "}
+
+ this guide
+ {" "}
+ for possible solutions.
+
+ );
+ }
+
+ if (!hasPipewirePulse && !ignorePulseWarning) {
+ return (
+
+ Could not find pipewire-pulse. See{" "}
+
+ this guide
+ {" "}
+ on how to switch to pipewire.
+ You can still continue, however, please{" "}
+ beware that you can only share audio of apps that are running under pipewire .{" "}
+ setIgnorePulseWarning(true)}>I know what I'm doing!
+
+ );
+ }
+
+ const specialSources: SpecialSource[] = ["None", "Entire System"] as const;
+
+ const uniqueName = (value: AudioItem, index: number, list: AudioItem[]) =>
+ list.findIndex(x => x.name === value.name) === index;
+
+ const allSources = sources.ok
+ ? [...specialSources, ...sources.targets]
+ .map(target => mapToAudioItem(target, granularSelect))
+ .flat()
+ .filter(uniqueName)
+ : [];
+
return (
<>
- Audio Settings
-
- {loading ? (
- Loading Audio Sources...
- ) : (
- Audio Source
- )}
-
- {!sources.ok && sources.isGlibCxxOutdated && (
-
- Failed to retrieve Audio Sources because your C++ library is too old to run
-
- venmic
-
- . See{" "}
-
- this guide
- {" "}
- for possible solutions.
-
- )}
-
- {hasPipewirePulse || ignorePulseWarning ? (
- allSources && (
+
+
+ {loading ? "Loading Sources..." : "Audio Sources"}
+ ({
+ label: name,
+ value: value,
+ default: name === "None"
+ }))}
+ isSelected={isItemSelected(includeSources)}
+ select={updateItems(setIncludeSources, includeSources)}
+ serialize={String}
+ popoutPosition="top"
+ closeOnSelect={false}
+ />
+
+ {includeSources === "Entire System" && (
+
+ Exclude Sources
({ label: s, value: s, default: s === "None" }))}
- isSelected={s => s === audioSource}
- select={setAudioSource}
+ options={allSources
+ .filter(x => x.name !== "Entire System")
+ .map(({ name, value }) => ({
+ label: name,
+ value: value,
+ default: name === "None"
+ }))}
+ isSelected={isItemSelected(excludeSources)}
+ select={updateItems(setExcludeSources, excludeSources)}
serialize={String}
+ popoutPosition="top"
+ closeOnSelect={false}
/>
- )
- ) : (
-
- Could not find pipewire-pulse. This usually means that you do not run pipewire as your main
- audio-server.
- You can still continue, however, please beware that you can only share audio of apps that are
- running under pipewire.
-
- setIgnorePulseWarning(true)}>I know what I'm doing
-
+
)}
-
-
-
-
- Work around an issue that causes the microphone to be shared instead of the correct audio.
- Only enable if you're experiencing this issue.
- >
- }
- >
- Microphone Workaround
-
-
-
- When sharing entire desktop audio, only share apps that play to the default speakers and
- ignore apps that play to other speakers or devices.
- >
- }
- >
- Only Default Speakers
-
-
+
+
+ Open Audio Settings
+
>
);
}
@@ -421,10 +661,11 @@ function ModalComponent({
}) {
const [selected, setSelected] = useState(skipPicker ? screens[0].id : void 0);
const [settings, setSettings] = useState({
- resolution: "1080",
- fps: "60",
+ resolution: "720",
+ fps: "30",
contentHint: "motion",
- audio: true
+ audio: true,
+ includeSources: "None"
});
return (
@@ -480,7 +721,7 @@ function ModalComponent({
const constraints = {
...track.getConstraints(),
- frameRate,
+ frameRate: { min: frameRate, ideal: frameRate },
width: { min: 640, ideal: width, max: width },
height: { min: 480, ideal: height, max: height },
advanced: [{ width: width, height: height }],
diff --git a/src/renderer/components/screenSharePicker.css b/src/renderer/components/screenSharePicker.css
index c2586a1..4f49323 100644
--- a/src/renderer/components/screenSharePicker.css
+++ b/src/renderer/components/screenSharePicker.css
@@ -11,17 +11,6 @@
gap: 1em;
}
-.vcd-screen-picker-settings-grid {
- gap: 1em;
- display: grid;
- grid-template-columns: 1fr 1fr;
-}
-
-.vcd-screen-picker-settings-grid>div {
- display: flex;
- flex-direction: column;
-}
-
.vcd-screen-picker-card {
flex-grow: 1;
}
@@ -38,7 +27,7 @@
}
.vcd-screen-picker-selected img {
- border: 2px solid var(--brand-experiment);
+ border: 2px solid var(--brand-500);
border-radius: 3px;
}
@@ -49,7 +38,7 @@
}
.vcd-screen-picker-grid label:hover {
- outline: 2px solid var(--brand-experiment);
+ outline: 2px solid var(--brand-500);
}
@@ -68,7 +57,7 @@
}
.vcd-screen-picker-preview-img-linux {
- width: 100%;
+ width: 60%;
margin-bottom: 0.5em;
}
@@ -101,8 +90,8 @@
}
.vcd-screen-picker-radio[data-checked="true"] {
- background-color: var(--brand-experiment);
- border-color: var(--brand-experiment);
+ background-color: var(--brand-500);
+ border-color: var(--brand-500);
}
.vcd-screen-picker-radio[data-checked="true"] h2 {
@@ -120,6 +109,11 @@
flex: 1 1 auto;
}
+.vcd-screen-picker-settings-button {
+ margin-left: auto;
+ margin-top: 0.3rem;
+}
+
.vcd-screen-picker-radios {
display: flex;
width: 100%;
@@ -148,4 +142,4 @@
font-size: 14px;
line-height: 20px;
font-weight: 400;
-}
\ No newline at end of file
+}
diff --git a/src/renderer/components/settings/Settings.tsx b/src/renderer/components/settings/Settings.tsx
index b39779c..cefa8f8 100644
--- a/src/renderer/components/settings/Settings.tsx
+++ b/src/renderer/components/settings/Settings.tsx
@@ -104,15 +104,7 @@ const SettingsOptions: Record>
defaultValue: false
}
],
- "Notifications & Updates": [
- NotificationBadgeToggle,
- {
- key: "checkUpdates",
- title: "Check for updates",
- description: "Automatically check for Vesktop updates",
- defaultValue: true
- }
- ],
+ Notifications: [NotificationBadgeToggle],
Miscelleanous: [
{
key: "arRPC",
diff --git a/src/renderer/components/settings/VencordLocationPicker.tsx b/src/renderer/components/settings/VencordLocationPicker.tsx
index 3759ae2..9af4711 100644
--- a/src/renderer/components/settings/VencordLocationPicker.tsx
+++ b/src/renderer/components/settings/VencordLocationPicker.tsx
@@ -4,24 +4,28 @@
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
+import { useForceUpdater } from "@vencord/types/utils";
import { Button, Forms, Toasts } from "@vencord/types/webpack/common";
import { SettingsComponent } from "./Settings";
export const VencordLocationPicker: SettingsComponent = ({ settings }) => {
+ const forceUpdate = useForceUpdater();
+ const vencordDir = VesktopNative.fileManager.getVencordDir();
+
return (
<>
Vencord files are loaded from{" "}
- {settings.vencordDir ? (
+ {vencordDir ? (
{
e.preventDefault();
- VesktopNative.fileManager.showItemInFolder(settings.vencordDir!);
+ VesktopNative.fileManager.showItemInFolder(vencordDir!);
}}
>
- {settings.vencordDir}
+ {vencordDir}
) : (
"the default location"
@@ -34,7 +38,14 @@ export const VencordLocationPicker: SettingsComponent = ({ settings }) => {
const choice = await VesktopNative.fileManager.selectVencordDir();
switch (choice) {
case "cancelled":
- return;
+ break;
+ case "ok":
+ Toasts.show({
+ message: "Vencord install changed. Fully restart Vesktop to apply.",
+ id: Toasts.genId(),
+ type: Toasts.Type.SUCCESS
+ });
+ break;
case "invalid":
Toasts.show({
message:
@@ -42,9 +53,9 @@ export const VencordLocationPicker: SettingsComponent = ({ settings }) => {
id: Toasts.genId(),
type: Toasts.Type.FAILURE
});
- return;
+ break;
}
- settings.vencordDir = choice;
+ forceUpdate();
}}
>
Change
@@ -52,7 +63,10 @@ export const VencordLocationPicker: SettingsComponent = ({ settings }) => {
(settings.vencordDir = void 0)}
+ onClick={async () => {
+ await VesktopNative.fileManager.selectVencordDir(null);
+ forceUpdate();
+ }}
>
Reset
diff --git a/src/renderer/fixes.css b/src/renderer/fixes.css
index aeec1bf..20e80aa 100644
--- a/src/renderer/fixes.css
+++ b/src/renderer/fixes.css
@@ -8,4 +8,9 @@
* {
scrollbar-width: unset !important;
scrollbar-color: unset !important;
-}
\ No newline at end of file
+}
+
+/* Workaround for making things in the draggable area clickable again on macOS */
+.platform-osx [class*=topic_], .platform-osx [class*=notice_] button {
+ -webkit-app-region: no-drag;
+}
diff --git a/src/renderer/index.ts b/src/renderer/index.ts
index 99dca25..e8ad31c 100644
--- a/src/renderer/index.ts
+++ b/src/renderer/index.ts
@@ -13,7 +13,7 @@ console.log("read if cute :3");
export * as Components from "./components";
import { findByPropsLazy, onceReady } from "@vencord/types/webpack";
-import { FluxDispatcher } from "@vencord/types/webpack/common";
+import { Alerts, FluxDispatcher } from "@vencord/types/webpack/common";
import SettingsUi from "./components/settings/Settings";
import { Settings } from "./settings";
@@ -59,3 +59,19 @@ VesktopNative.arrpc.onActivity(async data => {
arRPC.handleEvent(new MessageEvent("message", { data }));
});
+
+// TODO: remove soon
+const vencordDir = "vencordDir" as keyof typeof Settings.store;
+if (Settings.store[vencordDir]) {
+ onceReady.then(() =>
+ setTimeout(
+ () =>
+ Alerts.show({
+ title: "Custom Vencord Location",
+ body: "Due to security hardening changes in Vesktop, your custom Vencord location had to be reset. Please configure it again in the settings.",
+ onConfirm: () => delete Settings.store[vencordDir]
+ }),
+ 5000
+ )
+ );
+}
diff --git a/src/renderer/patches/enableNotificationsByDefault.ts b/src/renderer/patches/enableNotificationsByDefault.ts
index f48115d..5854977 100644
--- a/src/renderer/patches/enableNotificationsByDefault.ts
+++ b/src/renderer/patches/enableNotificationsByDefault.ts
@@ -13,7 +13,7 @@ addPatch({
replacement: {
// FIXME: fix eslint rule
// eslint-disable-next-line no-useless-escape
- match: /\.isPlatformEmbedded(?=\?\i\.DesktopNotificationTypes\.ALL)/g,
+ match: /\.isPlatformEmbedded(?=\?\i\.\i\.ALL)/g,
replace: "$&||true"
}
}
diff --git a/src/renderer/patches/hideSwitchDevice.tsx b/src/renderer/patches/hideSwitchDevice.tsx
index 911aed7..20aa51a 100644
--- a/src/renderer/patches/hideSwitchDevice.tsx
+++ b/src/renderer/patches/hideSwitchDevice.tsx
@@ -12,7 +12,7 @@ addPatch({
find: "lastOutputSystemDevice.justChanged",
replacement: {
// eslint-disable-next-line no-useless-escape
- match: /(\i)\.default\.getState\(\).neverShowModal/,
+ match: /(\i)\.\i\.getState\(\).neverShowModal/,
replace: "$& || $self.shouldIgnore($1)"
}
}
diff --git a/src/renderer/patches/screenShareFixes.ts b/src/renderer/patches/screenShareFixes.ts
index 66e4b14..00487d3 100644
--- a/src/renderer/patches/screenShareFixes.ts
+++ b/src/renderer/patches/screenShareFixes.ts
@@ -36,7 +36,7 @@ if (isLinux) {
const constraints = {
...track.getConstraints(),
- frameRate,
+ frameRate: { min: frameRate, ideal: frameRate },
width: { min: 640, ideal: width, max: width },
height: { min: 480, ideal: height, max: height },
advanced: [{ width: width, height: height }],
diff --git a/src/shared/IpcEvents.ts b/src/shared/IpcEvents.ts
index b7538fe..a9f19e9 100644
--- a/src/shared/IpcEvents.ts
+++ b/src/shared/IpcEvents.ts
@@ -24,6 +24,7 @@ export const enum IpcEvents {
GET_SETTINGS = "VCD_GET_SETTINGS",
SET_SETTINGS = "VCD_SET_SETTINGS",
+ GET_VENCORD_DIR = "VCD_GET_VENCORD_DIR",
SELECT_VENCORD_DIR = "VCD_SELECT_VENCORD_DIR",
UPDATER_GET_DATA = "VCD_UPDATER_GET_DATA",
diff --git a/src/shared/settings.d.ts b/src/shared/settings.d.ts
index 192d020..6470ea4 100644
--- a/src/shared/settings.d.ts
+++ b/src/shared/settings.d.ts
@@ -8,7 +8,6 @@ import type { Rectangle } from "electron";
export interface Settings {
discordBranch?: "stable" | "canary" | "ptb";
- vencordDir?: string;
transparencyOption?: "none" | "mica" | "tabbed" | "acrylic";
tray?: boolean;
minimizeToTray?: boolean;
@@ -24,13 +23,23 @@ export interface Settings {
clickTrayToShowHide?: boolean;
customTitleBar?: boolean;
- checkUpdates?: boolean;
-
splashTheming?: boolean;
splashColor?: string;
splashBackground?: string;
spellCheckLanguages?: string[];
+
+ audio?: {
+ workaround?: boolean;
+ granularSelect?: boolean;
+
+ ignoreVirtual?: boolean;
+ ignoreDevices?: boolean;
+ ignoreInputMedia?: boolean;
+
+ onlySpeakers?: boolean;
+ onlyDefaultSpeakers?: boolean;
+ };
}
export interface State {
@@ -39,8 +48,9 @@ export interface State {
windowBounds?: Rectangle;
displayid: int;
- skippedUpdate?: string;
firstLaunch?: boolean;
steamOSLayoutVersion?: number;
+
+ vencordDir?: string;
}
diff --git a/src/shared/utils/SettingsStore.ts b/src/shared/utils/SettingsStore.ts
index 22dd145..6aa7771 100644
--- a/src/shared/utils/SettingsStore.ts
+++ b/src/shared/utils/SettingsStore.ts
@@ -59,6 +59,19 @@ export class SettingsStore {
self.pathListeners.get(setPath)?.forEach(cb => cb(value));
return true;
+ },
+ deleteProperty(target, key: string) {
+ if (!(key in target)) return true;
+
+ const res = Reflect.deleteProperty(target, key);
+ if (!res) return false;
+
+ const setPath = `${path}${path && "."}${key}`;
+
+ self.globalListeners.forEach(cb => cb(root, setPath));
+ self.pathListeners.get(setPath)?.forEach(cb => cb(undefined));
+
+ return res;
}
});
}
diff --git a/src/updater/main.ts b/src/updater/main.ts
deleted file mode 100644
index 207687e..0000000
--- a/src/updater/main.ts
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * 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, BrowserWindow, shell } from "electron";
-import { Settings, State } from "main/settings";
-import { handle } from "main/utils/ipcWrappers";
-import { makeLinksOpenExternally } from "main/utils/makeLinksOpenExternally";
-import { githubGet, ReleaseData } from "main/utils/vencordLoader";
-import { join } from "path";
-import { IpcEvents } from "shared/IpcEvents";
-import { ICON_PATH, VIEW_DIR } from "shared/paths";
-
-export interface UpdateData {
- currentVersion: string;
- latestVersion: string;
- release: ReleaseData;
-}
-
-let updateData: UpdateData;
-
-handle(IpcEvents.UPDATER_GET_DATA, () => updateData);
-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 => {
- 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 =>
- process.arch === "arm64"
- ? a.name.endsWith("-arm64-mac.zip")
- : a.name.endsWith("-mac.zip") && !a.name.includes("arm64")
- )!.browser_download_url;
- case "linux":
- return updateData.release.html_url;
- default:
- throw new Error(`Unsupported platform: ${process.platform}`);
- }
- })();
-
- shell.openExternal(url);
-});
-
-handle(IpcEvents.UPDATE_IGNORE, () => {
- State.store.skippedUpdate = updateData.latestVersion;
-});
-
-function isOutdated(oldVersion: string, newVersion: string) {
- const oldParts = oldVersion.split(".");
- const newParts = newVersion.split(".");
-
- if (oldParts.length !== newParts.length)
- throw new Error(`Incompatible version strings (old: ${oldVersion}, new: ${newVersion})`);
-
- for (let i = 0; i < oldParts.length; i++) {
- const oldPart = Number(oldParts[i]);
- const newPart = Number(newParts[i]);
-
- if (isNaN(oldPart) || isNaN(newPart))
- throw new Error(`Invalid version string (old: ${oldVersion}, new: ${newVersion})`);
-
- if (oldPart < newPart) return true;
- if (oldPart > newPart) return false;
- }
-
- return false;
-}
-
-export async function checkUpdates() {
- if (Settings.store.checkUpdates === false) return;
-
- try {
- const raw = await githubGet("/repos/Vencord/Vesktop/releases/latest");
- const data: ReleaseData = await raw.json();
-
- const oldVersion = app.getVersion();
- const newVersion = data.tag_name.replace(/^v/, "");
- updateData = {
- currentVersion: oldVersion,
- latestVersion: newVersion,
- release: data
- };
-
- if (State.store.skippedUpdate !== newVersion && isOutdated(oldVersion, newVersion)) {
- openNewUpdateWindow();
- }
- } catch (e) {
- console.error("AppUpdater: Failed to check for updates\n", e);
- }
-}
-
-function openNewUpdateWindow() {
- const win = new BrowserWindow({
- width: 500,
- autoHideMenuBar: true,
- alwaysOnTop: true,
- webPreferences: {
- preload: join(__dirname, "updaterPreload.js"),
- nodeIntegration: false,
- contextIsolation: true,
- sandbox: true
- },
- icon: ICON_PATH
- });
-
- makeLinksOpenExternally(win);
-
- win.loadFile(join(VIEW_DIR, "updater.html"));
-}
diff --git a/src/updater/preload.ts b/src/updater/preload.ts
deleted file mode 100644
index 80e4dee..0000000
--- a/src/updater/preload.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * 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 { contextBridge } from "electron";
-import { invoke } from "preload/typedIpc";
-import { IpcEvents } from "shared/IpcEvents";
-
-import type { UpdateData } from "./main";
-
-contextBridge.exposeInMainWorld("Updater", {
- getData: () => invoke(IpcEvents.UPDATER_GET_DATA),
- download: () => {
- invoke(IpcEvents.UPDATER_DOWNLOAD);
- invoke(IpcEvents.CLOSE);
- },
- ignore: () => invoke(IpcEvents.UPDATE_IGNORE),
- close: () => invoke(IpcEvents.CLOSE)
-});