Add ability to load Vencord from custom location (dev install)
This commit is contained in:
parent
591d380160
commit
805b6fbcc4
14 changed files with 456 additions and 310 deletions
|
@ -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": {
|
||||
|
|
620
pnpm-lock.yaml
620
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -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
2
src/globals.d.ts
vendored
|
@ -4,6 +4,8 @@ declare global {
|
|||
// TODO
|
||||
export var Vencord: any;
|
||||
export var vcdLS: typeof localStorage;
|
||||
|
||||
export var IS_DEV: boolean;
|
||||
}
|
||||
|
||||
export { };
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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(() => "");
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
6
src/renderer/components/settings.css
Normal file
6
src/renderer/components/settings.css
Normal file
|
@ -0,0 +1,6 @@
|
|||
.vcd-location-btns {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 0.5em;
|
||||
margin-top: 0.5em;
|
||||
}
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
||||
|
|
1
src/shared/settings.d.ts
vendored
1
src/shared/settings.d.ts
vendored
|
@ -9,4 +9,5 @@ export interface Settings {
|
|||
};
|
||||
discordBranch?: "stable" | "canary" | "ptb";
|
||||
openLinksWithElectron?: boolean;
|
||||
vencordDir?: string;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue