Add ability to load Vencord from custom location (dev install)

This commit is contained in:
Vendicated 2023-04-09 02:26:31 +02:00
parent 591d380160
commit 805b6fbcc4
No known key found for this signature in database
GPG key ID: A1DC0CFB5615D905
14 changed files with 456 additions and 310 deletions

View file

@ -13,16 +13,19 @@
"package": "pnpm build && electron-builder",
"package:dir": "pnpm build && electron-builder --dir",
"start": "pnpm build && electron .",
"start:watch": "tsx scripts/startWatch.mts",
"start:dev": "pnpm build --dev && electron .",
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "pnpm build --watch"
},
"devDependencies": {
"@types/node": "^18.15.11",
"@types/react": "^18.0.33",
"electron": "^23.2.0",
"electron-builder": "^23.6.0",
"esbuild": "^0.17.14",
"source-map-support": "^0.5.21",
"tsx": "^3.12.6",
"type-fest": "^3.8.0",
"typescript": "^5.0.2"
},
"build": {

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,9 @@
import { BuildContext, BuildOptions, context } from "esbuild";
const isDev = process.argv.includes("--dev");
const CommonOpts: BuildOptions = {
minify: true,
minify: !isDev,
bundle: true,
sourcemap: "linked",
logLevel: "info"
@ -13,6 +15,9 @@ const NodeCommonOpts: BuildOptions = {
platform: "node",
external: ["electron"],
target: ["esnext"],
define: {
IS_DEV: JSON.stringify(isDev)
}
};
const contexts = [] as BuildContext[];

2
src/globals.d.ts vendored
View file

@ -4,6 +4,8 @@ declare global {
// TODO
export var Vencord: any;
export var vcdLS: typeof localStorage;
export var IS_DEV: boolean;
}
export { };

View file

@ -1,8 +1,10 @@
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 DATA_DIR = process.env.VENCORD_USER_DATA_DIR || join(app.getPath("userData"), "VencordDesktop");
// needs to be inline require because of circular dependency
// as otherwise "DATA_DIR" (which is used by ./settings) will be uninitialised
export const VENCORD_FILES_DIR = require("./settings").Settings.vencordDir || join(DATA_DIR, "vencordDist");
export const VENCORD_SETTINGS_DIR = join(DATA_DIR, "settings");
export const VENCORD_QUICKCSS_FILE = join(VENCORD_SETTINGS_DIR, "quickCss.css");
export const VENCORD_SETTINGS_FILE = join(VENCORD_SETTINGS_DIR, "settings.json");

View file

@ -3,16 +3,20 @@ import { join } from "path";
import { ICON_PATH } from "../shared/paths";
import { once } from "../shared/utils/once";
import { DATA_DIR, VENCORD_FILES_DIR } from "./constants";
import "./ipc";
import { createMainWindow } from "./mainWindow";
import { Settings } from "./settings";
import { createSplashWindow } from "./splash";
import { ensureVencordFiles } from "./utils/vencordLoader";
import "./ipc";
if (IS_DEV) {
require("source-map-support").install();
}
// Make the Vencord files use our DATA_DIR
process.env.VENCORD_USER_DATA_DIR = DATA_DIR;
const runVencordMain = once(() => require(join(VENCORD_FILES_DIR, "main.js")));
const runVencordMain = once(() => require(join(VENCORD_FILES_DIR, "vencordDesktopMain.js")));
let mainWin: BrowserWindow | null = null;

View file

@ -1,5 +1,5 @@
import { app, ipcMain, shell } from "electron";
import { readFileSync, watch } from "fs";
import { app, dialog, ipcMain, shell } from "electron";
import { existsSync, readFileSync, watch } from "fs";
import { open, readFile } from "fs/promises";
import { join } from "path";
import { debounce } from "shared/utils/debounce";
@ -12,6 +12,10 @@ ipcMain.on(IpcEvents.GET_VENCORD_PRELOAD_FILE, e => {
e.returnValue = join(VENCORD_FILES_DIR, "preload.js");
});
ipcMain.on(IpcEvents.GET_VENCORD_RENDERER_SCRIPT, e => {
e.returnValue = readFileSync(join(VENCORD_FILES_DIR, "vencordDesktopRenderer.js"), "utf-8");
});
ipcMain.on(IpcEvents.GET_RENDERER_SCRIPT, e => {
e.returnValue = readFileSync(join(__dirname, "renderer.js"), "utf-8");
});
@ -39,6 +43,20 @@ ipcMain.handle(IpcEvents.FOCUS, () => {
mainWin?.focus();
});
ipcMain.handle(IpcEvents.SELECT_VENCORD_DIR, async () => {
const res = await dialog.showOpenDialog(mainWin!, {
properties: ["openDirectory"]
});
if (!res.filePaths.length) return "cancelled";
const dir = res.filePaths[0];
for (const file of ["vencordDesktopMain.js", "preload.js", "vencordDesktopRenderer.js", "renderer.css"]) {
if (!existsSync(join(dir, file))) return "invalid";
}
return dir;
});
function readCss() {
return readFile(VENCORD_QUICKCSS_FILE, "utf-8").catch(() => "");
}

View file

@ -1,21 +1,31 @@
import { app, ipcRenderer } from "electron";
import type { Settings } from "../main/settings";
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;
}
export const VencordDesktopNative = {
app: {
relaunch: () => ipcRenderer.invoke(IpcEvents.RELAUNCH),
relaunch: () => invoke<void>(IpcEvents.RELAUNCH),
getVersion: () => app.getVersion()
},
fileManager: {
showItemInFolder: (path: string) => ipcRenderer.invoke(IpcEvents.SHOW_ITEM_IN_FOLDER, path)
showItemInFolder: (path: string) => invoke<void>(IpcEvents.SHOW_ITEM_IN_FOLDER, path),
selectVencordDir: () => invoke<LiteralUnion<"cancelled" | "invalid", string>>(IpcEvents.SELECT_VENCORD_DIR),
},
settings: {
get: () => ipcRenderer.sendSync(IpcEvents.GET_SETTINGS),
set: (settings: typeof Settings) => ipcRenderer.invoke(IpcEvents.SET_SETTINGS, settings)
get: () => sendSync<Settings>(IpcEvents.GET_SETTINGS),
set: (settings: Settings) => invoke<void>(IpcEvents.SET_SETTINGS, settings)
},
win: {
focus: () => ipcRenderer.invoke(IpcEvents.FOCUS)
focus: () => invoke<void>(IpcEvents.FOCUS)
}
}

View file

@ -6,5 +6,6 @@ contextBridge.exposeInMainWorld("VencordDesktopNative", VencordDesktopNative);
require(ipcRenderer.sendSync(IpcEvents.GET_VENCORD_PRELOAD_FILE));
webFrame.executeJavaScript(ipcRenderer.sendSync(IpcEvents.GET_VENCORD_RENDERER_SCRIPT));
webFrame.executeJavaScript(ipcRenderer.sendSync(IpcEvents.GET_RENDERER_SCRIPT));
ipcRenderer.invoke(IpcEvents.GET_RENDERER_STYLES).then(s => webFrame.insertCSS(s));

View file

@ -1,9 +1,13 @@
import { getValueAndOnChange, useSettings } from "renderer/settings";
import { Common } from "../vencord";
import { Common, Util } from "../vencord";
import "./settings.css";
const { Margins } = Util;
export default function SettingsUi() {
const Settings = useSettings();
const { Forms: { FormSection, FormText, FormDivider, FormSwitch, FormTitle }, Text, Select } = Common;
const { Forms: { FormSection, FormText, FormDivider, FormSwitch, FormTitle }, Text, Select, Button } = Common;
return (
<FormSection>
@ -11,7 +15,9 @@ export default function SettingsUi() {
Vencord Desktop Settings
</Text>
<FormTitle>Discord Branch</FormTitle>
<FormTitle className={Margins.top16}>
Discord Branch
</FormTitle>
<Select
placeholder="Stable"
options={[
@ -25,12 +31,58 @@ export default function SettingsUi() {
serialize={s => s}
/>
<FormDivider className={Margins.top16 + " " + Margins.bottom16} />
<FormSwitch
{...getValueAndOnChange("openLinksWithElectron")}
note={"This will open links in a new window instead of your WebBrowser"}
>
Open Links in app
</FormSwitch>
<FormTitle>Vencord Desktop Location</FormTitle>
<FormText>
Files are loaded from
{" "}
{Settings.vencordDir
? (
<a
href="about:blank"
onClick={e => {
e.preventDefault();
VencordDesktopNative.fileManager.showItemInFolder(Settings.vencordDir!);
}}
>
{Settings.vencordDir}
</a>
)
: "the default location"
}
</FormText>
<div className="vcd-location-btns">
<Button
size={Button.Sizes.SMALL}
onClick={async () => {
const choice = await VencordDesktopNative.fileManager.selectVencordDir();
switch (choice) {
case "cancelled":
case "invalid":
// TODO
return;
}
Settings.vencordDir = choice;
}}
>
Change
</Button>
<Button
size={Button.Sizes.SMALL}
color={Button.Colors.RED}
onClick={() => Settings.vencordDir = void 0}
>
Reset
</Button>
</div>
</FormSection>
);
}

View file

@ -0,0 +1,6 @@
.vcd-location-btns {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.5em;
margin-top: 0.5em;
}

View file

@ -1,12 +1,13 @@
// TODO: Taaaips when?
// FIXME: this is terrible
const { Webpack, Plugins } = Vencord;
const { Webpack, Plugins, Util } = Vencord;
const { Common } = Webpack;
const { plugins } = Plugins;
export {
Webpack,
Common,
Util,
Plugins,
plugins
};

View file

@ -1,5 +1,6 @@
export const enum IpcEvents {
GET_VENCORD_PRELOAD_FILE = "VCD_GET_VC_PRELOAD_FILE",
GET_VENCORD_RENDERER_SCRIPT = "VCD_GET_VC_RENDERER_SCRIPT",
GET_RENDERER_SCRIPT = "VCD_GET_RENDERER_SCRIPT",
GET_RENDERER_STYLES = "VCD_GET_RENDERER_STYLES",
@ -9,5 +10,7 @@ export const enum IpcEvents {
SHOW_ITEM_IN_FOLDER = "VCD_SHOW_ITEM_IN_FOLDER",
GET_SETTINGS = "VCD_GET_SETTINGS",
SET_SETTINGS = "VCD_SET_SETTINGS",
SELECT_VENCORD_DIR = "VCD_SELECT_VENCORD_DIR"
}

View file

@ -9,4 +9,5 @@ export interface Settings {
};
discordBranch?: "stable" | "canary" | "ptb";
openLinksWithElectron?: boolean;
vencordDir?: string;
}