Merge branch 'main' into main
This commit is contained in:
commit
f61cf34215
10 changed files with 1105 additions and 605 deletions
24
.github/ISSUE_TEMPLATE/bug_report.md
vendored
24
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -7,25 +7,38 @@ assignees: ''
|
|||
|
||||
---
|
||||
|
||||
<!--
|
||||
|
||||
Please do not open issues for the following things. We cannot help you with them:
|
||||
- "Vesktop.app is damaged" on MacOs ~ Fake issue created by crApple. Google how to fix it https://google.it/search?q=fix+app+is+damaged
|
||||
- Screenshare does not start / is black ~ This is an issue with your desktop environment, specifically its xdg-desktop-portal
|
||||
- Purely graphical glitches, like flickering, scaling issues, short whitescreens, etc ~ These are most likely issues with your GPU. try to disable hardware acceleration
|
||||
- Vencord related issues ~ This is the Vesktop repo, not Vencord
|
||||
- Getting logged out after restart ~ If you use DevTools, make sure you have NoDevtoolsWarning enabled. Otherwise try reinstalling Vesktop
|
||||
|
||||
-->
|
||||
|
||||
**Describe the bug**
|
||||
|
||||
A clear and concise description of what the bug is.
|
||||
<!-- A clear and concise description of what the bug is. -->
|
||||
|
||||
**To Reproduce**
|
||||
|
||||
<!--
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
-->
|
||||
|
||||
**Expected behavior**
|
||||
|
||||
A clear and concise description of what you expected to happen.
|
||||
<!-- A clear and concise description of what you expected to happen. -->
|
||||
|
||||
**Screenshots**
|
||||
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
<!-- If applicable, add screenshots to help explain your problem. -->
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS/Distro: [e.g. Windows / Fedora Linux / MacOs]
|
||||
|
@ -34,11 +47,12 @@ If applicable, add screenshots to help explain your problem.
|
|||
|
||||
**Command line output**
|
||||
|
||||
Run vesktop from the command line. Include the relevant command line output here:
|
||||
<!-- Run vesktop from the command line. Include the relevant command line output here: -->
|
||||
|
||||
```
|
||||
paste inside these backticks
|
||||
```
|
||||
|
||||
**Additional context**
|
||||
|
||||
Add any other context about the problem here.
|
||||
<!-- Add any other context about the problem here. -->
|
||||
|
|
|
@ -162,11 +162,7 @@
|
|||
<control>voice</control>
|
||||
<display_length compare="ge">760</display_length>
|
||||
<display_length compare="le">1200</display_length>
|
||||
<internet>always</internet>
|
||||
</recommends>
|
||||
<supports>
|
||||
<internet>always</internet>
|
||||
</supports>
|
||||
<content_rating type="oars-1.1">
|
||||
<content_attribute id="social-chat">intense</content_attribute>
|
||||
<content_attribute id="social-audio">intense</content_attribute>
|
||||
|
@ -180,4 +176,4 @@
|
|||
<keyword>Privacy</keyword>
|
||||
<keyword>Mod</keyword>
|
||||
</keywords>
|
||||
</component>
|
||||
</component>
|
||||
|
|
32
package.json
32
package.json
|
@ -31,29 +31,29 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@fal-works/esbuild-plugin-global-externals": "^2.1.2",
|
||||
"@types/node": "^20.11.2",
|
||||
"@types/react": "^18.2.48",
|
||||
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
||||
"@typescript-eslint/parser": "^6.19.0",
|
||||
"@types/node": "^20.11.26",
|
||||
"@types/react": "^18.2.65",
|
||||
"@typescript-eslint/eslint-plugin": "^7.2.0",
|
||||
"@typescript-eslint/parser": "^7.2.0",
|
||||
"@vencord/types": "^0.1.2",
|
||||
"dotenv": "^16.3.1",
|
||||
"electron": "^28.1.3",
|
||||
"electron-builder": "^24.9.1",
|
||||
"esbuild": "^0.19.11",
|
||||
"eslint": "^8.56.0",
|
||||
"dotenv": "^16.4.5",
|
||||
"electron": "^29.1.1",
|
||||
"electron-builder": "^24.13.3",
|
||||
"esbuild": "^0.20.1",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
"eslint-plugin-license-header": "^0.6.0",
|
||||
"eslint-plugin-path-alias": "^1.0.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-simple-import-sort": "^10.0.0",
|
||||
"eslint-plugin-unused-imports": "^3.0.0",
|
||||
"prettier": "^3.2.2",
|
||||
"eslint-plugin-simple-import-sort": "^12.0.0",
|
||||
"eslint-plugin-unused-imports": "^3.1.0",
|
||||
"prettier": "^3.2.5",
|
||||
"source-map-support": "^0.5.21",
|
||||
"tsx": "^4.7.0",
|
||||
"type-fest": "^4.9.0",
|
||||
"typescript": "^5.3.3",
|
||||
"xml-formatter": "^3.6.0"
|
||||
"tsx": "^4.7.1",
|
||||
"type-fest": "^4.12.0",
|
||||
"typescript": "^5.4.2",
|
||||
"xml-formatter": "^3.6.2"
|
||||
},
|
||||
"packageManager": "pnpm@8.11.0",
|
||||
"engines": {
|
||||
|
|
1531
pnpm-lock.yaml
1531
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -48,14 +48,14 @@ export const DEFAULT_HEIGHT = 720;
|
|||
|
||||
export const DISCORD_HOSTNAMES = ["discord.com", "canary.discord.com", "ptb.discord.com"];
|
||||
|
||||
const UserAgents = {
|
||||
darwin: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
||||
linux: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
|
||||
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",
|
||||
windows:
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
|
||||
};
|
||||
|
||||
export const UserAgent = UserAgents[process.platform] || UserAgents.windows;
|
||||
export const BrowserUserAgent = BrowserUserAgents[process.platform] || BrowserUserAgents.windows;
|
||||
|
||||
export const enum MessageBoxChoice {
|
||||
Default,
|
||||
|
|
|
@ -25,13 +25,13 @@ import { ICON_PATH } from "../shared/paths";
|
|||
import { createAboutWindow } from "./about";
|
||||
import { initArRPC } from "./arrpc";
|
||||
import {
|
||||
BrowserUserAgent,
|
||||
DATA_DIR,
|
||||
DEFAULT_HEIGHT,
|
||||
DEFAULT_WIDTH,
|
||||
MessageBoxChoice,
|
||||
MIN_HEIGHT,
|
||||
MIN_WIDTH,
|
||||
UserAgent,
|
||||
VENCORD_FILES_DIR
|
||||
} from "./constants";
|
||||
import { Settings, State, VencordSettings } from "./settings";
|
||||
|
@ -433,7 +433,7 @@ function createMainWindow() {
|
|||
initSettingsListeners(win);
|
||||
initSpellCheck(win);
|
||||
|
||||
win.webContents.setUserAgent(UserAgent);
|
||||
win.webContents.setUserAgent(BrowserUserAgent);
|
||||
|
||||
const subdomain =
|
||||
Settings.store.discordBranch === "canary" || Settings.store.discordBranch === "ptb"
|
||||
|
|
|
@ -5,41 +5,54 @@
|
|||
*/
|
||||
|
||||
import { createWriteStream } from "fs";
|
||||
import type { IncomingMessage } from "http";
|
||||
import { get, RequestOptions } from "https";
|
||||
import { finished } from "stream/promises";
|
||||
import { Readable } from "stream";
|
||||
import { pipeline } from "stream/promises";
|
||||
import { setTimeout } from "timers/promises";
|
||||
|
||||
export async function downloadFile(url: string, file: string, options: RequestOptions = {}) {
|
||||
const res = await simpleReq(url, options);
|
||||
await finished(
|
||||
res.pipe(
|
||||
createWriteStream(file, {
|
||||
autoClose: true
|
||||
})
|
||||
)
|
||||
interface FetchieOptions {
|
||||
retryOnNetworkError?: boolean;
|
||||
}
|
||||
|
||||
export async function downloadFile(url: string, file: string, options: RequestInit = {}, fetchieOpts?: FetchieOptions) {
|
||||
const res = await fetchie(url, options, fetchieOpts);
|
||||
await pipeline(
|
||||
// @ts-expect-error odd type error
|
||||
Readable.fromWeb(res.body!),
|
||||
createWriteStream(file, {
|
||||
autoClose: true
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export function simpleReq(url: string, options: RequestOptions = {}) {
|
||||
return new Promise<IncomingMessage>((resolve, reject) => {
|
||||
get(url, options, res => {
|
||||
const { statusCode, statusMessage, headers } = res;
|
||||
if (statusCode! >= 400) return void reject(`${statusCode}: ${statusMessage} - ${url}`);
|
||||
if (statusCode! >= 300) return simpleReq(headers.location!, options).then(resolve).catch(reject);
|
||||
const ONE_MINUTE_MS = 1000 * 60;
|
||||
|
||||
resolve(res);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function simpleGet(url: string, options: RequestOptions = {}) {
|
||||
const res = await simpleReq(url, options);
|
||||
|
||||
return new Promise<Buffer>((resolve, reject) => {
|
||||
const chunks = [] as Buffer[];
|
||||
|
||||
res.once("error", reject);
|
||||
res.on("data", chunk => chunks.push(chunk));
|
||||
res.once("end", () => resolve(Buffer.concat(chunks)));
|
||||
});
|
||||
export async function fetchie(url: string, options?: RequestInit, { retryOnNetworkError }: FetchieOptions = {}) {
|
||||
let res: Response | undefined;
|
||||
|
||||
try {
|
||||
res = await fetch(url, options);
|
||||
} catch (err) {
|
||||
if (retryOnNetworkError) {
|
||||
console.error("Failed to fetch", url + ".", "Gonna retry with backoff.");
|
||||
|
||||
for (let tries = 0, delayMs = 500; tries < 20; tries++, delayMs = Math.min(2 * delayMs, ONE_MINUTE_MS)) {
|
||||
await setTimeout(delayMs);
|
||||
try {
|
||||
res = await fetch(url, options);
|
||||
break;
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
|
||||
if (!res) throw new Error(`Failed to fetch ${url}\n${err}`);
|
||||
}
|
||||
|
||||
if (res.ok) return res;
|
||||
|
||||
let msg = `Got non-OK response for ${url}: ${res.status} ${res.statusText}`;
|
||||
|
||||
const reason = await res.text().catch(() => "");
|
||||
if (reason) msg += `\n${reason}`;
|
||||
|
||||
throw new Error(msg);
|
||||
}
|
||||
|
|
|
@ -5,11 +5,10 @@
|
|||
*/
|
||||
|
||||
import { existsSync, mkdirSync } from "fs";
|
||||
import type { RequestOptions } from "https";
|
||||
import { join } from "path";
|
||||
|
||||
import { USER_AGENT, VENCORD_FILES_DIR } from "../constants";
|
||||
import { downloadFile, simpleGet } from "./http";
|
||||
import { downloadFile, fetchie } from "./http";
|
||||
|
||||
const API_BASE = "https://api.github.com";
|
||||
|
||||
|
@ -31,27 +30,29 @@ export interface ReleaseData {
|
|||
}
|
||||
|
||||
export async function githubGet(endpoint: string) {
|
||||
const opts: RequestOptions = {
|
||||
const opts: RequestInit = {
|
||||
headers: {
|
||||
Accept: "application/vnd.github+json",
|
||||
"User-Agent": USER_AGENT
|
||||
}
|
||||
};
|
||||
|
||||
if (process.env.GITHUB_TOKEN) opts.headers!.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
|
||||
if (process.env.GITHUB_TOKEN) (opts.headers! as any).Authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
|
||||
|
||||
return simpleGet(API_BASE + endpoint, opts);
|
||||
return fetchie(API_BASE + endpoint, opts, { retryOnNetworkError: true });
|
||||
}
|
||||
|
||||
export async function downloadVencordFiles() {
|
||||
const release = await githubGet("/repos/Vendicated/Vencord/releases/latest");
|
||||
|
||||
const { assets } = JSON.parse(release.toString("utf-8")) as ReleaseData;
|
||||
const { assets }: ReleaseData = await release.json();
|
||||
|
||||
await Promise.all(
|
||||
assets
|
||||
.filter(({ name }) => FILES_TO_DOWNLOAD.some(f => name.startsWith(f)))
|
||||
.map(({ name, browser_download_url }) => downloadFile(browser_download_url, join(VENCORD_FILES_DIR, name)))
|
||||
.map(({ name, browser_download_url }) =>
|
||||
downloadFile(browser_download_url, join(VENCORD_FILES_DIR, name), {}, { retryOnNetworkError: true })
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import { addContextMenuPatch } from "@vencord/types/api/ContextMenu";
|
||||
import { findStoreLazy } from "@vencord/types/webpack";
|
||||
import { ContextMenu, FluxDispatcher, Menu } from "@vencord/types/webpack/common";
|
||||
import { FluxDispatcher, Menu, useStateFromStores } from "@vencord/types/webpack/common";
|
||||
|
||||
import { addPatch } from "./shared";
|
||||
|
||||
|
@ -46,7 +46,8 @@ addPatch({
|
|||
}
|
||||
});
|
||||
|
||||
addContextMenuPatch("textarea-context", children => () => {
|
||||
addContextMenuPatch("textarea-context", children => {
|
||||
const spellCheckEnabled = useStateFromStores([SpellCheckStore], () => SpellCheckStore.isEnabled());
|
||||
const hasCorrections = Boolean(word && corrections?.length);
|
||||
|
||||
children.push(
|
||||
|
@ -71,11 +72,9 @@ addContextMenuPatch("textarea-context", children => () => {
|
|||
<Menu.MenuCheckboxItem
|
||||
id="vcd-spellcheck-enabled"
|
||||
label="Enable Spellcheck"
|
||||
checked={SpellCheckStore.isEnabled()}
|
||||
checked={spellCheckEnabled}
|
||||
action={() => {
|
||||
FluxDispatcher.dispatch({ type: "SPELLCHECK_TOGGLE" });
|
||||
// Haven't found a good way to update state, so just close for now 🤷♀️
|
||||
ContextMenu.close();
|
||||
}}
|
||||
/>
|
||||
</Menu.MenuGroup>
|
||||
|
|
|
@ -81,7 +81,7 @@ export async function checkUpdates() {
|
|||
|
||||
try {
|
||||
const raw = await githubGet("/repos/Vencord/Vesktop/releases/latest");
|
||||
const data = JSON.parse(raw.toString("utf-8")) as ReleaseData;
|
||||
const data: ReleaseData = await raw.json();
|
||||
|
||||
const oldVersion = app.getVersion();
|
||||
const newVersion = data.tag_name.replace(/^v/, "");
|
||||
|
|
Reference in a new issue