mirror of
https://github.com/Vencord/Vesktop.git
synced 2025-02-22 21:35:08 +00:00
Add Vencord Loading & tray icon
This commit is contained in:
parent
307051141d
commit
f45d6482ac
12 changed files with 176 additions and 11 deletions
7
src/main/constants.ts
Normal file
7
src/main/constants.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { app } from "electron";
|
||||||
|
import { join } from "path";
|
||||||
|
|
||||||
|
export const DATA_DIR = process.env.VENCORD_USER_DATA_DIR ?? join(app.getPath("userData"), "VencordDesktop");
|
||||||
|
export const VENCORD_FILES_DIR = join(DATA_DIR, "vencordDist");
|
||||||
|
|
||||||
|
export const USER_AGENT = `VencordDesktop/${app.getVersion()} (https://github.com/Vencord/Electron)`;
|
|
@ -3,21 +3,33 @@ import { createMainWindow } from "./mainWindow";
|
||||||
import { createSplashWindow } from "./splash";
|
import { createSplashWindow } from "./splash";
|
||||||
|
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
|
|
||||||
|
import { DATA_DIR, VENCORD_FILES_DIR } from "./constants";
|
||||||
|
|
||||||
|
import { once } from "../shared/utils/once";
|
||||||
import "./ipc";
|
import "./ipc";
|
||||||
|
import { ensureVencordFiles } from "./utils/vencordLoader";
|
||||||
|
|
||||||
require(join(__dirname, "Vencord/main.js"));
|
// Make the Vencord files use our DATA_DIR
|
||||||
|
process.env.VENCORD_USER_DATA_DIR = DATA_DIR;
|
||||||
|
|
||||||
function createWindows() {
|
const runVencordMain = once(() => require(join(VENCORD_FILES_DIR, "main.js")));
|
||||||
const mainWindow = createMainWindow();
|
|
||||||
|
async function createWindows() {
|
||||||
const splash = createSplashWindow();
|
const splash = createSplashWindow();
|
||||||
|
|
||||||
|
await ensureVencordFiles();
|
||||||
|
runVencordMain();
|
||||||
|
|
||||||
|
const mainWindow = createMainWindow();
|
||||||
|
|
||||||
mainWindow.once("ready-to-show", () => {
|
mainWindow.once("ready-to-show", () => {
|
||||||
splash.destroy();
|
splash.destroy();
|
||||||
mainWindow.show();
|
mainWindow.show();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
app.whenReady().then(() => {
|
app.whenReady().then(async () => {
|
||||||
createWindows();
|
createWindows();
|
||||||
|
|
||||||
app.on('activate', () => {
|
app.on('activate', () => {
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { ipcMain } from "electron";
|
||||||
|
import { join } from "path";
|
||||||
|
import { GET_PRELOAD_FILE } from "../shared/IpcEvents";
|
||||||
|
import { VENCORD_FILES_DIR } from "./constants";
|
||||||
|
|
||||||
|
ipcMain.on(GET_PRELOAD_FILE, e => {
|
||||||
|
e.returnValue = join(VENCORD_FILES_DIR, "preload.js");
|
||||||
|
});
|
|
@ -1,7 +1,9 @@
|
||||||
import { BrowserWindow } from "electron";
|
import { BrowserWindow, Menu, Tray, app } from "electron";
|
||||||
import { join } from "path";
|
import { join } from "path";
|
||||||
|
|
||||||
export function createMainWindow() {
|
export function createMainWindow() {
|
||||||
|
let isQuitting = false;
|
||||||
|
|
||||||
const win = new BrowserWindow({
|
const win = new BrowserWindow({
|
||||||
show: false,
|
show: false,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
|
@ -10,9 +12,42 @@ export function createMainWindow() {
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
devTools: true,
|
devTools: true,
|
||||||
preload: join(__dirname, "preload.js")
|
preload: join(__dirname, "preload.js")
|
||||||
}
|
},
|
||||||
|
icon: join(__dirname, "..", "..", "static", "icon.ico")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.on("before-quit", () => {
|
||||||
|
isQuitting = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
win.on("close", e => {
|
||||||
|
if (isQuitting) return;
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
win.hide();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
const tray = new Tray(join(__dirname, "..", "..", "static", "icon.ico"));
|
||||||
|
tray.setToolTip("Vencord Desktop");
|
||||||
|
tray.setContextMenu(Menu.buildFromTemplate([
|
||||||
|
{
|
||||||
|
label: "Open",
|
||||||
|
click() {
|
||||||
|
win.show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Quit",
|
||||||
|
click() {
|
||||||
|
isQuitting = true;
|
||||||
|
app.quit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]));
|
||||||
|
tray.on("click", () => win.show());
|
||||||
|
|
||||||
win.loadURL("https://discord.com/app");
|
win.loadURL("https://discord.com/app");
|
||||||
|
|
||||||
return win;
|
return win;
|
||||||
|
|
|
@ -12,7 +12,7 @@ export function createSplashWindow() {
|
||||||
maximizable: false
|
maximizable: false
|
||||||
});
|
});
|
||||||
|
|
||||||
splash.loadFile(join(__dirname, "..", "static", "splash.html"));
|
splash.loadFile(join(__dirname, "..", "..", "static", "splash.html"));
|
||||||
|
|
||||||
return splash;
|
return splash;
|
||||||
}
|
}
|
||||||
|
|
41
src/main/utils/http.ts
Normal file
41
src/main/utils/http.ts
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
import { createWriteStream } from "fs";
|
||||||
|
import type { IncomingMessage } from "http";
|
||||||
|
import { RequestOptions, get } from "https";
|
||||||
|
import { finished } from "stream/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
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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)));
|
||||||
|
});
|
||||||
|
}
|
54
src/main/utils/vencordLoader.ts
Normal file
54
src/main/utils/vencordLoader.ts
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import { existsSync, mkdirSync } from "fs";
|
||||||
|
import { join } from "path";
|
||||||
|
import { USER_AGENT, VENCORD_FILES_DIR } from "../constants";
|
||||||
|
import { downloadFile, simpleGet } from "./http";
|
||||||
|
|
||||||
|
// TODO: Setting to switch repo
|
||||||
|
const API_BASE = "https://api.github.com/repos/Vendicated/VencordDev";
|
||||||
|
|
||||||
|
const FILES_TO_DOWNLOAD = [
|
||||||
|
"vencordDesktopMain.js",
|
||||||
|
"preload.js",
|
||||||
|
"vencordDesktopRenderer.js",
|
||||||
|
"renderer.css"
|
||||||
|
];
|
||||||
|
|
||||||
|
export async function githubGet(endpoint: string) {
|
||||||
|
return simpleGet(API_BASE + endpoint, {
|
||||||
|
headers: {
|
||||||
|
Accept: "application/vnd.github+json",
|
||||||
|
"User-Agent": USER_AGENT
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function downloadVencordFiles() {
|
||||||
|
const release = await githubGet("/releases/latest");
|
||||||
|
|
||||||
|
const data = JSON.parse(release.toString("utf-8"));
|
||||||
|
const assets = data.assets as Array<{
|
||||||
|
name: string;
|
||||||
|
browser_download_url: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
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.replace(/vencordDesktop(\w)/, (_, c) => c.toLowerCase())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function ensureVencordFiles() {
|
||||||
|
if (existsSync(join(VENCORD_FILES_DIR, "main.js"))) return;
|
||||||
|
mkdirSync(VENCORD_FILES_DIR, { recursive: true });
|
||||||
|
|
||||||
|
await downloadVencordFiles();
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
import { join } from "path";
|
import { ipcRenderer } from "electron";
|
||||||
|
import { GET_PRELOAD_FILE } from "../shared/IpcEvents";
|
||||||
|
|
||||||
require(join(__dirname, "Vencord/preload.js"));
|
require(ipcRenderer.sendSync(GET_PRELOAD_FILE));
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
export const GET_PRELOAD_FILE = "VCD_GET_PRELOAD_FILE";
|
|
@ -1,2 +0,0 @@
|
||||||
|
|
||||||
|
|
8
src/shared/utils/once.ts
Normal file
8
src/shared/utils/once.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
export function once<T extends Function>(fn: T): T {
|
||||||
|
let called = false;
|
||||||
|
return function (this: any, ...args: any[]) {
|
||||||
|
if (called) return;
|
||||||
|
called = true;
|
||||||
|
return fn.apply(this, args);
|
||||||
|
} as any;
|
||||||
|
}
|
BIN
static/icon.ico
Normal file
BIN
static/icon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
Loading…
Add table
Reference in a new issue