diff --git a/scripts/build/build.mjs b/scripts/build/build.mjs index 45cda74a..51b6055f 100755 --- a/scripts/build/build.mjs +++ b/scripts/build/build.mjs @@ -76,7 +76,7 @@ await Promise.all([ outfile: "dist/renderer.js", format: "iife", target: ["esnext"], - footer: { js: "//# sourceURL=VencordRenderer\n" + sourceMapFooter("renderer") }, + footer: { js: "Vencord.Plugins.loadExternalPlugins();\n//# sourceURL=VencordRenderer\n" + sourceMapFooter("renderer") }, globalName: "Vencord", sourcemap, plugins: [ @@ -110,7 +110,7 @@ await Promise.all([ outfile: "dist/vencordDesktopRenderer.js", format: "iife", target: ["esnext"], - footer: { js: "//# sourceURL=VencordDesktopRenderer\n" + sourceMapFooter("vencordDesktopRenderer") }, + footer: { js: "Vencord.Plugins.loadExternalPlugins();\n//# sourceURL=VencordDesktopRenderer\n" + sourceMapFooter("vencordDesktopRenderer") }, globalName: "Vencord", sourcemap, plugins: [ diff --git a/src/main/ipcMain.ts b/src/main/ipcMain.ts index d60200f7..df6407ec 100644 --- a/src/main/ipcMain.ts +++ b/src/main/ipcMain.ts @@ -22,13 +22,13 @@ import { debounce } from "@utils/debounce"; import IpcEvents from "@utils/IpcEvents"; import { Queue } from "@utils/Queue"; import { BrowserWindow, ipcMain, shell } from "electron"; -import { mkdirSync, readFileSync, watch } from "fs"; +import { mkdirSync, readdirSync, readFileSync, watch } from "fs"; import { open, readFile, writeFile } from "fs/promises"; import { join } from "path"; import monacoHtml from "~fileContent/../components/monacoWin.html;base64"; -import { ALLOWED_PROTOCOLS, QUICKCSS_PATH, SETTINGS_DIR, SETTINGS_FILE } from "./utils/constants"; +import { ALLOWED_PROTOCOLS, PLUGINS_DIR, QUICKCSS_PATH, SETTINGS_DIR, SETTINGS_FILE } from "./utils/constants"; mkdirSync(SETTINGS_DIR, { recursive: true }); @@ -105,3 +105,15 @@ ipcMain.handle(IpcEvents.OPEN_MONACO_EDITOR, async () => { }); await win.loadURL(`data:text/html;base64,${monacoHtml}`); }); + +ipcMain.on(IpcEvents.GET_PLUGINS, e => { + try { + const files = readdirSync(PLUGINS_DIR).filter(f => f.endsWith(".js")); + console.log(files); + + e.returnValue = files.map(f => [f, readFileSync(join(PLUGINS_DIR, f), "utf-8")]); + } catch (err) { + console.error(err); + e.returnValue = []; + } +}); diff --git a/src/main/utils/constants.ts b/src/main/utils/constants.ts index cc9f459c..07802e53 100644 --- a/src/main/utils/constants.ts +++ b/src/main/utils/constants.ts @@ -25,6 +25,7 @@ export const DATA_DIR = process.env.VENCORD_USER_DATA_DIR ?? ( : join(app.getPath("userData"), "..", "Vencord") ); export const SETTINGS_DIR = join(DATA_DIR, "settings"); +export const PLUGINS_DIR = join(DATA_DIR, "plugins"); export const QUICKCSS_PATH = join(SETTINGS_DIR, "quickCss.css"); export const SETTINGS_FILE = join(SETTINGS_DIR, "settings.json"); export const ALLOWED_PROTOCOLS = [ diff --git a/src/plugins/index.ts b/src/plugins/index.ts index d0d16c23..21a484a5 100644 --- a/src/plugins/index.ts +++ b/src/plugins/index.ts @@ -18,6 +18,7 @@ import { registerCommand, unregisterCommand } from "@api/Commands"; import { Settings } from "@api/settings"; +import IpcEvents from "@utils/IpcEvents"; import Logger from "@utils/Logger"; import { Patch, Plugin } from "@utils/types"; @@ -63,7 +64,7 @@ for (const p of pluginsValues) if (settings[p.name]?.enabled) { }); } -for (const p of pluginsValues) { +function initPlugin(p: Plugin) { if (p.settings) { p.settings.pluginName = p.name; p.options ??= {}; @@ -82,6 +83,9 @@ for (const p of pluginsValues) { } } } +for (const p of pluginsValues) { + initPlugin(p); +} export const startAllPlugins = traceFunction("startAllPlugins", function startAllPlugins() { for (const name in Plugins) @@ -172,3 +176,18 @@ export const stopPlugin = traceFunction("stopPlugin", function stopPlugin(p: Plu return true; }, p => `stopPlugin ${p.name}`); + +export function loadExternalPlugins() { + for (const [name, src] of VencordNative.ipc.sendSync(IpcEvents.GET_PLUGINS)) { + try { + const p = Function(src)().default; + if (!p.name || Object.prototype.hasOwnProperty.call(Plugins, p.name)) + throw new Error("Invalid plugin or name conflicts with existing plugin"); + + Plugins[p.name] = p; + initPlugin(p); + } catch (err) { + logger.error(`Failed to load plugin ${name}`, err); + } + } +} diff --git a/src/utils/IpcEvents.ts b/src/utils/IpcEvents.ts index 57e4bb20..bb4727d1 100644 --- a/src/utils/IpcEvents.ts +++ b/src/utils/IpcEvents.ts @@ -43,4 +43,5 @@ export default strEnum({ UPDATE: "VencordUpdate", BUILD: "VencordBuild", OPEN_MONACO_EDITOR: "VencordOpenMonacoEditor", + GET_PLUGINS: "VencordGetPlugins", } as const);