mirror of
https://github.com/Vencord/Vesktop.git
synced 2025-02-23 13:45:09 +00:00
Merge remote-tracking branch 'origin/main' into tray-icon
This commit is contained in:
commit
7d836b4f2f
84 changed files with 1787 additions and 1194 deletions
9
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
9
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
|
@ -24,6 +24,7 @@ body:
|
|||
- Issues with Input Methods[^4]
|
||||
- Issues with File Drag and Drop[^5]
|
||||
- Network Errors[^6]
|
||||
- Anything about Screenshare Performance[^7]
|
||||
|
||||
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,
|
||||
|
@ -36,6 +37,8 @@ body:
|
|||
[^4]: These things are handled by Chromium / Electron, not us. If they don't work, it's either an issue with your system or a bug with Chromium.
|
||||
[^5]: You are likely using the Vesktop flatpak and trying to drop a file the flatpak can't access. You can fix this by installing Flatseal and using it to grant Vesktop full access to your files
|
||||
[^6]: Issue on your end, you have to fix it. Try changing your DNS to [1.1.1.1 (Cloudflare DNS)](https://developers.cloudflare.com/1.1.1.1/setup/)
|
||||
[^7]: Screensharing is managed entirely by Chromium and your System. For optimal performance, make sure you [enable Hardware Acceleration](https://wiki.archlinux.org/title/Chromium#Hardware_video_acceleration).
|
||||
Depending on GPU driver, it might not be supported. We are actively working on making this work out of the box everywhere.
|
||||
|
||||
- type: input
|
||||
id: discord
|
||||
|
@ -109,10 +112,8 @@ body:
|
|||
attributes:
|
||||
label: Debug Logs
|
||||
description: Run vesktop from the command line. Include the relevant command line output here. If there are any lines that seem relevant, try googling them or searching existing issues
|
||||
value: |
|
||||
```
|
||||
Replace this text with your crash-log. Do not remove the backticks
|
||||
```
|
||||
placeholder: Paste your crash-log here.
|
||||
render: shell
|
||||
validations:
|
||||
required: true
|
||||
|
||||
|
|
12
.github/workflows/meta.yml
vendored
12
.github/workflows/meta.yml
vendored
|
@ -6,6 +6,9 @@ on:
|
|||
- published
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
update:
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -29,10 +32,11 @@ jobs:
|
|||
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
|
||||
|
||||
gh release upload "${{ github.event.release.tag_name }}" meta/dev.vencord.Vesktop.metainfo.xml
|
||||
|
||||
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 }}."
|
||||
git commit -m "metainfo: add entry for ${{ github.event.release.tag_name }}"
|
||||
git push origin main
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
28
.github/workflows/update-vencord-dev.yml
vendored
Normal file
28
.github/workflows/update-vencord-dev.yml
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
name: Update vencord.dev Vesktop version
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
|
||||
jobs:
|
||||
update:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Update scripts/_latestVesktopVersion.txt file in vencord.dev repo
|
||||
run: |
|
||||
git config --global user.name "$USERNAME"
|
||||
git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
git clone https://$USERNAME:$API_TOKEN@github.com/$GH_REPO.git repo
|
||||
|
||||
cd repo
|
||||
echo "${{ github.event.release.tag_name }}" > scripts/_latestVesktopVersion.txt
|
||||
|
||||
git add scripts/_latestVesktopVersion.txt
|
||||
git commit -m "Update Vesktop version to ${{ github.event.release.tag_name }}"
|
||||
git push https://$USERNAME:$API_TOKEN@github.com/$GH_REPO.git
|
||||
env:
|
||||
API_TOKEN: ${{ secrets.VENCORD_DEV_GITHUB_TOKEN }}
|
||||
GH_REPO: Vencord/vencord.dev
|
||||
USERNAME: GitHub-Actions
|
|
@ -53,6 +53,7 @@ Below you can find unofficial packages created by the community. They are not of
|
|||
|
||||
- Arch Linux: [Vesktop on the Arch user repository](https://aur.archlinux.org/packages?K=vesktop)
|
||||
- NixOS: https://wiki.nixos.org/wiki/Discord#Vesktop
|
||||
- Slackware: [Vesktop on the SlackBuilds](https://slackbuilds.org/result/?search=vesktop)
|
||||
- Windows - Scoop: https://scoop.sh/#/apps?q=Vesktop
|
||||
|
||||
## Building from Source
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
//@ts-check
|
||||
|
||||
import stylistic from "@stylistic/eslint-plugin";
|
||||
import pathAlias from "eslint-plugin-path-alias";
|
||||
import header from "eslint-plugin-simple-header";
|
||||
import simpleHeader from "eslint-plugin-simple-header";
|
||||
import importSort from "eslint-plugin-simple-import-sort";
|
||||
import unusedImports from "eslint-plugin-unused-imports";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
@ -20,7 +20,7 @@ export default tseslint.config(
|
|||
{
|
||||
files: ["src/**/*.{tsx,ts,mts,mjs,js,jsx}"],
|
||||
plugins: {
|
||||
header,
|
||||
simpleHeader,
|
||||
stylistic,
|
||||
importSort,
|
||||
unusedImports,
|
||||
|
@ -42,10 +42,11 @@ export default tseslint.config(
|
|||
}
|
||||
},
|
||||
rules: {
|
||||
"header/header": [
|
||||
"simpleHeader/header": [
|
||||
"error",
|
||||
{
|
||||
files: ["scripts/header.txt"]
|
||||
files: ["scripts/header.txt"],
|
||||
templates: { author: [".*", "Vendicated and Vesktop contributors"] }
|
||||
}
|
||||
],
|
||||
|
||||
|
|
|
@ -28,6 +28,21 @@
|
|||
</screenshot>
|
||||
</screenshots>
|
||||
<releases>
|
||||
<release version="1.5.5" date="2025-02-06" type="stable">
|
||||
<url>https://github.com/Vencord/Vesktop/releases/tag/v1.5.5</url>
|
||||
<description>
|
||||
<p>What's Changed</p>
|
||||
<ul>
|
||||
<li>Now remembers your previous Screenshare resolution & FPS</li>
|
||||
<li>You can now disable the splash screen in Vesktop Settings</li>
|
||||
<li>Now supports deep links (opening Discord Message Links in Vesktop) by @Covkie</li>
|
||||
<li>Now supports discord:// uri scheme, allowing it to open things like invites from your Browser even while closed by @Covkie</li>
|
||||
<li>Added 4k resolution to screenshare by @makindotcc</li>
|
||||
<li>Fixed some performance issues caused by a recent Discord update</li>
|
||||
<li>Updated Electron to v34 & chromium to v132, bringing new features and fixes</li>
|
||||
</ul>
|
||||
</description>
|
||||
</release>
|
||||
<release version="1.5.4" date="2024-12-05" type="stable">
|
||||
<url>https://github.com/Vencord/Vesktop/releases/tag/v1.5.4</url>
|
||||
<description>
|
||||
|
|
47
package.json
47
package.json
|
@ -1,11 +1,11 @@
|
|||
{
|
||||
"name": "vesktop",
|
||||
"version": "1.5.4",
|
||||
"version": "1.5.5",
|
||||
"private": true,
|
||||
"description": "Vesktop is a custom Discord desktop app",
|
||||
"keywords": [],
|
||||
"homepage": "https://vencord.dev/",
|
||||
"license": "GPL-3.0",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"author": "Vendicated <vendicated@riseup.net>",
|
||||
"main": "dist/js/main.js",
|
||||
"scripts": {
|
||||
|
@ -21,10 +21,12 @@
|
|||
"test": "pnpm lint && pnpm testTypes",
|
||||
"testTypes": "tsc --noEmit",
|
||||
"watch": "pnpm build --watch",
|
||||
"updateMeta": "tsx scripts/utils/updateMeta.mts"
|
||||
"updateMeta": "tsx scripts/utils/updateMeta.mts",
|
||||
"updateArrpcDB": "node ./node_modules/arrpc/update_db.js",
|
||||
"postinstall": "pnpm updateArrpcDB"
|
||||
},
|
||||
"dependencies": {
|
||||
"arrpc": "github:OpenAsar/arrpc#5aadc307cb9bf4479f0a12364a253b07a77ace22",
|
||||
"arrpc": "github:OpenAsar/arrpc#2234e9c9111f4c42ebcc3aa6a2215bfd979eef77",
|
||||
"electron-updater": "^6.3.9"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
|
@ -33,28 +35,28 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
|
||||
"@stylistic/eslint-plugin": "^2.11.0",
|
||||
"@types/node": "^22.10.1",
|
||||
"@types/react": "^18.3.12",
|
||||
"@stylistic/eslint-plugin": "^3.0.1",
|
||||
"@types/node": "^22.13.1",
|
||||
"@types/react": "18.3.12",
|
||||
"@vencord/types": "^1.8.4",
|
||||
"dotenv": "^16.4.6",
|
||||
"electron": "^33.2.1",
|
||||
"dotenv": "^16.4.7",
|
||||
"electron": "^34.1.0",
|
||||
"electron-builder": "^25.1.8",
|
||||
"esbuild": "^0.24.0",
|
||||
"eslint": "^9.16.0",
|
||||
"esbuild": "^0.24.2",
|
||||
"eslint": "^9.19.0",
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
"eslint-plugin-path-alias": "^2.1.0",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"eslint-plugin-simple-header": "^1.2.1",
|
||||
"eslint-plugin-prettier": "^5.2.3",
|
||||
"eslint-plugin-simple-header": "^1.2.2",
|
||||
"eslint-plugin-simple-import-sort": "^12.1.1",
|
||||
"eslint-plugin-unused-imports": "^4.1.4",
|
||||
"prettier": "^3.4.1",
|
||||
"prettier": "^3.4.2",
|
||||
"source-map-support": "^0.5.21",
|
||||
"tsx": "^4.19.2",
|
||||
"type-fest": "^4.30.0",
|
||||
"typescript": "^5.7.2",
|
||||
"typescript-eslint": "^8.17.0",
|
||||
"xml-formatter": "^3.6.3"
|
||||
"type-fest": "^4.33.0",
|
||||
"typescript": "^5.7.3",
|
||||
"typescript-eslint": "^8.23.0",
|
||||
"xml-formatter": "^3.6.4"
|
||||
},
|
||||
"packageManager": "pnpm@9.1.0",
|
||||
"engines": {
|
||||
|
@ -72,6 +74,12 @@
|
|||
"package.json",
|
||||
"LICENSE"
|
||||
],
|
||||
"protocols": {
|
||||
"name": "Discord",
|
||||
"schemes": [
|
||||
"discord"
|
||||
]
|
||||
},
|
||||
"beforePack": "scripts/build/sandboxFix.js",
|
||||
"linux": {
|
||||
"icon": "build/icon.icns",
|
||||
|
@ -112,7 +120,8 @@
|
|||
"GenericName": "Internet Messenger",
|
||||
"Type": "Application",
|
||||
"Categories": "Network;InstantMessaging;Chat;",
|
||||
"Keywords": "discord;vencord;electron;chat;"
|
||||
"Keywords": "discord;vencord;electron;chat;",
|
||||
"MimeType": "x-scheme-handler/discord"
|
||||
}
|
||||
},
|
||||
"mac": {
|
||||
|
|
|
@ -1,14 +1,27 @@
|
|||
diff --git a/src/process/index.js b/src/process/index.js
|
||||
index 97ea6514b54dd9c5df588c78f0397d31ab5f882a..c2bdbd6aaa5611bc6ff1d993beeb380b1f5ec575 100644
|
||||
index 389b0845256a34b4536d6da99edb00d17f13a6b4..f17a0ac687e9110ebfd33cb91fd2f6250d318643 100644
|
||||
--- a/src/process/index.js
|
||||
+++ b/src/process/index.js
|
||||
@@ -5,8 +5,7 @@ import fs from 'node:fs';
|
||||
@@ -5,8 +5,20 @@ 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');
|
||||
+DetectableDB.push(
|
||||
+ {
|
||||
+ aliases: ["Obs"],
|
||||
+ executables: [
|
||||
+ { is_launcher: false, name: "obs", os: "linux" },
|
||||
+ { is_launcher: false, name: "obs.exe", os: "win32" },
|
||||
+ { is_launcher: false, name: "obs.app", os: "darwin" }
|
||||
+ ],
|
||||
+ hook: true,
|
||||
+ id: "STREAMERMODE",
|
||||
+ name: "OBS"
|
||||
+ }
|
||||
+);
|
||||
|
||||
import * as Natives from './native/index.js';
|
||||
const Native = Natives[process.platform];
|
||||
|
|
1734
pnpm-lock.yaml
generated
1734
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { BuildContext, BuildOptions, context } from "esbuild";
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
/*
|
||||
* 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 const VencordFragment = /* #__PURE__*/ Symbol.for("react.fragment");
|
||||
export let VencordCreateElement = (...args) =>
|
||||
(VencordCreateElement = Vencord.Webpack.Common.React.createElement)(...args);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
// Based on https://github.com/gergof/electron-builder-sandbox-fix/blob/master/lib/index.js
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { globalExternalsWithRegExp } from "@fal-works/esbuild-plugin-global-externals";
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* 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
|
||||
* Copyright (c) {year} {author}
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import "./start";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { config } from "dotenv";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { spawn as spaaawn, SpawnOptions } from "child_process";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { promises as fs } from "node:fs";
|
||||
|
|
2
src/globals.d.ts
vendored
2
src/globals.d.ts
vendored
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
declare global {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { BrowserWindow } from "electron";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { app, NativeImage, nativeImage } from "electron";
|
||||
|
|
|
@ -1,13 +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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import Server from "arrpc";
|
||||
import { IpcEvents } from "shared/IpcEvents";
|
||||
import { IpcCommands } from "shared/IpcEvents";
|
||||
|
||||
import { mainWin } from "./mainWindow";
|
||||
import { sendRendererCommand } from "./ipcCommands";
|
||||
import { Settings } from "./settings";
|
||||
|
||||
let server: any;
|
||||
|
@ -19,16 +19,15 @@ export async function initArRPC() {
|
|||
|
||||
try {
|
||||
server = await new Server();
|
||||
server.on("activity", (data: any) => mainWin.webContents.send(IpcEvents.ARRPC_ACTIVITY, JSON.stringify(data)));
|
||||
server.on("invite", (invite: string, callback: (valid: boolean) => void) => {
|
||||
server.on("activity", (data: any) => sendRendererCommand(IpcCommands.RPC_ACTIVITY, JSON.stringify(data)));
|
||||
server.on("invite", async (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);
|
||||
await sendRendererCommand(IpcCommands.RPC_INVITE, invite).then(callback);
|
||||
});
|
||||
server.on("link", async (data: any, deepCallback: (valid: boolean) => void) => {
|
||||
await sendRendererCommand(IpcCommands.RPC_DEEP_LINK, data).then(deepCallback);
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("Failed to start arRPC server", e);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { app } from "electron";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { app } from "electron";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { app } from "electron";
|
||||
|
@ -28,6 +28,7 @@ interface Data {
|
|||
export function createFirstLaunchTour() {
|
||||
const win = new BrowserWindow({
|
||||
...SplashProps,
|
||||
transparent: false,
|
||||
frame: true,
|
||||
autoHideMenuBar: true,
|
||||
height: 470,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import "./ipc";
|
||||
|
@ -23,10 +23,14 @@ if (IS_DEV) {
|
|||
autoUpdater.checkForUpdatesAndNotify();
|
||||
}
|
||||
|
||||
console.log("Vesktop v" + app.getVersion());
|
||||
|
||||
// Make the Vencord files use our DATA_DIR
|
||||
process.env.VENCORD_USER_DATA_DIR = DATA_DIR;
|
||||
|
||||
function init() {
|
||||
app.setAsDefaultProtocolClient("discord");
|
||||
|
||||
const { disableSmoothScroll, hardwareAcceleration } = Settings.store;
|
||||
|
||||
const enabledFeatures = app.commandLine.getSwitchValue("enable-features").split(",");
|
||||
|
@ -35,7 +39,12 @@ function init() {
|
|||
if (hardwareAcceleration === false) {
|
||||
app.disableHardwareAcceleration();
|
||||
} else {
|
||||
enabledFeatures.push("VaapiVideoDecodeLinuxGL", "VaapiVideoEncoder", "VaapiVideoDecoder");
|
||||
enabledFeatures.push(
|
||||
"AcceleratedVideoDecodeLinuxGL",
|
||||
"AcceleratedVideoEncoder",
|
||||
"AcceleratedVideoDecoder",
|
||||
"AcceleratedVideoDecodeLinuxZeroCopyGL"
|
||||
);
|
||||
}
|
||||
|
||||
if (disableSmoothScroll) {
|
||||
|
@ -112,6 +121,12 @@ async function bootstrap() {
|
|||
}
|
||||
}
|
||||
|
||||
// MacOS only event
|
||||
export let darwinURL: string | undefined;
|
||||
app.on("open-url", (_, url) => {
|
||||
darwinURL = url;
|
||||
});
|
||||
|
||||
app.on("window-all-closed", () => {
|
||||
if (process.platform !== "darwin") app.quit();
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
if (process.platform === "linux") import("./venmic");
|
||||
|
@ -144,6 +144,17 @@ handle(IpcEvents.CLIPBOARD_COPY_IMAGE, async (_, buf: ArrayBuffer, src: string)
|
|||
});
|
||||
});
|
||||
|
||||
function openDebugPage(page: string) {
|
||||
const win = new BrowserWindow({
|
||||
autoHideMenuBar: true
|
||||
});
|
||||
|
||||
win.loadURL(page);
|
||||
}
|
||||
|
||||
handle(IpcEvents.DEBUG_LAUNCH_GPU, () => openDebugPage("chrome://gpu"));
|
||||
handle(IpcEvents.DEBUG_LAUNCH_WEBRTC_INTERNALS, () => openDebugPage("chrome://webrtc-internals"));
|
||||
|
||||
function readCss() {
|
||||
return readFile(VENCORD_QUICKCSS_FILE, "utf-8").catch(() => "");
|
||||
}
|
||||
|
|
56
src/main/ipcCommands.ts
Normal file
56
src/main/ipcCommands.ts
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2025 Vendicated and Vencord contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { randomUUID } from "crypto";
|
||||
import { ipcMain } from "electron";
|
||||
import { IpcEvents } from "shared/IpcEvents";
|
||||
|
||||
import { mainWin } from "./mainWindow";
|
||||
|
||||
const resolvers = new Map<string, Record<"resolve" | "reject", (data: any) => void>>();
|
||||
|
||||
export interface IpcMessage {
|
||||
nonce: string;
|
||||
message: string;
|
||||
data?: any;
|
||||
}
|
||||
|
||||
export interface IpcResponse {
|
||||
nonce: string;
|
||||
ok: boolean;
|
||||
data?: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a message to the renderer process and waits for a response.
|
||||
* `data` must be serializable as it will be sent over IPC.
|
||||
*
|
||||
* You must add a handler for the message in the renderer process.
|
||||
*/
|
||||
export function sendRendererCommand<T = any>(message: string, data?: any) {
|
||||
const nonce = randomUUID();
|
||||
|
||||
const promise = new Promise<T>((resolve, reject) => {
|
||||
resolvers.set(nonce, { resolve, reject });
|
||||
});
|
||||
|
||||
mainWin.webContents.send(IpcEvents.IPC_COMMAND, { nonce, message, data });
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
ipcMain.on(IpcEvents.IPC_COMMAND, (_event, { nonce, ok, data }: IpcResponse) => {
|
||||
const resolver = resolvers.get(nonce);
|
||||
if (!resolver) throw new Error(`Unknown message: ${nonce}`);
|
||||
|
||||
if (ok) {
|
||||
resolver.resolve(data);
|
||||
} else {
|
||||
resolver.reject(data);
|
||||
}
|
||||
|
||||
resolvers.delete(nonce);
|
||||
});
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import dbus from "@homebridge/dbus-native";
|
||||
|
@ -21,7 +21,7 @@ import {
|
|||
import { existsSync } from "fs";
|
||||
import { rm } from "fs/promises";
|
||||
import { join } from "path";
|
||||
import { IpcEvents } from "shared/IpcEvents";
|
||||
import { IpcCommands, IpcEvents } from "shared/IpcEvents";
|
||||
import { ICON_PATH, ICONS_DIR } from "shared/paths";
|
||||
import { isTruthy } from "shared/utils/guards";
|
||||
import { once } from "shared/utils/once";
|
||||
|
@ -39,6 +39,8 @@ import {
|
|||
MIN_WIDTH,
|
||||
VENCORD_FILES_DIR
|
||||
} from "./constants";
|
||||
import { darwinURL } from "./index";
|
||||
import { sendRendererCommand } from "./ipcCommands";
|
||||
import { Settings, State, VencordSettings } from "./settings";
|
||||
import { createSplashWindow } from "./splash";
|
||||
import { makeLinksOpenExternally } from "./utils/makeLinksOpenExternally";
|
||||
|
@ -205,9 +207,7 @@ function initMenuBar(win: BrowserWindow) {
|
|||
label: "Settings",
|
||||
accelerator: "CmdOrCtrl+,",
|
||||
async click() {
|
||||
mainWin.webContents.executeJavaScript(
|
||||
"Vencord.Webpack.Common.SettingsRouter.open('My Account')"
|
||||
);
|
||||
sendRendererCommand(IpcCommands.NAVIGATE_SETTINGS);
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -278,7 +278,7 @@ function getWindowBoundsOptions(): BrowserWindowConstructorOptions {
|
|||
height: height ?? DEFAULT_HEIGHT
|
||||
} as BrowserWindowConstructorOptions;
|
||||
|
||||
const storedDisplay = screen.getAllDisplays().find(display => display.id === State.store.displayid);
|
||||
const storedDisplay = screen.getAllDisplays().find(display => display.id === State.store.displayId);
|
||||
|
||||
if (x != null && y != null && storedDisplay) {
|
||||
options.x = x;
|
||||
|
@ -306,7 +306,7 @@ function getDarwinOptions(): BrowserWindowConstructorOptions {
|
|||
options.vibrancy = "sidebar";
|
||||
options.backgroundColor = "#ffffff00";
|
||||
} else {
|
||||
if (splashTheming) {
|
||||
if (splashTheming !== false) {
|
||||
options.backgroundColor = splashBackground;
|
||||
} else {
|
||||
options.backgroundColor = nativeTheme.shouldUseDarkColors ? "#313338" : "#ffffff";
|
||||
|
@ -328,7 +328,7 @@ function initWindowBoundsListeners(win: BrowserWindow) {
|
|||
|
||||
const saveBounds = () => {
|
||||
State.store.windowBounds = win.getBounds();
|
||||
State.store.displayid = screen.getDisplayMatching(State.store.windowBounds).id;
|
||||
State.store.displayId = screen.getDisplayMatching(State.store.windowBounds).id;
|
||||
};
|
||||
|
||||
win.on("resize", saveBounds);
|
||||
|
@ -340,6 +340,7 @@ function initSettingsListeners(win: BrowserWindow) {
|
|||
if (enable) initTray(win);
|
||||
else tray?.destroy();
|
||||
});
|
||||
|
||||
addSettingsListener("disableMinSize", disable => {
|
||||
if (disable) {
|
||||
// 0 no work
|
||||
|
@ -373,7 +374,7 @@ function initSettingsListeners(win: BrowserWindow) {
|
|||
}
|
||||
|
||||
async function initSpellCheckLanguages(win: BrowserWindow, languages?: string[]) {
|
||||
languages ??= await win.webContents.executeJavaScript("[...new Set(navigator.languages)]").catch(() => []);
|
||||
languages ??= await sendRendererCommand(IpcCommands.GET_LANGUAGES);
|
||||
if (!languages) return;
|
||||
|
||||
const ses = session.defaultSession;
|
||||
|
@ -391,19 +392,38 @@ function initSpellCheck(win: BrowserWindow) {
|
|||
initSpellCheckLanguages(win, Settings.store.spellCheckLanguages);
|
||||
}
|
||||
|
||||
function initStaticTitle(win: BrowserWindow) {
|
||||
const listener = (e: { preventDefault: Function }) => e.preventDefault();
|
||||
|
||||
if (Settings.store.staticTitle) win.on("page-title-updated", listener);
|
||||
|
||||
addSettingsListener("staticTitle", enabled => {
|
||||
if (enabled) {
|
||||
win.setTitle("Vesktop");
|
||||
win.on("page-title-updated", listener);
|
||||
} else {
|
||||
win.off("page-title-updated", listener);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createMainWindow() {
|
||||
// Clear up previous settings listeners
|
||||
removeSettingsListeners();
|
||||
removeVencordSettingsListeners();
|
||||
|
||||
const { staticTitle, transparencyOption, enableMenu, customTitleBar } = Settings.store;
|
||||
const { staticTitle, transparencyOption, enableMenu, customTitleBar, splashTheming, splashBackground } =
|
||||
Settings.store;
|
||||
|
||||
const { frameless, transparent } = VencordSettings.store;
|
||||
|
||||
const noFrame = frameless === true || customTitleBar === true;
|
||||
const backgroundColor =
|
||||
splashTheming !== false ? splashBackground : nativeTheme.shouldUseDarkColors ? "#313338" : "#ffffff";
|
||||
|
||||
const win = (mainWin = new BrowserWindow({
|
||||
show: false,
|
||||
show: Settings.store.enableSplashScreen === false,
|
||||
backgroundColor,
|
||||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
sandbox: false,
|
||||
|
@ -451,44 +471,51 @@ function createMainWindow() {
|
|||
return false;
|
||||
});
|
||||
|
||||
if (Settings.store.staticTitle) win.on("page-title-updated", e => e.preventDefault());
|
||||
|
||||
initWindowBoundsListeners(win);
|
||||
if (!isDeckGameMode && (Settings.store.tray ?? true) && process.platform !== "darwin") initTray(win);
|
||||
initMenuBar(win);
|
||||
makeLinksOpenExternally(win);
|
||||
initSettingsListeners(win);
|
||||
initSpellCheck(win);
|
||||
initStaticTitle(win);
|
||||
|
||||
win.webContents.setUserAgent(BrowserUserAgent);
|
||||
|
||||
const subdomain =
|
||||
Settings.store.discordBranch === "canary" || Settings.store.discordBranch === "ptb"
|
||||
? `${Settings.store.discordBranch}.`
|
||||
: "";
|
||||
|
||||
win.loadURL(`https://${subdomain}discord.com/app`);
|
||||
// if the open-url event is fired (in index.ts) while starting up, darwinURL will be set. If not fall back to checking the process args (which Windows and Linux use for URI calling.)
|
||||
loadUrl(darwinURL || process.argv.find(arg => arg.startsWith("discord://")));
|
||||
|
||||
return win;
|
||||
}
|
||||
|
||||
const runVencordMain = once(() => require(join(VENCORD_FILES_DIR, "vencordDesktopMain.js")));
|
||||
|
||||
export function loadUrl(uri: string | undefined) {
|
||||
const branch = Settings.store.discordBranch;
|
||||
const subdomain = branch === "canary" || branch === "ptb" ? `${branch}.` : "";
|
||||
mainWin.loadURL(`https://${subdomain}discord.com/${uri ? new URL(uri).pathname.slice(1) || "app" : "app"}`);
|
||||
}
|
||||
|
||||
export async function createWindows() {
|
||||
const startMinimized = process.argv.includes("--start-minimized");
|
||||
const splash = createSplashWindow(startMinimized);
|
||||
|
||||
let splash: BrowserWindow | undefined;
|
||||
if (Settings.store.enableSplashScreen !== false) {
|
||||
splash = createSplashWindow(startMinimized);
|
||||
|
||||
// SteamOS letterboxes and scales it terribly, so just full screen it
|
||||
if (isDeckGameMode) splash.setFullScreen(true);
|
||||
}
|
||||
|
||||
await ensureVencordFiles();
|
||||
runVencordMain();
|
||||
|
||||
mainWin = createMainWindow();
|
||||
|
||||
mainWin.webContents.on("did-finish-load", () => {
|
||||
splash.destroy();
|
||||
splash?.destroy();
|
||||
|
||||
if (!startMinimized) {
|
||||
mainWin!.show();
|
||||
if (splash) mainWin!.show();
|
||||
if (State.store.maximized && !isDeckGameMode) mainWin!.maximize();
|
||||
}
|
||||
|
||||
|
@ -506,6 +533,14 @@ export async function createWindows() {
|
|||
});
|
||||
});
|
||||
|
||||
mainWin.webContents.on("did-navigate", (_, url: string, responseCode: number) => {
|
||||
// check url to ensure app doesn't loop
|
||||
if (responseCode >= 300 && new URL(url).pathname !== `/app`) {
|
||||
loadUrl(undefined);
|
||||
console.warn(`'did-navigate': Caught bad page response: ${responseCode}, redirecting to main app`);
|
||||
}
|
||||
});
|
||||
|
||||
initArRPC();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { session, systemPreferences } from "electron";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { desktopCapturer, session, Streams } from "electron";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { BrowserWindow } from "electron";
|
||||
|
@ -22,7 +22,7 @@ export function createSplashWindow(startMinimized = false) {
|
|||
|
||||
const { splashBackground, splashColor, splashTheming } = Settings.store;
|
||||
|
||||
if (splashTheming) {
|
||||
if (splashTheming !== false) {
|
||||
if (splashColor) {
|
||||
const semiTransparentSplashColor = splashColor.replace("rgb(", "rgba(").replace(")", ", 0.2)");
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { createWriteStream } from "fs";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { ipcMain, IpcMainEvent, IpcMainInvokeEvent, WebFrameMain } from "electron";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { BrowserWindow, shell } from "electron";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { BrowserWindow, BrowserWindowConstructorOptions } from "electron";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { BrowserWindow, dialog } from "electron";
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { mkdirSync } from "fs";
|
||||
import { access, constants as FsConstants } from "fs/promises";
|
||||
import { access, constants as FsConstants, writeFile } from "fs/promises";
|
||||
import { join } from "path";
|
||||
|
||||
import { USER_AGENT, VENCORD_FILES_DIR } from "../constants";
|
||||
|
@ -63,7 +63,8 @@ const existsAsync = (path: string) =>
|
|||
.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));
|
||||
const results = await Promise.all(["package.json", ...FILES_TO_DOWNLOAD].map(f => existsAsync(join(dir, f))));
|
||||
return !results.includes(false);
|
||||
}
|
||||
|
||||
export async function ensureVencordFiles() {
|
||||
|
@ -71,5 +72,5 @@ export async function ensureVencordFiles() {
|
|||
|
||||
mkdirSync(VENCORD_FILES_DIR, { recursive: true });
|
||||
|
||||
await downloadVencordFiles();
|
||||
await Promise.all([downloadVencordFiles(), writeFile(join(VENCORD_FILES_DIR, "package.json"), "{}")]);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { LinkData, Node, PatchBay as PatchBayType } from "@vencord/venmic";
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Node } from "@vencord/venmic";
|
||||
import { ipcRenderer } from "electron";
|
||||
import { IpcMessage, IpcResponse } from "main/ipcCommands";
|
||||
import type { Settings } from "shared/settings";
|
||||
|
||||
import { IpcEvents } from "../shared/IpcEvents";
|
||||
|
@ -73,11 +74,6 @@ export const VesktopNative = {
|
|||
startSystem: (exclude: Node[]) => invoke<void>(IpcEvents.VIRT_MIC_START_SYSTEM, exclude),
|
||||
stop: () => invoke<void>(IpcEvents.VIRT_MIC_STOP)
|
||||
},
|
||||
arrpc: {
|
||||
onActivity(cb: (data: string) => void) {
|
||||
ipcRenderer.on(IpcEvents.ARRPC_ACTIVITY, (_, data: string) => cb(data));
|
||||
}
|
||||
},
|
||||
clipboard: {
|
||||
copyImage: (imageBuffer: Uint8Array, imageSrc: string) =>
|
||||
invoke<void>(IpcEvents.CLIPBOARD_COPY_IMAGE, imageBuffer, imageSrc)
|
||||
|
@ -107,5 +103,15 @@ export const VesktopNative = {
|
|||
);
|
||||
},
|
||||
returnIconWithBadge: (dataURL: string) => invoke<void>(IpcEvents.GET_ICON_WITH_BADGE, dataURL)
|
||||
},
|
||||
debug: {
|
||||
launchGpu: () => invoke<void>(IpcEvents.DEBUG_LAUNCH_GPU),
|
||||
launchWebrtcInternals: () => invoke<void>(IpcEvents.DEBUG_LAUNCH_WEBRTC_INTERNALS)
|
||||
},
|
||||
commands: {
|
||||
onCommand(cb: (message: IpcMessage) => void) {
|
||||
ipcRenderer.on(IpcEvents.IPC_COMMAND, (_, message) => cb(message));
|
||||
},
|
||||
respond: (response: IpcResponse) => ipcRenderer.send(IpcEvents.IPC_COMMAND, response)
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { contextBridge, ipcRenderer, webFrame } from "electron";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { ipcRenderer } from "electron";
|
||||
|
|
|
@ -1,12 +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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { filters, waitFor } from "@vencord/types/webpack";
|
||||
import { RelationshipStore } from "@vencord/types/webpack/common";
|
||||
|
||||
import { VesktopLogger } from "./logger";
|
||||
import { Settings } from "./settings";
|
||||
|
||||
let GuildReadStateStore: any;
|
||||
|
@ -26,7 +27,7 @@ export function setBadge() {
|
|||
|
||||
VesktopNative.app.setBadgeCount(totalCount);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
VesktopLogger.error("Failed to update badge count", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
68
src/renderer/arrpc.ts
Normal file
68
src/renderer/arrpc.ts
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2025 Vendicated and Vencord contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Logger } from "@vencord/types/utils";
|
||||
import { findLazy, findStoreLazy, onceReady } from "@vencord/types/webpack";
|
||||
import { FluxDispatcher, InviteActions } from "@vencord/types/webpack/common";
|
||||
import { IpcCommands } from "shared/IpcEvents";
|
||||
|
||||
import { onIpcCommand } from "./ipcCommands";
|
||||
import { Settings } from "./settings";
|
||||
|
||||
const logger = new Logger("VesktopRPC", "#5865f2");
|
||||
const StreamerModeStore = findStoreLazy("StreamerModeStore");
|
||||
|
||||
const arRPC = Vencord.Plugins.plugins["WebRichPresence (arRPC)"] as any as {
|
||||
handleEvent(e: MessageEvent): void;
|
||||
};
|
||||
|
||||
onIpcCommand(IpcCommands.RPC_ACTIVITY, async jsonData => {
|
||||
if (!Settings.store.arRPC) return;
|
||||
|
||||
await onceReady;
|
||||
|
||||
const data = JSON.parse(jsonData);
|
||||
|
||||
if (data.socketId === "STREAMERMODE" && StreamerModeStore.autoToggle) {
|
||||
FluxDispatcher.dispatch({
|
||||
type: "STREAMER_MODE_UPDATE",
|
||||
key: "enabled",
|
||||
value: data.activity?.application_id === "STREAMERMODE"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
arRPC.handleEvent(new MessageEvent("message", { data: jsonData }));
|
||||
});
|
||||
|
||||
onIpcCommand(IpcCommands.RPC_INVITE, async code => {
|
||||
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 { DEEP_LINK } = findLazy(m => m.DEEP_LINK?.handler);
|
||||
|
||||
onIpcCommand(IpcCommands.RPC_DEEP_LINK, async data => {
|
||||
logger.debug("Opening deep link:", data);
|
||||
try {
|
||||
DEEP_LINK.handler({ args: data });
|
||||
return true;
|
||||
} catch (err) {
|
||||
logger.error("Failed to open deep link:", err);
|
||||
return false;
|
||||
}
|
||||
});
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import "./screenSharePicker.css";
|
||||
|
@ -22,12 +22,14 @@ import {
|
|||
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";
|
||||
import { State, useSettings, useVesktopState } from "renderer/settings";
|
||||
import { classNameFactory, isLinux, isWindows } from "renderer/utils";
|
||||
|
||||
const StreamResolutions = ["480", "720", "1080", "1440"] as const;
|
||||
const StreamResolutions = ["480", "720", "1080", "1440", "2160"] as const;
|
||||
const StreamFps = ["15", "30", "60"] as const;
|
||||
|
||||
const cl = classNameFactory("vcd-screen-picker-");
|
||||
|
||||
const MediaEngineStore = findStoreLazy("MediaEngineStore");
|
||||
|
||||
export type StreamResolution = (typeof StreamResolutions)[number];
|
||||
|
@ -44,8 +46,6 @@ interface AudioItem {
|
|||
}
|
||||
|
||||
interface StreamSettings {
|
||||
resolution: StreamResolution;
|
||||
fps: StreamFps;
|
||||
audio: boolean;
|
||||
contentHint?: string;
|
||||
includeSources?: AudioSources;
|
||||
|
@ -77,10 +77,11 @@ addPatch({
|
|||
}
|
||||
],
|
||||
patchStreamQuality(opts: any) {
|
||||
if (!currentSettings) return;
|
||||
const { screenshareQuality } = State.store;
|
||||
if (!screenshareQuality) return;
|
||||
|
||||
const framerate = Number(currentSettings.fps);
|
||||
const height = Number(currentSettings.resolution);
|
||||
const framerate = Number(screenshareQuality.frameRate);
|
||||
const height = Number(screenshareQuality.resolution);
|
||||
const width = Math.round(height * (16 / 9));
|
||||
|
||||
Object.assign(opts, {
|
||||
|
@ -161,13 +162,21 @@ export function openScreenSharePicker(screens: Source[], skipPicker: boolean) {
|
|||
|
||||
function ScreenPicker({ screens, chooseScreen }: { screens: Source[]; chooseScreen: (id: string) => void }) {
|
||||
return (
|
||||
<div className="vcd-screen-picker-grid">
|
||||
<div className={cl("screen-grid")}>
|
||||
{screens.map(({ id, name, url }) => (
|
||||
<label key={id}>
|
||||
<input type="radio" name="screen" value={id} onChange={() => chooseScreen(id)} />
|
||||
<label key={id} className={cl("screen-label")}>
|
||||
<input
|
||||
type="radio"
|
||||
className={cl("screen-radio")}
|
||||
name="screen"
|
||||
value={id}
|
||||
onChange={() => chooseScreen(id)}
|
||||
/>
|
||||
|
||||
<img src={url} alt="" />
|
||||
<Text variant="text-sm/normal">{name}</Text>
|
||||
<Text className={cl("screen-name")} variant="text-sm/normal">
|
||||
{name}
|
||||
</Text>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
|
@ -187,11 +196,13 @@ function AudioSettingsModal({
|
|||
|
||||
return (
|
||||
<Modals.ModalRoot {...modalProps} size={ModalSize.MEDIUM}>
|
||||
<Modals.ModalHeader className="vcd-screen-picker-header">
|
||||
<Forms.FormTitle tag="h2">Venmic Settings</Forms.FormTitle>
|
||||
<Modals.ModalHeader className={cl("header")}>
|
||||
<Forms.FormTitle tag="h2" className={cl("header-title")}>
|
||||
Venmic Settings
|
||||
</Forms.FormTitle>
|
||||
<Modals.ModalCloseButton onClick={close} />
|
||||
</Modals.ModalHeader>
|
||||
<Modals.ModalContent className="vcd-screen-picker-modal">
|
||||
<Modals.ModalContent className={cl("modal")}>
|
||||
<Switch
|
||||
hideBorder
|
||||
onChange={v => (Settings.audio = { ...Settings.audio, workaround: v })}
|
||||
|
@ -295,7 +306,7 @@ function AudioSettingsModal({
|
|||
Device Selection
|
||||
</Switch>
|
||||
</Modals.ModalContent>
|
||||
<Modals.ModalFooter className="vcd-screen-picker-footer">
|
||||
<Modals.ModalFooter className={cl("footer")}>
|
||||
<Button color={Button.Colors.TRANSPARENT} onClick={close}>
|
||||
Back
|
||||
</Button>
|
||||
|
@ -304,7 +315,35 @@ function AudioSettingsModal({
|
|||
);
|
||||
}
|
||||
|
||||
function StreamSettings({
|
||||
function OptionRadio<Settings extends object, Key extends keyof Settings>(props: {
|
||||
options: Array<string> | ReadonlyArray<string>;
|
||||
labels?: Array<string>;
|
||||
settings: Settings;
|
||||
settingsKey: Key;
|
||||
onChange: (option: string) => void;
|
||||
}) {
|
||||
const { options, settings, settingsKey, labels, onChange } = props;
|
||||
|
||||
return (
|
||||
<div className={cl("option-radios")}>
|
||||
{(options as string[]).map((option, idx) => (
|
||||
<label className={cl("option-radio")} data-checked={settings[settingsKey] === option} key={option}>
|
||||
<Text variant="text-sm/bold">{labels?.[idx] ?? option}</Text>
|
||||
<input
|
||||
className={cl("option-input")}
|
||||
type="radio"
|
||||
name="fps"
|
||||
value={option}
|
||||
checked={settings[settingsKey] === option}
|
||||
onChange={() => onChange(option)}
|
||||
/>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function StreamSettingsUi({
|
||||
source,
|
||||
settings,
|
||||
setSettings,
|
||||
|
@ -316,6 +355,7 @@ function StreamSettings({
|
|||
skipPicker: boolean;
|
||||
}) {
|
||||
const Settings = useSettings();
|
||||
const qualitySettings = State.store.screenshareQuality!;
|
||||
|
||||
const [thumb] = useAwaiter(
|
||||
() => (skipPicker ? Promise.resolve(source.url) : VesktopNative.capturer.getLargeThumbnail(source.id)),
|
||||
|
@ -340,88 +380,47 @@ function StreamSettings({
|
|||
return (
|
||||
<div>
|
||||
<Forms.FormTitle>What you're streaming</Forms.FormTitle>
|
||||
<Card className="vcd-screen-picker-card vcd-screen-picker-preview">
|
||||
<img
|
||||
src={thumb}
|
||||
alt=""
|
||||
className={isLinux ? "vcd-screen-picker-preview-img-linux" : "vcd-screen-picker-preview-img"}
|
||||
/>
|
||||
<Card className={cl("card", "preview")}>
|
||||
<img src={thumb} alt="" className={cl(isLinux ? "preview-img-linux" : "preview-img")} />
|
||||
<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>
|
||||
<Card className={cl("card")}>
|
||||
<div className={cl("quality")}>
|
||||
<section className={cl("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 }))}
|
||||
<OptionRadio
|
||||
options={StreamResolutions}
|
||||
settings={qualitySettings}
|
||||
settingsKey="resolution"
|
||||
onChange={value => (qualitySettings.resolution = value)}
|
||||
/>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<section className={cl("quality-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 }))}
|
||||
<OptionRadio
|
||||
options={StreamFps}
|
||||
settings={qualitySettings}
|
||||
settingsKey="frameRate"
|
||||
onChange={value => (qualitySettings.frameRate = value)}
|
||||
/>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div className="vcd-screen-picker-quality">
|
||||
<section>
|
||||
<div className={cl("quality")}>
|
||||
<section className={cl("quality-section")}>
|
||||
<Forms.FormTitle>Content Type</Forms.FormTitle>
|
||||
<div>
|
||||
<div className="vcd-screen-picker-radios">
|
||||
<label
|
||||
className="vcd-screen-picker-radio"
|
||||
data-checked={settings.contentHint === "motion"}
|
||||
>
|
||||
<Text variant="text-sm/bold">Prefer Smoothness</Text>
|
||||
<input
|
||||
type="radio"
|
||||
name="contenthint"
|
||||
value="motion"
|
||||
checked={settings.contentHint === "motion"}
|
||||
onChange={() => setSettings(s => ({ ...s, contentHint: "motion" }))}
|
||||
<OptionRadio
|
||||
options={["motion", "detail"]}
|
||||
labels={["Prefer Smoothness", "Prefer Clarity"]}
|
||||
settings={settings}
|
||||
settingsKey="contentHint"
|
||||
onChange={option => setSettings(s => ({ ...s, contentHint: option }))}
|
||||
/>
|
||||
</label>
|
||||
<label
|
||||
className="vcd-screen-picker-radio"
|
||||
data-checked={settings.contentHint === "detail"}
|
||||
>
|
||||
<Text variant="text-sm/bold">Prefer Clarity</Text>
|
||||
<input
|
||||
type="radio"
|
||||
name="contenthint"
|
||||
value="detail"
|
||||
checked={settings.contentHint === "detail"}
|
||||
onChange={() => setSettings(s => ({ ...s, contentHint: "detail" }))}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div className="vcd-screen-picker-hint-description">
|
||||
<div className={cl("hint-description")}>
|
||||
<p>
|
||||
Choosing "Prefer Clarity" will result in a significantly lower framerate in exchange
|
||||
for a much sharper and clearer image.
|
||||
|
@ -433,7 +432,7 @@ function StreamSettings({
|
|||
value={settings.audio}
|
||||
onChange={checked => setSettings(s => ({ ...s, audio: checked }))}
|
||||
hideBorder
|
||||
className="vcd-screen-picker-audio"
|
||||
className={cl("audio")}
|
||||
>
|
||||
Stream With Audio
|
||||
</Switch>
|
||||
|
@ -639,7 +638,7 @@ function AudioSourcePickerLinux({
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className={includeSources === "Entire System" ? "vcd-screen-picker-quality" : undefined}>
|
||||
<div className={cl({ quality: includeSources === "Entire System" })}>
|
||||
<section>
|
||||
<Forms.FormTitle>{loading ? "Loading Sources..." : "Audio Sources"}</Forms.FormTitle>
|
||||
<Select
|
||||
|
@ -675,11 +674,7 @@ function AudioSourcePickerLinux({
|
|||
</section>
|
||||
)}
|
||||
</div>
|
||||
<Button
|
||||
color={Button.Colors.TRANSPARENT}
|
||||
onClick={openSettings}
|
||||
className="vcd-screen-picker-settings-button"
|
||||
>
|
||||
<Button color={Button.Colors.TRANSPARENT} onClick={openSettings} className={cl("settings-button")}>
|
||||
Open Audio Settings
|
||||
</Button>
|
||||
</>
|
||||
|
@ -701,24 +696,26 @@ function ModalComponent({
|
|||
}) {
|
||||
const [selected, setSelected] = useState<string | undefined>(skipPicker ? screens[0].id : void 0);
|
||||
const [settings, setSettings] = useState<StreamSettings>({
|
||||
resolution: "720",
|
||||
fps: "30",
|
||||
contentHint: "motion",
|
||||
audio: true,
|
||||
includeSources: "None"
|
||||
});
|
||||
const qualitySettings = (useVesktopState().screenshareQuality ??= {
|
||||
resolution: "720",
|
||||
frameRate: "30"
|
||||
});
|
||||
|
||||
return (
|
||||
<Modals.ModalRoot {...modalProps} size={ModalSize.MEDIUM}>
|
||||
<Modals.ModalHeader className="vcd-screen-picker-header">
|
||||
<Modals.ModalHeader className={cl("header")}>
|
||||
<Forms.FormTitle tag="h2">ScreenShare</Forms.FormTitle>
|
||||
<Modals.ModalCloseButton onClick={close} />
|
||||
</Modals.ModalHeader>
|
||||
<Modals.ModalContent className="vcd-screen-picker-modal">
|
||||
<Modals.ModalContent className={cl("modal")}>
|
||||
{!selected ? (
|
||||
<ScreenPicker screens={screens} chooseScreen={setSelected} />
|
||||
) : (
|
||||
<StreamSettings
|
||||
<StreamSettingsUi
|
||||
source={screens.find(s => s.id === selected)!}
|
||||
settings={settings}
|
||||
setSettings={setSettings}
|
||||
|
@ -726,14 +723,14 @@ function ModalComponent({
|
|||
/>
|
||||
)}
|
||||
</Modals.ModalContent>
|
||||
<Modals.ModalFooter className="vcd-screen-picker-footer">
|
||||
<Modals.ModalFooter className={cl("footer")}>
|
||||
<Button
|
||||
disabled={!selected}
|
||||
onClick={() => {
|
||||
currentSettings = settings;
|
||||
try {
|
||||
const frameRate = Number(settings.fps);
|
||||
const height = Number(settings.resolution);
|
||||
const frameRate = Number(qualitySettings.frameRate);
|
||||
const height = Number(qualitySettings.resolution);
|
||||
const width = Math.round(height * (16 / 9));
|
||||
|
||||
const conn = [...MediaEngineStore.getMediaEngine().connections].find(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export * as ScreenShare from "./ScreenSharePicker";
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
padding: 1em;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-header h1 {
|
||||
.vcd-screen-picker-header-title {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
@ -15,23 +15,20 @@
|
|||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-grid {
|
||||
|
||||
/* Screen Grid */
|
||||
.vcd-screen-picker-screen-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 2em 1em;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-grid input {
|
||||
.vcd-screen-picker-screen-radio {
|
||||
appearance: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-selected img {
|
||||
border: 2px solid var(--brand-500);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-grid label {
|
||||
.vcd-screen-picker-screen-label {
|
||||
overflow: hidden;
|
||||
padding: 8px;
|
||||
cursor: pointer;
|
||||
|
@ -39,11 +36,11 @@
|
|||
justify-items: center;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-grid label:hover {
|
||||
.vcd-screen-picker-screen-label:hover {
|
||||
outline: 2px solid var(--brand-500);
|
||||
}
|
||||
|
||||
.vcd-screen-picker-grid div {
|
||||
.vcd-screen-picker-screen-name {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
|
@ -75,37 +72,48 @@
|
|||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-radio input {
|
||||
display: none;
|
||||
|
||||
/* Option Radios */
|
||||
|
||||
.vcd-screen-picker-option-radios {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-radio {
|
||||
.vcd-screen-picker-option-radio {
|
||||
flex: 1 1 auto;
|
||||
text-align: center;
|
||||
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-option-radio:first-child {
|
||||
border-radius: 3px 0 0 3px;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-radio[data-checked="true"] {
|
||||
.vcd-screen-picker-option-radio:last-child {
|
||||
border-radius: 0 3px 3px 0;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-option-input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vcd-screen-picker-option-radio[data-checked="true"] {
|
||||
background-color: var(--brand-500);
|
||||
border-color: var(--brand-500);
|
||||
}
|
||||
|
||||
.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 {
|
||||
.vcd-screen-picker-quality-section {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
|
@ -114,24 +122,6 @@
|
|||
margin-top: 0.3rem;
|
||||
}
|
||||
|
||||
.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,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Switch, useState } from "@vencord/types/webpack/common";
|
||||
|
|
|
@ -1,15 +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
|
||||
* Copyright (c) 2025 Vendicated and Vencord contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { useForceUpdater } from "@vencord/types/utils";
|
||||
import { Button, Forms, Toasts } from "@vencord/types/webpack/common";
|
||||
import {
|
||||
Margins,
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalHeader,
|
||||
ModalRoot,
|
||||
ModalSize,
|
||||
openModal,
|
||||
useForceUpdater
|
||||
} from "@vencord/types/utils";
|
||||
import { Button, Forms, Text, Toasts } from "@vencord/types/webpack/common";
|
||||
import { Settings } from "shared/settings";
|
||||
|
||||
import { SettingsComponent } from "./Settings";
|
||||
|
||||
export const VencordLocationPicker: SettingsComponent = ({ settings }) => {
|
||||
export const DeveloperOptionsButton: SettingsComponent = ({ settings }) => {
|
||||
return <Button onClick={() => openDeveloperOptionsModal(settings)}>Open Developer Settings</Button>;
|
||||
};
|
||||
|
||||
function openDeveloperOptionsModal(settings: Settings) {
|
||||
openModal(props => (
|
||||
<ModalRoot {...props} size={ModalSize.MEDIUM}>
|
||||
<ModalHeader>
|
||||
<Text variant="heading-lg/semibold" style={{ flexGrow: 1 }}>
|
||||
Vesktop Developer Options
|
||||
</Text>
|
||||
<ModalCloseButton onClick={props.onClose} />
|
||||
</ModalHeader>
|
||||
|
||||
<ModalContent>
|
||||
<div style={{ padding: "1em 0" }}>
|
||||
<Forms.FormTitle tag="h5">Vencord Location</Forms.FormTitle>
|
||||
<VencordLocationPicker settings={settings} />
|
||||
|
||||
<Forms.FormTitle tag="h5" className={Margins.top16}>
|
||||
Debugging
|
||||
</Forms.FormTitle>
|
||||
<div className="vcd-settings-button-grid">
|
||||
<Button onClick={() => VesktopNative.debug.launchGpu()}>Open chrome://gpu</Button>
|
||||
<Button onClick={() => VesktopNative.debug.launchWebrtcInternals()}>
|
||||
Open chrome://webrtc-internals
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</ModalContent>
|
||||
</ModalRoot>
|
||||
));
|
||||
}
|
||||
|
||||
const VencordLocationPicker: SettingsComponent = ({ settings }) => {
|
||||
const forceUpdate = useForceUpdater();
|
||||
const vencordDir = VesktopNative.fileManager.getVencordDir();
|
||||
|
||||
|
@ -31,7 +75,7 @@ export const VencordLocationPicker: SettingsComponent = ({ settings }) => {
|
|||
"the default location"
|
||||
)}
|
||||
</Forms.FormText>
|
||||
<div className="vcd-location-btns">
|
||||
<div className="vcd-settings-button-grid">
|
||||
<Button
|
||||
size={Button.Sizes.SMALL}
|
||||
onClick={async () => {
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Select } from "@vencord/types/webpack/common";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Switch } from "@vencord/types/webpack/common";
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import "./settings.css";
|
||||
|
||||
import { ErrorBoundary } from "@vencord/types/components";
|
||||
import { Forms, Switch, Text } from "@vencord/types/webpack/common";
|
||||
import { ComponentType } from "react";
|
||||
import { Settings, useSettings } from "renderer/settings";
|
||||
import { isMac, isWindows } from "renderer/utils";
|
||||
|
||||
import { AutoStartToggle } from "./AutoStartToggle";
|
||||
import { DeveloperOptionsButton } from "./DeveloperOptions";
|
||||
import { DiscordBranchPicker } from "./DiscordBranchPicker";
|
||||
import { NotificationBadgeToggle } from "./NotificationBadgeToggle";
|
||||
import {
|
||||
|
@ -21,7 +23,6 @@ import {
|
|||
TrayIconPicker,
|
||||
TraySwitch
|
||||
} from "./TraySettings";
|
||||
import { VencordLocationPicker } from "./VencordLocationPicker";
|
||||
import { WindowsTransparencyControls } from "./WindowsTransparencyControls";
|
||||
|
||||
interface BooleanSetting {
|
||||
|
@ -66,11 +67,18 @@ const SettingsOptions: Record<string, Array<BooleanSetting | SettingsComponent>>
|
|||
defaultValue: false,
|
||||
disabled: () => Settings.store.customTitleBar ?? isWindows
|
||||
},
|
||||
{
|
||||
key: "enableSplashScreen",
|
||||
title: "Enable Splash Screen",
|
||||
description:
|
||||
"Shows a small splash screen while Vesktop is loading. Disabling this option will show the main window earlier while it's still loading.",
|
||||
defaultValue: true
|
||||
},
|
||||
{
|
||||
key: "splashTheming",
|
||||
title: "Splash theming",
|
||||
description: "Adapt the splash window colors to your custom theme",
|
||||
defaultValue: false
|
||||
defaultValue: true
|
||||
},
|
||||
WindowsTransparencyControls
|
||||
],
|
||||
|
@ -125,7 +133,7 @@ const SettingsOptions: Record<string, Array<BooleanSetting | SettingsComponent>>
|
|||
defaultValue: false
|
||||
}
|
||||
],
|
||||
"Vencord Location": [VencordLocationPicker]
|
||||
"Developer Options": [DeveloperOptionsButton]
|
||||
};
|
||||
|
||||
function SettingsSections() {
|
||||
|
@ -162,7 +170,8 @@ function SettingsSections() {
|
|||
return <>{sections}</>;
|
||||
}
|
||||
|
||||
export default function SettingsUi() {
|
||||
export default ErrorBoundary.wrap(
|
||||
function SettingsUI() {
|
||||
return (
|
||||
<Forms.FormSection>
|
||||
<Text variant="heading-lg/semibold" style={{ color: "var(--header-primary)" }} tag="h2">
|
||||
|
@ -172,4 +181,9 @@ export default function SettingsUi() {
|
|||
<SettingsSections />
|
||||
</Forms.FormSection>
|
||||
);
|
||||
},
|
||||
{
|
||||
message:
|
||||
"Failed to render the Vesktop Settings tab. If this issue persists, try to right click the Vesktop tray icon, then click 'Repair Vencord'. And make sure your Vesktop is up to date."
|
||||
}
|
||||
);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Margins } from "@vencord/types/utils";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.vcd-location-btns {
|
||||
.vcd-settings-button-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 0.5em;
|
||||
|
|
|
@ -1,15 +1,3 @@
|
|||
/* Download Desktop button in guilds list */
|
||||
[class^=listItem_]:has([data-list-item-id=guildsnav___app-download-button]),
|
||||
[class^=listItem_]:has(+ [class^=listItem_] [data-list-item-id=guildsnav___app-download-button]) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* FIXME: remove this once Discord fixes their css to not explode scrollbars on chromium >=121 */
|
||||
* {
|
||||
scrollbar-width: unset !important;
|
||||
scrollbar-color: unset !important;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import "./fixes.css";
|
||||
|
||||
import { isWindows, localStorage } from "./utils";
|
||||
import { localStorage } from "./utils";
|
||||
|
||||
// Make clicking Notifications focus the window
|
||||
const originalSetOnClick = Object.getOwnPropertyDescriptor(Notification.prototype, "onclick")!.set!;
|
||||
|
@ -22,14 +22,3 @@ Object.defineProperty(Notification.prototype, "onclick", {
|
|||
|
||||
// Hide "Download Discord Desktop now!!!!" banner
|
||||
localStorage.setItem("hideNag", "true");
|
||||
|
||||
// FIXME: Remove eventually.
|
||||
// Originally, Vencord always used a Windows user agent. This seems to cause captchas
|
||||
// Now, we use a platform specific UA - HOWEVER, discord FOR SOME REASON????? caches
|
||||
// device props in localStorage. This code fixes their cache to properly update the platform in SuperProps
|
||||
if (!isWindows)
|
||||
try {
|
||||
const deviceProperties = localStorage.getItem("deviceProperties");
|
||||
if (deviceProperties && JSON.parse(deviceProperties).os === "Windows")
|
||||
localStorage.removeItem("deviceProperties");
|
||||
} catch {}
|
||||
|
|
|
@ -1,41 +1,25 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import "./fixes";
|
||||
import "./themedSplash";
|
||||
import "./ipcCommands";
|
||||
import "./appBadge";
|
||||
import "./patches";
|
||||
import "./themedSplash";
|
||||
|
||||
console.log("read if cute :3");
|
||||
import "./fixes";
|
||||
import "./arrpc";
|
||||
|
||||
export * as Components from "./components";
|
||||
import { findByPropsLazy, onceReady } from "@vencord/types/webpack";
|
||||
import { Alerts, FluxDispatcher } from "@vencord/types/webpack/common";
|
||||
|
||||
import SettingsUi from "./components/settings/Settings";
|
||||
import { VesktopLogger } from "./logger";
|
||||
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;
|
||||
}
|
||||
VesktopLogger.log("read if cute :3");
|
||||
VesktopLogger.log("Vesktop v" + VesktopNative.app.getVersion());
|
||||
|
||||
const customSettingsSections = (
|
||||
Vencord.Plugins.plugins.Settings as any as { customSections: ((ID: Record<string, unknown>) => any)[] }
|
||||
|
@ -47,31 +31,3 @@ customSettingsSections.push(() => ({
|
|||
element: SettingsUi,
|
||||
className: "vc-vesktop-settings"
|
||||
}));
|
||||
|
||||
const arRPC = Vencord.Plugins.plugins["WebRichPresence (arRPC)"] as any as {
|
||||
handleEvent(e: MessageEvent): void;
|
||||
};
|
||||
|
||||
VesktopNative.arrpc.onActivity(async data => {
|
||||
if (!Settings.store.arRPC) return;
|
||||
|
||||
await onceReady;
|
||||
|
||||
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
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
49
src/renderer/ipcCommands.ts
Normal file
49
src/renderer/ipcCommands.ts
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2025 Vendicated and Vencord contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { SettingsRouter } from "@vencord/types/webpack/common";
|
||||
import { IpcCommands } from "shared/IpcEvents";
|
||||
|
||||
type IpcCommandHandler = (data: any) => any;
|
||||
|
||||
const handlers = new Map<string, IpcCommandHandler>();
|
||||
|
||||
function respond(nonce: string, ok: boolean, data: any) {
|
||||
VesktopNative.commands.respond({ nonce, ok, data });
|
||||
}
|
||||
|
||||
VesktopNative.commands.onCommand(async ({ message, nonce, data }) => {
|
||||
const handler = handlers.get(message);
|
||||
if (!handler) {
|
||||
return respond(nonce, false, `No handler for message: ${message}`);
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await handler(data);
|
||||
respond(nonce, true, result);
|
||||
} catch (err) {
|
||||
respond(nonce, false, String(err));
|
||||
}
|
||||
});
|
||||
|
||||
export function onIpcCommand(channel: string, handler: IpcCommandHandler) {
|
||||
if (handlers.has(channel)) {
|
||||
throw new Error(`Handler for message ${channel} already exists`);
|
||||
}
|
||||
|
||||
handlers.set(channel, handler);
|
||||
}
|
||||
|
||||
export function offIpcCommand(channel: string) {
|
||||
handlers.delete(channel);
|
||||
}
|
||||
|
||||
/* Generic Handlers */
|
||||
|
||||
onIpcCommand(IpcCommands.NAVIGATE_SETTINGS, () => {
|
||||
SettingsRouter.open("My Account");
|
||||
});
|
||||
onIpcCommand(IpcCommands.GET_LANGUAGES, () => navigator.languages);
|
9
src/renderer/logger.ts
Normal file
9
src/renderer/logger.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2025 Vendicated and Vencord contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Logger } from "@vencord/types/utils";
|
||||
|
||||
export const VesktopLogger = new Logger("Vesktop", "#d3869b");
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { addPatch } from "./shared";
|
||||
|
|
19
src/renderer/patches/hideDownloadAppsButton.ts
Normal file
19
src/renderer/patches/hideDownloadAppsButton.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2025 Vendicated and Vencord contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { addPatch } from "./shared";
|
||||
|
||||
addPatch({
|
||||
patches: [
|
||||
{
|
||||
find: '"app-download-button"',
|
||||
replacement: {
|
||||
match: /return(?=.{0,50}id:"app-download-button")/,
|
||||
replace: "return null;return"
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { addPatch } from "./shared";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { addPatch } from "./shared";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
// TODO: Possibly auto generate glob if we have more patches in the future
|
||||
|
@ -13,3 +13,6 @@ import "./screenShareFixes";
|
|||
import "./spellCheck";
|
||||
import "./windowsTitleBar";
|
||||
import "./tray";
|
||||
import "./streamerMode";
|
||||
import "./nativeFocus";
|
||||
import "./hideDownloadAppsButton";
|
||||
|
|
23
src/renderer/patches/nativeFocus.tsx
Normal file
23
src/renderer/patches/nativeFocus.tsx
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2025 Vendicated and Vencord contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { addPatch } from "./shared";
|
||||
|
||||
addPatch({
|
||||
patches: [
|
||||
{
|
||||
find: ".DEEP_LINK]:{",
|
||||
replacement: [
|
||||
{
|
||||
// TODO: Fix eslint rule
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
match: /(?<=\.DEEP_LINK.{0,200}?)\i\.\i\.focus\(\)/,
|
||||
replace: "VesktopNative.win.focus()"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
});
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Settings } from "renderer/settings";
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Logger } from "@vencord/types/utils";
|
||||
import { currentSettings } from "renderer/components/ScreenSharePicker";
|
||||
import { State } from "renderer/settings";
|
||||
import { isLinux } from "renderer/utils";
|
||||
|
||||
const logger = new Logger("VesktopStreamFixes");
|
||||
|
@ -27,8 +28,8 @@ if (isLinux) {
|
|||
const stream = await original.call(this, opts);
|
||||
const id = await getVirtmic();
|
||||
|
||||
const frameRate = Number(currentSettings?.fps);
|
||||
const height = Number(currentSettings?.resolution);
|
||||
const frameRate = Number(State.store.screenshareQuality?.frameRate ?? 30);
|
||||
const height = Number(State.store.screenshareQuality?.resolution ?? 720);
|
||||
const width = Math.round(height * (16 / 9));
|
||||
const track = stream.getVideoTracks()[0];
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Patch } from "@vencord/types/utils/types";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { addContextMenuPatch } from "@vencord/types/api/ContextMenu";
|
||||
|
|
21
src/renderer/patches/streamerMode.ts
Normal file
21
src/renderer/patches/streamerMode.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
|
||||
* Copyright (c) 2025 Vendicated and Vencord contributors
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { addPatch } from "./shared";
|
||||
|
||||
addPatch({
|
||||
patches: [
|
||||
{
|
||||
find: ".STREAMER_MODE_ENABLE,",
|
||||
replacement: {
|
||||
// remove if (platformEmbedded) check from streamer mode toggle
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
match: /if\(\i\.\i\)(?=return.{0,200}?"autoToggle")/g,
|
||||
replace: ""
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Settings } from "renderer/settings";
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { useEffect, useReducer } from "@vencord/types/webpack/common";
|
||||
import { SettingsStore } from "shared/utils/SettingsStore";
|
||||
|
||||
import { VesktopLogger } from "./logger";
|
||||
import { localStorage } from "./utils";
|
||||
|
||||
export const Settings = new SettingsStore(VesktopNative.settings.get());
|
||||
Settings.addGlobalChangeListener((o, p) => VesktopNative.settings.set(o, p));
|
||||
|
||||
|
@ -28,3 +31,38 @@ export function getValueAndOnChange(key: keyof typeof Settings.store) {
|
|||
onChange: (value: any) => (Settings.store[key] = value)
|
||||
};
|
||||
}
|
||||
|
||||
interface TState {
|
||||
screenshareQuality?: {
|
||||
resolution: string;
|
||||
frameRate: string;
|
||||
};
|
||||
}
|
||||
|
||||
const stateKey = "VesktopState";
|
||||
|
||||
const currentState: TState = (() => {
|
||||
const stored = localStorage.getItem(stateKey);
|
||||
if (!stored) return {};
|
||||
try {
|
||||
return JSON.parse(stored);
|
||||
} catch (e) {
|
||||
VesktopLogger.error("Failed to parse stored state", e);
|
||||
return {};
|
||||
}
|
||||
})();
|
||||
|
||||
export const State = new SettingsStore<TState>(currentState);
|
||||
State.addGlobalChangeListener((o, p) => localStorage.setItem(stateKey, JSON.stringify(o)));
|
||||
|
||||
export function useVesktopState() {
|
||||
const [, update] = useReducer(x => x + 1, 0);
|
||||
|
||||
useEffect(() => {
|
||||
State.addGlobalChangeListener(update);
|
||||
|
||||
return () => State.removeGlobalChangeListener(update);
|
||||
}, []);
|
||||
|
||||
return State.store;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { Settings } from "./settings";
|
||||
|
@ -10,15 +10,49 @@ function isValidColor(color: CSSStyleValue | undefined): color is CSSUnparsedVal
|
|||
return color instanceof CSSUnparsedValue && typeof color[0] === "string" && CSS.supports("color", color[0]);
|
||||
}
|
||||
|
||||
// https://gist.github.com/earthbound19/e7fe15fdf8ca3ef814750a61bc75b5ce
|
||||
function clamp(value: number, min: number, max: number) {
|
||||
return Math.max(Math.min(value, max), min);
|
||||
}
|
||||
const linearToGamma = (c: number) => (c >= 0.0031308 ? 1.055 * Math.pow(c, 1 / 2.4) - 0.055 : 12.92 * c);
|
||||
|
||||
function oklabToSRGB({ L, a, b }: { L: number; a: number; b: number }) {
|
||||
let l = L + a * +0.3963377774 + b * +0.2158037573;
|
||||
let m = L + a * -0.1055613458 + b * -0.0638541728;
|
||||
let s = L + a * -0.0894841775 + b * -1.291485548;
|
||||
l **= 3;
|
||||
m **= 3;
|
||||
s **= 3;
|
||||
let R = l * +4.0767416621 + m * -3.3077115913 + s * +0.2309699292;
|
||||
let G = l * -1.2684380046 + m * +2.6097574011 + s * -0.3413193965;
|
||||
let B = l * -0.0041960863 + m * -0.7034186147 + s * +1.707614701;
|
||||
R = 255 * linearToGamma(R);
|
||||
G = 255 * linearToGamma(G);
|
||||
B = 255 * linearToGamma(B);
|
||||
R = Math.round(clamp(R, 0, 255));
|
||||
G = Math.round(clamp(G, 0, 255));
|
||||
B = Math.round(clamp(B, 0, 255));
|
||||
|
||||
return `rgb(${R}, ${G}, ${B})`;
|
||||
}
|
||||
|
||||
function resolveColor(color: string) {
|
||||
const span = document.createElement("span");
|
||||
span.style.color = color;
|
||||
span.style.display = "none";
|
||||
|
||||
document.body.append(span);
|
||||
const rgbColor = getComputedStyle(span).color;
|
||||
let rgbColor = getComputedStyle(span).color;
|
||||
span.remove();
|
||||
|
||||
if (rgbColor.startsWith("oklab(")) {
|
||||
// scam
|
||||
const [_, L, a, b] = rgbColor.match(/oklab\((.+?)[, ]+(.+?)[, ]+(.+?)\)/) ?? [];
|
||||
if (L && a && b) {
|
||||
rgbColor = oklabToSRGB({ L: parseFloat(L), a: parseFloat(a), b: parseFloat(b) });
|
||||
}
|
||||
}
|
||||
|
||||
return rgbColor;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
// Discord deletes this from the window so we need to capture it in a variable
|
||||
export const { localStorage } = window;
|
||||
|
||||
export const isFirstRun = (() => {
|
||||
|
@ -18,3 +19,26 @@ const { platform } = navigator;
|
|||
export const isWindows = platform.startsWith("Win");
|
||||
export const isMac = platform.startsWith("Mac");
|
||||
export const isLinux = platform.startsWith("Linux");
|
||||
|
||||
type ClassNameFactoryArg = string | string[] | Record<string, unknown> | false | null | undefined | 0 | "";
|
||||
/**
|
||||
* @param prefix The prefix to add to each class, defaults to `""`
|
||||
* @returns A classname generator function
|
||||
* @example
|
||||
* const cl = classNameFactory("plugin-");
|
||||
*
|
||||
* cl("base", ["item", "editable"], { selected: null, disabled: true })
|
||||
* // => "plugin-base plugin-item plugin-editable plugin-disabled"
|
||||
*/
|
||||
export const classNameFactory =
|
||||
(prefix: string = "") =>
|
||||
(...args: ClassNameFactoryArg[]) => {
|
||||
const classNames = new Set<string>();
|
||||
for (const arg of args) {
|
||||
if (arg && typeof arg === "string") classNames.add(arg);
|
||||
else if (Array.isArray(arg)) arg.forEach(name => classNames.add(name));
|
||||
else if (arg && typeof arg === "object")
|
||||
Object.entries(arg).forEach(([name, value]) => value && classNames.add(name));
|
||||
}
|
||||
return Array.from(classNames, name => prefix + name).join(" ");
|
||||
};
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export const enum IpcEvents {
|
||||
|
@ -62,5 +62,17 @@ export const enum IpcEvents {
|
|||
GET_SYSTEM_ACCENT_COLOR = "VCD_GET_ACCENT_COLOR",
|
||||
SELECT_TRAY_ICON = "VCD_SELECT_TRAY_ICON",
|
||||
ADD_BADGE_TO_ICON = "VCD_ADD_BADGE_TO_ICON",
|
||||
GET_ICON_WITH_BADGE = "VCD_GET_ICON_WITH_BADGE"
|
||||
GET_ICON_WITH_BADGE = "VCD_GET_ICON_WITH_BADGE",
|
||||
DEBUG_LAUNCH_GPU = "VCD_DEBUG_LAUNCH_GPU",
|
||||
DEBUG_LAUNCH_WEBRTC_INTERNALS = "VCD_DEBUG_LAUNCH_WEBRTC",
|
||||
|
||||
IPC_COMMAND = "VCD_IPC_COMMAND"
|
||||
}
|
||||
|
||||
export const enum IpcCommands {
|
||||
RPC_ACTIVITY = "rpc:activity",
|
||||
RPC_INVITE = "rpc:invite",
|
||||
RPC_DEEP_LINK = "rpc:link",
|
||||
NAVIGATE_SETTINGS = "navigate:settings",
|
||||
GET_LANGUAGES = "navigator.languages"
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { BrowserWindowConstructorOptions } from "electron";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { DATA_DIR } from "main/constants";
|
||||
|
|
5
src/shared/settings.d.ts
vendored
5
src/shared/settings.d.ts
vendored
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { Rectangle } from "electron";
|
||||
|
@ -30,6 +30,7 @@ export interface Settings {
|
|||
clickTrayToShowHide?: boolean;
|
||||
customTitleBar?: boolean;
|
||||
|
||||
enableSplashScreen?: boolean;
|
||||
splashTheming?: boolean;
|
||||
splashColor?: string;
|
||||
splashBackground?: string;
|
||||
|
@ -55,7 +56,7 @@ export interface State {
|
|||
maximized?: boolean;
|
||||
minimized?: boolean;
|
||||
windowBounds?: Rectangle;
|
||||
displayid: int;
|
||||
displayId: int;
|
||||
|
||||
firstLaunch?: boolean;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { LiteralUnion } from "type-fest";
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export function isTruthy<T>(item: T): item is Exclude<T, 0 | "" | false | null | undefined> {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* 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
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
export function sleep(ms: number): Promise<void> {
|
||||
|
|
Loading…
Add table
Reference in a new issue