Merge branch 'main' into isMaximized-in-renderer

This commit is contained in:
Sqaaakoi 2024-03-27 09:19:52 +13:00 committed by GitHub
commit 41787042cc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 1121 additions and 605 deletions

View file

@ -28,6 +28,24 @@
</screenshot>
</screenshots>
<releases>
<release version="1.5.1" date="2024-03-12" type="stable">
<url>https://github.com/Vencord/Vesktop/releases/tag/v1.5.1</url>
<description>
<p>New Features</p>
<ul>
<li>Added categories to Vesktop settings to reduce visual clutter by @justin13888</li>
<li>Added support for Vencord's transparent window options</li>
</ul>
<p>Fixes</p>
<ul>
<li>Fixed ugly error popups when starting Vesktop without working internet connection</li>
<li>Fixed popout title bars on Windows</li>
<li>Fixed spellcheck entries</li>
<li>Fixed screenshare audio using microphone on debian, by @Curve</li>
<li>Fixed a bug where autostart on Linux won't preserve command line flags</li>
</ul>
</description>
</release>
<release version="1.5.0" date="2024-01-16" type="stable">
<url>https://github.com/Vencord/Vesktop/releases/tag/v1.5.0</url>
<description>

View file

@ -1,6 +1,6 @@
{
"name": "vesktop",
"version": "1.5.0",
"version": "1.5.1",
"private": true,
"description": "",
"keywords": [],
@ -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": {

File diff suppressed because it is too large Load diff

View file

@ -8,4 +8,4 @@ import "./utils/dotenv";
import { spawnNodeModuleBin } from "./utils/spawn.mjs";
spawnNodeModuleBin("electron", [".", ...(process.env.ELECTRON_LAUNCH_FLAGS?.split(" ") ?? [])]);
spawnNodeModuleBin("electron", [process.cwd(), ...(process.env.ELECTRON_LAUNCH_FLAGS?.split(" ") ?? [])]);

View file

@ -5,7 +5,7 @@
*/
import { app } from "electron";
import { existsSync, mkdirSync, rmSync, writeFileSync } from "fs";
import { existsSync, mkdirSync, renameSync, rmSync, writeFileSync } from "fs";
import { join } from "path";
interface AutoStart {
@ -17,7 +17,16 @@ interface AutoStart {
function makeAutoStartLinux(): AutoStart {
const configDir = process.env.XDG_CONFIG_HOME || join(process.env.HOME!, ".config");
const dir = join(configDir, "autostart");
const file = join(dir, "vencord.desktop");
const file = join(dir, "vesktop.desktop");
// IM STUPID
const legacyName = join(dir, "vencord.desktop");
if (existsSync(legacyName)) renameSync(legacyName, file);
// "Quoting must be done by enclosing the argument between double quotes and escaping the double quote character,
// backtick character ("`"), dollar sign ("$") and backslash character ("\") by preceding it with an additional backslash character"
// https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables
const commandLine = process.argv.map(arg => '"' + arg.replace(/["$`\\]/g, "\\$&") + '"').join(" ");
return {
isEnabled: () => existsSync(file),
@ -25,12 +34,11 @@ function makeAutoStartLinux(): AutoStart {
const desktopFile = `
[Desktop Entry]
Type=Application
Version=1.0
Name=Vencord
Comment=Vencord autostart script
Exec=${process.execPath}
Terminal=false
Name=Vesktop
Comment=Vesktop autostart script
Exec=${commandLine}
StartupNotify=false
Terminal=false
`.trim();
mkdirSync(dir, { recursive: true });

View file

@ -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,

View file

@ -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";
@ -435,7 +435,7 @@ function createMainWindow() {
initSpellCheck(win);
initMaximizedHook(win);
win.webContents.setUserAgent(UserAgent);
win.webContents.setUserAgent(BrowserUserAgent);
const subdomain =
Settings.store.discordBranch === "canary" || Settings.store.discordBranch === "ptb"

View file

@ -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(
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 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 {}
}
}
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)));
});
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);
}

View file

@ -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 })
)
);
}

View file

@ -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>

View file

@ -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/, "");