diff --git a/package.json b/package.json index 7e45ce0..997302d 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "updateMeta": "tsx scripts/utils/updateMeta.mts" }, "dependencies": { - "arrpc": "github:OpenAsar/arrpc#c62ec6a04c8d870530aa6944257fe745f6c59a24" + "arrpc": "github:OpenAsar/arrpc#c62ec6a04c8d870530aa6944257fe745f6c59a24", + "electron-updater": "^6.2.1" }, "optionalDependencies": { "@vencord/venmic": "^6.1.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9cbb7be..da8e84d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,6 +16,9 @@ importers: arrpc: specifier: github:OpenAsar/arrpc#c62ec6a04c8d870530aa6944257fe745f6c59a24 version: https://codeload.github.com/OpenAsar/arrpc/tar.gz/c62ec6a04c8d870530aa6944257fe745f6c59a24(patch_hash=biyukfa6dww2wxujy4eyvkhrti) + electron-updater: + specifier: ^6.2.1 + version: 6.2.1 optionalDependencies: '@vencord/venmic': specifier: ^6.1.0 @@ -429,6 +432,7 @@ packages: '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} @@ -436,6 +440,7 @@ packages: '@humanwhocodes/object-schema@2.0.2': resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} + deprecated: Use @eslint/object-schema instead '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} @@ -1085,6 +1090,9 @@ packages: electron-publish@24.13.1: resolution: {integrity: sha512-2ZgdEqJ8e9D17Hwp5LEq5mLQPjqU3lv/IALvgp+4W8VeNhryfGhYEQC/PgDPMrnWUp+l60Ou5SJLsu+k4mhQ8A==} + electron-updater@6.2.1: + resolution: {integrity: sha512-83eKIPW14qwZqUUM6wdsIRwVKZyjmHxQ4/8G+1C6iS5PdDt7b1umYQyj1/qPpH510GmHEQe4q0kCPe3qmb3a0Q==} + electron@31.0.1: resolution: {integrity: sha512-2eBcp4iqLkTsml6mMq+iqrS5u3kJ/2mpOLP7Mj7lo0uNK3OyfNqRS9z1ArsHjBF2/HV250Te/O9nKrwQRTX/+g==} engines: {node: '>= 12.20.55'} @@ -1796,9 +1804,15 @@ packages: lodash.difference@4.5.0: resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==} + lodash.escaperegexp@4.1.2: + resolution: {integrity: sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==} + lodash.flatten@4.4.0: resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} + lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + lodash.isplainobject@4.0.6: resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} @@ -2379,6 +2393,9 @@ packages: text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + tiny-typed-emitter@2.1.0: + resolution: {integrity: sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA==} + tmp-promise@3.0.3: resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==} @@ -3659,6 +3676,19 @@ snapshots: transitivePeerDependencies: - supports-color + electron-updater@6.2.1: + dependencies: + builder-util-runtime: 9.2.4 + fs-extra: 10.1.0 + js-yaml: 4.1.0 + lazy-val: 1.0.5 + lodash.escaperegexp: 4.1.2 + lodash.isequal: 4.5.0 + semver: 7.6.0 + tiny-typed-emitter: 2.1.0 + transitivePeerDependencies: + - supports-color + electron@31.0.1: dependencies: '@electron/get': 2.0.3 @@ -4520,8 +4550,12 @@ snapshots: lodash.difference@4.5.0: {} + lodash.escaperegexp@4.1.2: {} + lodash.flatten@4.4.0: {} + lodash.isequal@4.5.0: {} + lodash.isplainobject@4.0.6: {} lodash.merge@4.6.2: {} @@ -5133,6 +5167,8 @@ snapshots: text-table@0.2.0: {} + tiny-typed-emitter@2.1.0: {} + tmp-promise@3.0.3: dependencies: tmp: 0.2.3 diff --git a/scripts/build/build.mts b/scripts/build/build.mts index 27f45cc..243381b 100644 --- a/scripts/build/build.mts +++ b/scripts/build/build.mts @@ -63,12 +63,6 @@ await Promise.all([ outfile: "dist/js/preload.js", footer: { js: "//# sourceURL=VCDPreload" } }), - createContext({ - ...NodeCommonOpts, - entryPoints: ["src/updater/preload.ts"], - outfile: "dist/js/updaterPreload.js", - footer: { js: "//# sourceURL=VCDUpdaterPreload" } - }), createContext({ ...CommonOpts, globalName: "Vesktop", diff --git a/src/main/index.ts b/src/main/index.ts index 29010c4..dbc0ee2 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -7,7 +7,7 @@ import "./ipc"; import { app, BrowserWindow, nativeTheme } from "electron"; -import { checkUpdates } from "updater/main"; +import { autoUpdater } from "electron-updater"; import { DATA_DIR } from "./constants"; import { createFirstLaunchTour } from "./firstLaunch"; @@ -21,6 +21,8 @@ if (IS_DEV) { require("source-map-support").install(); } +autoUpdater.checkForUpdatesAndNotify(); + // Make the Vencord files use our DATA_DIR process.env.VENCORD_USER_DATA_DIR = DATA_DIR; @@ -74,7 +76,6 @@ function init() { }); app.whenReady().then(async () => { - checkUpdates(); if (process.platform === "win32") app.setAppUserModelId("dev.vencord.vesktop"); registerScreenShareHandler(); diff --git a/src/main/settings.ts b/src/main/settings.ts index f2c1b80..b2aeea9 100644 --- a/src/main/settings.ts +++ b/src/main/settings.ts @@ -41,14 +41,7 @@ export const VencordSettings = loadSettings(VENCORD_SETTINGS_FILE, "Vencord if (Object.hasOwn(Settings.plain, "firstLaunch") && !existsSync(STATE_FILE)) { console.warn("legacy state in settings.json detected. migrating to state.json"); const state = {} as TState; - for (const prop of [ - "firstLaunch", - "maximized", - "minimized", - "skippedUpdate", - "steamOSLayoutVersion", - "windowBounds" - ] as const) { + for (const prop of ["firstLaunch", "maximized", "minimized", "steamOSLayoutVersion", "windowBounds"] as const) { state[prop] = Settings.plain[prop]; delete Settings.plain[prop]; } diff --git a/src/renderer/components/settings/Settings.tsx b/src/renderer/components/settings/Settings.tsx index d6de13c..d56f0ea 100644 --- a/src/renderer/components/settings/Settings.tsx +++ b/src/renderer/components/settings/Settings.tsx @@ -102,15 +102,7 @@ const SettingsOptions: Record> defaultValue: false } ], - "Notifications & Updates": [ - NotificationBadgeToggle, - { - key: "checkUpdates", - title: "Check for updates", - description: "Automatically check for Vesktop updates", - defaultValue: true - } - ], + Notifications: [NotificationBadgeToggle], Miscelleanous: [ { key: "arRPC", diff --git a/src/shared/settings.d.ts b/src/shared/settings.d.ts index ae19668..9597f85 100644 --- a/src/shared/settings.d.ts +++ b/src/shared/settings.d.ts @@ -22,8 +22,6 @@ export interface Settings { clickTrayToShowHide?: boolean; customTitleBar?: boolean; - checkUpdates?: boolean; - splashTheming?: boolean; splashColor?: string; splashBackground?: string; @@ -49,7 +47,6 @@ export interface State { windowBounds?: Rectangle; displayid: int; - skippedUpdate?: string; firstLaunch?: boolean; steamOSLayoutVersion?: number; diff --git a/src/updater/main.ts b/src/updater/main.ts deleted file mode 100644 index 4c19ffd..0000000 --- a/src/updater/main.ts +++ /dev/null @@ -1,115 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-3.0 - * Vesktop, a desktop app aiming to give you a snappier Discord Experience - * Copyright (c) 2023 Vendicated and Vencord contributors - */ - -import { app, BrowserWindow, shell } from "electron"; -import { PORTABLE } from "main/constants"; -import { Settings, State } from "main/settings"; -import { handle } from "main/utils/ipcWrappers"; -import { makeLinksOpenExternally } from "main/utils/makeLinksOpenExternally"; -import { githubGet, ReleaseData } from "main/utils/vencordLoader"; -import { join } from "path"; -import { IpcEvents } from "shared/IpcEvents"; -import { ICON_PATH, VIEW_DIR } from "shared/paths"; - -export interface UpdateData { - currentVersion: string; - latestVersion: string; - release: ReleaseData; -} - -let updateData: UpdateData; - -handle(IpcEvents.UPDATER_GET_DATA, () => updateData); -handle(IpcEvents.UPDATER_DOWNLOAD, () => { - const { assets } = updateData.release; - const url = (() => { - switch (process.platform) { - case "win32": - return assets.find(a => { - return a.name.endsWith(PORTABLE ? "win.zip" : ".exe"); - })!.browser_download_url; - case "darwin": - return assets.find(a => - process.arch === "arm64" - ? a.name.endsWith("-arm64-mac.zip") - : a.name.endsWith("-mac.zip") && !a.name.includes("arm64") - )!.browser_download_url; - case "linux": - return updateData.release.html_url; - default: - throw new Error(`Unsupported platform: ${process.platform}`); - } - })(); - - shell.openExternal(url); -}); - -handle(IpcEvents.UPDATE_IGNORE, () => { - State.store.skippedUpdate = updateData.latestVersion; -}); - -function isOutdated(oldVersion: string, newVersion: string) { - const oldParts = oldVersion.split("."); - const newParts = newVersion.split("."); - - if (oldParts.length !== newParts.length) - throw new Error(`Incompatible version strings (old: ${oldVersion}, new: ${newVersion})`); - - for (let i = 0; i < oldParts.length; i++) { - const oldPart = Number(oldParts[i]); - const newPart = Number(newParts[i]); - - if (isNaN(oldPart) || isNaN(newPart)) - throw new Error(`Invalid version string (old: ${oldVersion}, new: ${newVersion})`); - - if (oldPart < newPart) return true; - if (oldPart > newPart) return false; - } - - return false; -} - -export async function checkUpdates() { - if (Settings.store.checkUpdates === false) return; - - try { - const raw = await githubGet("/repos/Vencord/Vesktop/releases/latest"); - const data: ReleaseData = await raw.json(); - - const oldVersion = app.getVersion(); - const newVersion = data.tag_name.replace(/^v/, ""); - updateData = { - currentVersion: oldVersion, - latestVersion: newVersion, - release: data - }; - - if (State.store.skippedUpdate !== newVersion && isOutdated(oldVersion, newVersion)) { - openNewUpdateWindow(); - } - } catch (e) { - console.error("AppUpdater: Failed to check for updates\n", e); - } -} - -function openNewUpdateWindow() { - const win = new BrowserWindow({ - width: 500, - autoHideMenuBar: true, - alwaysOnTop: true, - webPreferences: { - preload: join(__dirname, "updaterPreload.js"), - nodeIntegration: false, - contextIsolation: true, - sandbox: true - }, - icon: ICON_PATH - }); - - makeLinksOpenExternally(win); - - win.loadFile(join(VIEW_DIR, "updater.html")); -} diff --git a/src/updater/preload.ts b/src/updater/preload.ts deleted file mode 100644 index 80e4dee..0000000 --- a/src/updater/preload.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * SPDX-License-Identifier: GPL-3.0 - * Vesktop, a desktop app aiming to give you a snappier Discord Experience - * Copyright (c) 2023 Vendicated and Vencord contributors - */ - -import { contextBridge } from "electron"; -import { invoke } from "preload/typedIpc"; -import { IpcEvents } from "shared/IpcEvents"; - -import type { UpdateData } from "./main"; - -contextBridge.exposeInMainWorld("Updater", { - getData: () => invoke(IpcEvents.UPDATER_GET_DATA), - download: () => { - invoke(IpcEvents.UPDATER_DOWNLOAD); - invoke(IpcEvents.CLOSE); - }, - ignore: () => invoke(IpcEvents.UPDATE_IGNORE), - close: () => invoke(IpcEvents.CLOSE) -});