14 Commits

Author SHA1 Message Date
Vendicated
a12ba017bc bump to 0.1.8 2023-04-15 20:24:09 +02:00
Vendicated
7a2161d746 Make IS_DEV force new instance 2023-04-15 20:23:47 +02:00
Vendicated
d0e7a319d6 Spoof UserAgent as browser. Fixes VCs????? 2023-04-15 20:13:18 +02:00
Vendicated
4afafa5038 bump 2023-04-15 12:38:17 +02:00
Ryan Cao
583680d311 feat: reuse built-in menus in system menubar (#12)
* fix: add edit menu on macOS to allow clipboard actions

* feat: reuse more built-in menus

* re-add zoom shortcut fix

---------

Co-authored-by: V <vendicated@riseup.net>
2023-04-15 10:37:52 +00:00
Vendicated
70dd38f79d make spellcheck use all system locales 2023-04-14 04:05:56 +02:00
Sofia Lima
9120d05efc fix makepkg in AUR workflow again (#11) 2023-04-11 05:43:12 +02:00
Vendicated
3a820b458f Fix ssh shenanigans 2023-04-11 02:12:10 +02:00
Sofia Lima
47f3b7fc89 fix AUR workflow (#10) 2023-04-11 01:44:15 +02:00
Vendicated
838a3c78dd Bump to 0.1.6 2023-04-10 22:54:09 +02:00
V
8d51cd5029 Add basic update notifications (#9) 2023-04-10 22:53:44 +02:00
Vendicated
bfb9af05b0 Fix Settings not persisting, ooop 2023-04-10 22:30:39 +02:00
Vendicated
897df3a5d4 Add support for (optional) GITHUB_TOKEN env variable 2023-04-10 22:05:21 +02:00
Vendicated
d1296d1708 Windows: Fix taskbar icon getting removed on update 2023-04-10 21:37:14 +02:00
28 changed files with 468 additions and 104 deletions

6
.env.example Normal file
View File

@@ -0,0 +1,6 @@
# githubs api has a rate limit of 60/h if not authorised.
# you may quickly hit that and get rate limited. To counteract this, you can provide a github token
# here and it will be used. To do so, create a token at the following links and just leave
# all permissions at the defaults (public repos read only, 0 permissions):
# https://github.com/settings/personal-access-tokens/new
GITHUB_TOKEN=

View File

@@ -30,13 +30,15 @@ jobs:
- name: Update AUR package
if: ${{ matrix.os == 'ubuntu-latest' }}
run: |
sudo apt install makepkg
mkdir -p -m 700 ~/.ssh
echo $SSH_KEY > ~/.ssh/aur
echo $SSH_PUB_KEY > ~/.ssh/aur.pub
chmod 600 ~/.ssh/*
export GIT_SSH_COMMAND="ssh -i ~/.ssh/aur"
./scripts/aur_bump.sh
sudo ./scripts/ci/install_makepkg.sh
./scripts/ci/aur_bump.sh
env:
SSH_KEY: ${{ secrets.AUR_SSH_KEY }}
SSH_PUB_KEY: ${{ secrets.AUR_SSH_PUB_KEY }}

1
.gitignore vendored
View File

@@ -1,2 +1,3 @@
dist
node_modules
.env

View File

@@ -1,6 +1,6 @@
{
"name": "VencordDesktop",
"version": "0.1.5",
"version": "0.1.8",
"private": true,
"description": "",
"keywords": [],
@@ -10,13 +10,14 @@
"main": "dist/js/main.js",
"scripts": {
"build": "tsx scripts/build/build.mts",
"build:dev": "pnpm build --dev",
"package": "pnpm build && electron-builder",
"package:dir": "pnpm build && electron-builder --dir",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx,.mts,.mjs",
"lint:fix": "pnpm lint --fix",
"start": "pnpm build && electron .",
"start:dev": "pnpm build --dev && electron .",
"start:watch": "tsx scripts/startWatch.mts",
"start:dev": "pnpm build:dev && electron .",
"start:watch": "pnpm build:dev && tsx scripts/startWatch.mts",
"test": "pnpm lint && pnpm testTypes",
"testTypes": "tsc --noEmit",
"watch": "pnpm build --watch"
@@ -26,6 +27,7 @@
"@types/react": "^18.0.33",
"@typescript-eslint/eslint-plugin": "^5.57.1",
"@typescript-eslint/parser": "^5.57.1",
"dotenv": "^16.0.3",
"electron": "^23.2.0",
"electron-builder": "^23.6.0",
"esbuild": "^0.17.14",
@@ -79,7 +81,6 @@
"category": "Network"
},
"nsis": {
"allowToChangeInstallationDirectory": true,
"include": "build/installer.nsh",
"oneClick": false
}

8
pnpm-lock.yaml generated
View File

@@ -13,6 +13,9 @@ devDependencies:
'@typescript-eslint/parser':
specifier: ^5.57.1
version: 5.57.1(eslint@8.38.0)(typescript@5.0.2)
dotenv:
specifier: ^16.0.3
version: 16.0.3
electron:
specifier: ^23.2.0
version: 23.2.0
@@ -1390,6 +1393,11 @@ packages:
resolution: {integrity: sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==}
dev: true
/dotenv@16.0.3:
resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==}
engines: {node: '>=12'}
dev: true
/dotenv@9.0.2:
resolution: {integrity: sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==}
engines: {node: '>=10'}

View File

@@ -1,3 +1,9 @@
/*
* SPDX-License-Identifier: GPL-3.0
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
import { BuildContext, BuildOptions, context } from "esbuild";
const isDev = process.argv.includes("--dev");
@@ -36,6 +42,11 @@ await Promise.all([
entryPoints: ["src/preload/index.ts"],
outfile: "dist/js/preload.js"
}),
createContext({
...NodeCommonOpts,
entryPoints: ["src/updater/preload.ts"],
outfile: "dist/js/updaterPreload.js"
}),
createContext({
...CommonOpts,
globalName: "VencordDesktop",
@@ -55,8 +66,10 @@ const watch = process.argv.includes("--watch");
if (watch) {
await Promise.all(contexts.map(ctx => ctx.watch()));
} else {
await Promise.all(contexts.map(async ctx => {
await ctx.rebuild();
await ctx.dispose();
}));
await Promise.all(
contexts.map(async ctx => {
await ctx.rebuild();
await ctx.dispose();
})
);
}

View File

@@ -1,3 +1,9 @@
/*
* SPDX-License-Identifier: GPL-3.0
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
export const VencordFragment = /* #__PURE__*/ Symbol.for("react.fragment");
export let VencordCreateElement =
(...args) => (VencordCreateElement = Vencord.Webpack.Common.React.createElement)(...args);
export let VencordCreateElement = (...args) =>
(VencordCreateElement = Vencord.Webpack.Common.React.createElement)(...args);

13
scripts/ci/install_makepkg.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/bin/sh
set -e
for i in \
"makepkg_6.0.2-3_amd64.deb" \
"libalpm13_13.0.2-3_amd64.deb" \
"pacman-package-manager_6.0.2-3_amd64.deb"; do
wget -O/tmp/$i https://fr.archive.ubuntu.com/ubuntu/pool/universe/p/pacman-package-manager/$i
dpkg -i /tmp/$i || true
done
apt-get -f install -oDpkg::Use-Pty=0 -qq

11
scripts/start.ts Normal file
View File

@@ -0,0 +1,11 @@
/*
* SPDX-License-Identifier: GPL-3.0
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
import "./utils/dotenv";
import { spawnNodeModuleBin } from "./utils/spawn.mjs";
spawnNodeModuleBin("electron", ["."]);

View File

@@ -1,15 +1,10 @@
import { spawn as cpSpawn, SpawnOptions } from "child_process";
import { join } from "path";
/*
* SPDX-License-Identifier: GPL-3.0
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
const EXT = process.platform === "win32" ? ".cmd" : "";
import "./start";
const OPTS: SpawnOptions = {
stdio: "inherit",
};
function spawn(bin: string, args: string[]) {
cpSpawn(join("node_modules", ".bin", bin + EXT), args, OPTS);
}
spawn("tsx", ["scripts/build/build.mts", "--", "--watch", "--dev"]);
spawn("electron", ["."]);
import { spawnNodeModuleBin } from "./utils/spawn.mjs";
spawnNodeModuleBin("tsx", ["scripts/build/build.mts", "--", "--watch", "--dev"]);

9
scripts/utils/dotenv.ts Normal file
View File

@@ -0,0 +1,9 @@
/*
* SPDX-License-Identifier: GPL-3.0
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
import { config } from "dotenv";
config();

18
scripts/utils/spawn.mts Normal file
View File

@@ -0,0 +1,18 @@
/*
* SPDX-License-Identifier: GPL-3.0
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
import { spawn as spaaawn, SpawnOptions } from "child_process";
import { join } from "path";
const EXT = process.platform === "win32" ? ".cmd" : "";
const OPTS: SpawnOptions = {
stdio: "inherit"
};
export function spawnNodeModuleBin(bin: string, args: string[]) {
spaaawn(join("node_modules", ".bin", bin + EXT), args, OPTS);
}

View File

@@ -8,6 +8,7 @@ import "./ipc";
import { app, BrowserWindow } from "electron";
import { join } from "path";
import { checkUpdates } from "updater/main";
import { ICON_PATH } from "../shared/paths";
import { once } from "../shared/utils/once";
@@ -27,12 +28,10 @@ const runVencordMain = once(() => require(join(VENCORD_FILES_DIR, "vencordDeskto
let mainWin: BrowserWindow | null = null;
if (!app.requestSingleInstanceLock()) {
console.log("Vencord Desktop is already running. Quitting...");
app.quit();
} else {
app.on("second-instance", () => {
if (mainWin) {
function init() {
app.on("second-instance", (_event, _cmdLine, _cwd, data: any) => {
if (data.IS_DEV) app.quit();
else if (mainWin) {
if (mainWin.isMinimized()) mainWin.restore();
if (!mainWin.isVisible()) mainWin.show();
mainWin.focus();
@@ -40,6 +39,7 @@ if (!app.requestSingleInstanceLock()) {
});
app.whenReady().then(async () => {
checkUpdates();
if (process.platform === "win32") app.setAppUserModelId("dev.vencord.desktop");
else if (process.platform === "darwin") app.dock.setIcon(ICON_PATH);
@@ -51,6 +51,18 @@ if (!app.requestSingleInstanceLock()) {
});
}
if (!app.requestSingleInstanceLock({ IS_DEV })) {
if (IS_DEV) {
console.log("Vencord Desktop is already running. Quitting previous instance...");
init();
} else {
console.log("Vencord Desktop is already running. Quitting...");
app.quit();
}
} else {
init();
}
async function createWindows() {
const splash = createSplashWindow();

View File

@@ -4,7 +4,7 @@
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
import { app, dialog, ipcMain, shell } from "electron";
import { app, dialog, ipcMain, session, shell } from "electron";
import { existsSync, readFileSync, watch } from "fs";
import { open, readFile } from "fs/promises";
import { join } from "path";
@@ -52,8 +52,20 @@ ipcMain.handle(IpcEvents.SHOW_ITEM_IN_FOLDER, (_, path) => {
shell.showItemInFolder(path);
});
ipcMain.handle(IpcEvents.FOCUS, () => {
mainWin?.focus();
ipcMain.handle(IpcEvents.FOCUS, e => {
e.sender.focus();
});
ipcMain.handle(IpcEvents.CLOSE, e => {
e.sender.close();
});
ipcMain.handle(IpcEvents.SPELLCHECK_SET_LANGUAGES, (_, languages: string[]) => {
const ses = session.defaultSession;
const available = ses.availableSpellCheckerLanguages;
const applicable = languages.filter(l => available.includes(l)).slice(0, 3);
if (applicable.length) ses.setSpellCheckerLanguages(applicable);
});
ipcMain.handle(IpcEvents.SELECT_VENCORD_DIR, async () => {

View File

@@ -84,9 +84,11 @@ function initMenuBar(win: BrowserWindow) {
const menu = Menu.buildFromTemplate([
{
label: "Vencord Desktop",
role: "appMenu",
submenu: [
{
label: "About Vencord Desktop",
role: "about",
click: createAboutWindow
},
{
@@ -98,28 +100,6 @@ function initMenuBar(win: BrowserWindow) {
},
toolTip: "Vencord Desktop will automatically restart after this operation"
},
{
label: "Toggle Developer Tools",
accelerator: "CmdOrCtrl+Shift+I",
click() {
BrowserWindow.getFocusedWindow()!.webContents.toggleDevTools();
}
},
{
label: "Toggle Developer Tools (Hidden)",
accelerator: "F12",
visible: false,
click() {
BrowserWindow.getFocusedWindow()!.webContents.toggleDevTools();
}
},
{
label: "Reload Window",
accelerator: "CmdOrCtrl+R",
click() {
BrowserWindow.getFocusedWindow()!.webContents.reload();
}
},
{
label: "Relaunch",
accelerator: "CmdOrCtrl+Shift+R",
@@ -132,6 +112,7 @@ function initMenuBar(win: BrowserWindow) {
label: "Quit",
accelerator: wantCtrlQ ? "CmdOrCtrl+Q" : void 0,
visible: !isWindows,
role: "quit",
click() {
app.quit();
}
@@ -140,34 +121,28 @@ function initMenuBar(win: BrowserWindow) {
label: "Quit",
accelerator: isWindows ? "Alt+F4" : void 0,
visible: isWindows,
role: "quit",
click() {
app.quit();
}
}
]
},
{ role: "fileMenu" },
{ role: "editMenu" },
{ role: "viewMenu" },
{ role: "windowMenu" },
{
label: "Zoom",
submenu: [
{
label: "Zoom in",
accelerator: "CmdOrCtrl+Plus",
role: "zoomIn"
},
// Fix for zoom in on keyboards with dedicated + like QWERTZ (or numpad)
// See https://github.com/electron/electron/issues/14742 and https://github.com/electron/electron/issues/5256
{
label: "Zoom in",
accelerator: "CmdOrCtrl+=",
role: "zoomIn",
visible: false
},
{
label: "Zoom out",
accelerator: "CmdOrCtrl+-",
role: "zoomOut"
role: "zoomIn"
}
]
],
visible: false
}
]);
@@ -281,6 +256,10 @@ export function createMainWindow() {
makeLinksOpenExternally(win);
initSettingsListeners(win);
win.webContents.setUserAgent(
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"
);
const subdomain =
Settings.store.discordBranch === "canary" || Settings.store.discordBranch === "ptb"
? `${Settings.store.discordBranch}.`

View File

@@ -6,18 +6,11 @@
import { BrowserWindow } from "electron";
import { join } from "path";
import { SplashProps } from "shared/browserWinProperties";
import { STATIC_DIR } from "shared/paths";
export function createSplashWindow() {
const splash = new BrowserWindow({
transparent: true,
frame: false,
height: 350,
width: 300,
center: true,
resizable: false,
maximizable: false
});
const splash = new BrowserWindow(SplashProps);
splash.loadFile(join(STATIC_DIR, "splash.html"));

View File

@@ -5,32 +5,43 @@
*/
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";
const API_BASE = "https://api.github.com/repos/Vendicated/Vencord";
const API_BASE = "https://api.github.com";
const FILES_TO_DOWNLOAD = ["vencordDesktopMain.js", "preload.js", "vencordDesktopRenderer.js", "renderer.css"];
export interface ReleaseData {
name: string;
tag_name: string;
html_url: string;
assets: Array<{
name: string;
browser_download_url: string;
}>;
}
export async function githubGet(endpoint: string) {
return simpleGet(API_BASE + endpoint, {
const opts: RequestOptions = {
headers: {
Accept: "application/vnd.github+json",
"User-Agent": USER_AGENT
}
});
};
if (process.env.GITHUB_TOKEN) opts.headers!.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
return simpleGet(API_BASE + endpoint, opts);
}
export async function downloadVencordFiles() {
const release = await githubGet("/releases/latest");
const release = await githubGet("/repos/Vendicated/Vencord/releases/latest");
const data = JSON.parse(release.toString("utf-8"));
const assets = data.assets as Array<{
name: string;
browser_download_url: string;
}>;
const { assets } = JSON.parse(release.toString("utf-8")) as ReleaseData;
await Promise.all(
assets

View File

@@ -4,19 +4,11 @@
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
import { ipcRenderer } from "electron";
import type { Settings } from "shared/settings";
import type { LiteralUnion } from "type-fest";
import { IpcEvents } from "../shared/IpcEvents";
function invoke<T = any>(event: IpcEvents, ...args: any[]) {
return ipcRenderer.invoke(event, ...args) as Promise<T>;
}
function sendSync<T = any>(event: IpcEvents, ...args: any[]) {
return ipcRenderer.sendSync(event, ...args) as T;
}
import { invoke, sendSync } from "./typedIpcs";
export const VencordDesktopNative = {
app: {
@@ -31,6 +23,10 @@ export const VencordDesktopNative = {
get: () => sendSync<Settings>(IpcEvents.GET_SETTINGS),
set: (settings: Settings, path?: string) => invoke<void>(IpcEvents.SET_SETTINGS, settings, path)
},
spellcheck: {
setLanguages: (languages: readonly string[]) => invoke<void>(IpcEvents.SPELLCHECK_SET_LANGUAGES, languages)
// todo: perhaps add ways to learn words
},
win: {
focus: () => invoke<void>(IpcEvents.FOCUS)
}

View File

@@ -39,5 +39,6 @@ if (IS_DEV) {
document.getElementById("vcd-css-core")!.textContent = readFileSync(rendererCss, "utf-8");
});
}
// #endregion
VencordDesktopNative.spellcheck.setLanguages(window.navigator.languages);

16
src/preload/typedIpcs.ts Normal file
View File

@@ -0,0 +1,16 @@
/*
* SPDX-License-Identifier: GPL-3.0
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
import { ipcRenderer } from "electron";
import { IpcEvents } from "shared/IpcEvents";
export function invoke<T = any>(event: IpcEvents, ...args: any[]) {
return ipcRenderer.invoke(event, ...args) as Promise<T>;
}
export function sendSync<T = any>(event: IpcEvents, ...args: any[]) {
return ipcRenderer.sendSync(event, ...args) as T;
}

View File

@@ -19,5 +19,13 @@ export const enum IpcEvents {
GET_SETTINGS = "VCD_GET_SETTINGS",
SET_SETTINGS = "VCD_SET_SETTINGS",
SELECT_VENCORD_DIR = "VCD_SELECT_VENCORD_DIR"
SELECT_VENCORD_DIR = "VCD_SELECT_VENCORD_DIR",
UPDATER_GET_DATA = "VCD_UPDATER_GET_DATA",
UPDATER_DOWNLOAD = "VCD_UPDATER_DOWNLOAD",
UPDATE_IGNORE = "VCD_UPDATE_IGNORE",
SPELLCHECK_SET_LANGUAGES = "VCD_SPELLCHECK_SET_LANGUAGES",
CLOSE = "VCD_CLOSE"
}

View File

@@ -0,0 +1,18 @@
/*
* SPDX-License-Identifier: GPL-3.0
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
import type { BrowserWindowConstructorOptions } from "electron";
export const SplashProps: BrowserWindowConstructorOptions = {
transparent: true,
frame: false,
height: 350,
width: 300,
center: true,
resizable: false,
maximizable: false,
alwaysOnTop: true
};

View File

@@ -16,4 +16,5 @@ export interface Settings {
disableMinSize?: boolean;
tray?: boolean;
minimizeToTray?: boolean;
skippedUpdate?: string;
}

View File

@@ -67,7 +67,7 @@ export class SettingsStore<T extends object> {
* Set the data of the store.
* This will update this.store and this.plain (and old references to them will be stale! Avoid storing them in variables)
*
* Additionally, all global listeners (or those for pathToNotify, if specified) will be called with the new data
* Additionally, all global listeners (and those for pathToNotify, if specified) will be called with the new data
* @param value New data
* @param pathToNotify Optional path to notify instead of globally. Used to transfer path via ipc
*/
@@ -90,9 +90,9 @@ export class SettingsStore<T extends object> {
}
this.pathListeners.get(pathToNotify)?.forEach(cb => cb(v));
} else {
this.globalListeners.forEach(cb => cb(value, ""));
}
this.globalListeners.forEach(cb => cb(value, ""));
}
/**

98
src/updater/main.ts Normal file
View File

@@ -0,0 +1,98 @@
/*
* SPDX-License-Identifier: GPL-3.0
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
import { app, BrowserWindow, ipcMain, shell } from "electron";
import { Settings } from "main/settings";
import { githubGet, ReleaseData } from "main/utils/vencordLoader";
import { join } from "path";
import { SplashProps } from "shared/browserWinProperties";
import { IpcEvents } from "shared/IpcEvents";
import { STATIC_DIR } from "shared/paths";
export interface UpdateData {
currentVersion: string;
latestVersion: string;
release: ReleaseData;
}
let updateData: UpdateData;
ipcMain.handle(IpcEvents.UPDATER_GET_DATA, () => updateData);
ipcMain.handle(IpcEvents.UPDATER_DOWNLOAD, () => {
const { assets } = updateData.release;
const url = (() => {
switch (process.platform) {
case "win32":
return assets.find(a => a.name.endsWith(".exe"))!.browser_download_url;
case "darwin":
return assets.find(a => a.name.endsWith(".dmg"))!.browser_download_url;
case "linux":
return updateData.release.html_url;
default:
throw new Error(`Unsupported platform: ${process.platform}`);
}
})();
shell.openExternal(url);
});
ipcMain.handle(IpcEvents.UPDATE_IGNORE, () => {
Settings.store.skippedUpdate = updateData.latestVersion;
});
function isOutdated(oldVersion: string, newVersion: string) {
const oldParts = oldVersion.split(".");
const newParts = newVersion.split(".");
if (oldParts.length !== newParts.length)
throw new Error(`Incompatible version strings (old: ${oldVersion}, new: ${newVersion})`);
for (let i = 0; i < oldParts.length; i++) {
const oldPart = Number(oldParts[i]);
const newPart = Number(newParts[i]);
if (isNaN(oldPart) || isNaN(newPart))
throw new Error(`Invalid version string (old: ${oldVersion}, new: ${newVersion})`);
if (oldPart < newPart) return true;
if (oldPart > newPart) return false;
}
return false;
}
export async function checkUpdates() {
// if (IS_DEV) return;
try {
const raw = await githubGet("/repos/Vencord/Desktop/releases/latest");
const data = JSON.parse(raw.toString("utf-8")) as ReleaseData;
const oldVersion = app.getVersion();
const newVersion = data.tag_name.replace(/^v/, "");
if (Settings.store.skippedUpdate !== newVersion && isOutdated(oldVersion, newVersion)) {
updateData = {
currentVersion: oldVersion,
latestVersion: newVersion,
release: data
};
openNewUpdateWindow();
}
} catch (e) {
console.error("AppUpdater: Failed to check for updates\n", e);
}
}
function openNewUpdateWindow() {
const win = new BrowserWindow({
...SplashProps,
webPreferences: {
preload: join(__dirname, "updaterPreload.js")
}
});
win.loadFile(join(STATIC_DIR, "updater.html"));
}

21
src/updater/preload.ts Normal file
View File

@@ -0,0 +1,21 @@
/*
* SPDX-License-Identifier: GPL-3.0
* Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience
* Copyright (c) 2023 Vendicated and Vencord contributors
*/
import { contextBridge } from "electron";
import { invoke } from "preload/typedIpcs";
import { IpcEvents } from "shared/IpcEvents";
import type { UpdateData } from "./main";
contextBridge.exposeInMainWorld("Updater", {
getData: () => invoke<UpdateData>(IpcEvents.UPDATER_GET_DATA),
download: () => {
invoke<void>(IpcEvents.UPDATER_DOWNLOAD);
invoke<void>(IpcEvents.CLOSE);
},
ignore: () => invoke<void>(IpcEvents.UPDATE_IGNORE),
close: () => invoke<void>(IpcEvents.CLOSE)
});

115
static/updater.html Normal file
View File

@@ -0,0 +1,115 @@
<head>
<style>
body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell,
"Open Sans", "Helvetica Neue", sans-serif;
margin: 0;
padding: 0;
color: rgb(219, 222, 225);
}
.wrapper {
display: flex;
flex-direction: column;
justify-content: space-between;
box-sizing: border-box;
height: 100%;
background-color: #313338;
border-radius: 8px;
border: 1px solid #248046;
padding: 1em;
}
h1 {
text-align: center;
}
.buttons {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.5em;
margin-top: 0.25em;
}
button {
cursor: pointer;
padding: 0.5em;
color: white;
border: none;
border-radius: 3px;
font-weight: bold;
transition: filter 0.2 ease-in-out;
}
button:hover,
button:active {
filter: brightness(0.9);
}
.green {
background-color: #248046;
}
.red {
background-color: #ed4245;
}
</style>
</head>
<body>
<div class="wrapper">
<section>
<h1>Update Available</h1>
<p>There's a new update for Vencord Desktop! Update now to get new fixes and features!</p>
<p>
Current: <span id="current"></span>
<br />
Latest: <span id="latest"></span>
</p>
</section>
<section>
<label id="disable-remind">
<input type="checkbox" />
<span>Do not remind again for </span>
</label>
<div class="buttons">
<button name="download" class="green">Download Update</button>
<button name="close" class="red">Close</button>
</div>
</section>
</div>
</body>
<script type="module">
const data = await Updater.getData();
document.getElementById("current").textContent = data.currentVersion;
document.getElementById("latest").textContent = data.latestVersion;
document.querySelector("#disable-remind > span").textContent += data.latestVersion;
function checkDisableRemind() {
const checkbox = document.querySelector("#disable-remind > input");
if (checkbox.checked) {
Updater.ignore();
}
}
const onClicks = {
download() {
checkDisableRemind();
Updater.download();
},
close() {
checkDisableRemind();
Updater.close();
}
};
for (const name in onClicks) {
document.querySelectorAll(`button[name="${name}"]`).forEach(button => {
button.addEventListener("click", onClicks[name]);
});
}
</script>