diff --git a/scripts/build/build.mts b/scripts/build/build.mts index c335fe8..11c4d5f 100644 --- a/scripts/build/build.mts +++ b/scripts/build/build.mts @@ -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(); + }) + ); } diff --git a/scripts/startWatch.mts b/scripts/startWatch.mts index d30a938..1605115 100644 --- a/scripts/startWatch.mts +++ b/scripts/startWatch.mts @@ -1,10 +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 { spawn as cpSpawn, SpawnOptions } from "child_process"; import { join } from "path"; const EXT = process.platform === "win32" ? ".cmd" : ""; const OPTS: SpawnOptions = { - stdio: "inherit", + stdio: "inherit" }; function spawn(bin: string, args: string[]) { diff --git a/src/main/index.ts b/src/main/index.ts index eccfb75..68c8972 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -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"; @@ -40,6 +41,8 @@ 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); diff --git a/src/main/utils/vencordLoader.ts b/src/main/utils/vencordLoader.ts index 5f17add..6429872 100644 --- a/src/main/utils/vencordLoader.ts +++ b/src/main/utils/vencordLoader.ts @@ -10,10 +10,20 @@ 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, { headers: { @@ -24,13 +34,9 @@ export async function githubGet(endpoint: string) { } 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 diff --git a/src/shared/IpcEvents.ts b/src/shared/IpcEvents.ts index d324315..58bb316 100644 --- a/src/shared/IpcEvents.ts +++ b/src/shared/IpcEvents.ts @@ -19,5 +19,7 @@ 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_LATEST_VERSION = "VCD_UPDATER_GET_LATEST_VERSION" } diff --git a/src/updater/main.ts b/src/updater/main.ts new file mode 100644 index 0000000..1a6da0e --- /dev/null +++ b/src/updater/main.ts @@ -0,0 +1,61 @@ +/* + * 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 } from "electron"; +import { githubGet, ReleaseData } from "main/utils/vencordLoader"; +import { join } from "path"; +import { IpcEvents } from "shared/IpcEvents"; +import { STATIC_DIR } from "shared/paths"; + +let latestVersion: string; + +ipcMain.handle(IpcEvents.UPDATER_GET_LATEST_VERSION, () => 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 { tag_name } = JSON.parse(raw.toString("utf-8")) as ReleaseData; + + const oldVersion = app.getVersion(); + const newVersion = (latestVersion = tag_name.replace(/^v/, "")); + if (isOutdated(oldVersion, newVersion)) openNewUpdateWindow(); + } catch (e) { + console.error("AppUpdater: Failed to check for updates\n", e); + } +} + +function openNewUpdateWindow() { + const win = new BrowserWindow({ + webPreferences: { + preload: join(__dirname, "updaterPreload.js") + } + }); + + win.loadFile(join(STATIC_DIR, "updater.html")); +} diff --git a/src/updater/preload.ts b/src/updater/preload.ts new file mode 100644 index 0000000..88722d8 --- /dev/null +++ b/src/updater/preload.ts @@ -0,0 +1,12 @@ +/* + * 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, ipcRenderer } from "electron"; +import { IpcEvents } from "shared/IpcEvents"; + +contextBridge.exposeInMainWorld("Updater", { + getLatestVersion: () => ipcRenderer.invoke(IpcEvents.UPDATER_GET_LATEST_VERSION) +}); diff --git a/static/updater.html b/static/updater.html new file mode 100644 index 0000000..2b52a69 --- /dev/null +++ b/static/updater.html @@ -0,0 +1,7 @@ +
hi
+

+ +