From 96e6b5d01802ad389b83f6159791a6a2e735f41d Mon Sep 17 00:00:00 2001 From: Araxeus <78568641+Araxeus@users.noreply.github.com> Date: Sun, 12 Mar 2023 00:23:37 +0200 Subject: [PATCH 1/4] Add dynamic synced plugin config provider --- config/dynamic.js | 112 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 config/dynamic.js diff --git a/config/dynamic.js b/config/dynamic.js new file mode 100644 index 000000000..2e995f21f --- /dev/null +++ b/config/dynamic.js @@ -0,0 +1,112 @@ +const { ipcRenderer, ipcMain } = require("electron"); + +const defaultConfig = require("./defaults"); +const { getOptions, setOptions, setMenuOptions } = require("./plugins"); + +/** + * This class is used to create a dynamic synced config for plugins. + * + * [!IMPORTANT!] + * The methods are **sync** in the main process and **async** in the renderer process. + * + * @param {string} name - The name of the plugin. + * @param {boolean} [options.enableFront] - Whether the config should be available in front.js. Default: false. + * @param {object} [options.initialOptions] - The initial options for the plugin. Default: loaded from store. + * + * @example + * const { PluginConfig } = require("../../config/dynamic"); + * const config = new PluginConfig("plugin-name", { enableFront: true }); + * module.exports = { ...config }; + * + * // or + * + * module.exports = (win, options) => { + * const config = new PluginConfig("plugin-name", { + * enableFront: true, + * initialOptions: options, + * }); + * setupMyPlugin(win, config); + * }; + */ +module.exports.PluginConfig = class PluginConfig { + #name; + #config; + #defaultConfig; + #enableFront; + + constructor(name, { enableFront = false, initialOptions = undefined } = {}) { + const pluginDefaultConfig = defaultConfig.plugins[name] || {}; + const pluginConfig = initialOptions || getOptions(name) || {}; + + this.#name = name; + this.#enableFront = enableFront; + this.#defaultConfig = pluginDefaultConfig; + this.#config = { ...pluginDefaultConfig, ...pluginConfig }; + + if (this.#enableFront) { + this.#setupFront(); + } + } + + get = (option) => { + return this.#config[option]; + }; + + set = (option, value) => { + this.#config[option] = value; + this.#save(); + }; + + toggle = (option) => { + this.#config[option] = !this.#config[option]; + this.#save(); + }; + + getAll = () => { + return { ...this.#config }; + }; + + setAll = (options) => { + this.#config = { ...options }; + this.#save(); + }; + + getDefaultConfig = () => { + return this.#defaultConfig; + }; + + /** + * Use this method to set an option and restart the app if `appConfig.restartOnConfigChange === true` + * + * Used for options that require a restart to take effect. + */ + setAndMaybeRestart = (option, value) => { + this.#config[option] = value; + setMenuOptions(this.#name, this.#config); + }; + + #save() { + setOptions(this.#name, this.#config); + } + + #setupFront() { + if (process.type === "renderer") { + for (const [fnName, fn] of Object.entries(this)) { + if (typeof fn !== "function") return; + this[fnName] = async (...args) => { + return await ipcRenderer.invoke( + `${this.name}-config-${fnName}`, + ...args, + ); + }; + } + } else if (process.type === "browser") { + for (const [fnName, fn] of Object.entries(this)) { + if (typeof fn !== "function") return; + ipcMain.handle(`${this.name}-config-${fnName}`, (_, ...args) => { + return fn(...args); + }); + } + } + } +}; From bdfdf83c246ae2f15c8895690542f0743e0b35be Mon Sep 17 00:00:00 2001 From: Araxeus <78568641+Araxeus@users.noreply.github.com> Date: Sun, 12 Mar 2023 00:24:41 +0200 Subject: [PATCH 2/4] [notifications] use dynamic config --- plugins/notifications/back.js | 1 - plugins/notifications/config.js | 24 +++--------------------- 2 files changed, 3 insertions(+), 22 deletions(-) diff --git a/plugins/notifications/back.js b/plugins/notifications/back.js index 419e27d32..385ecca75 100644 --- a/plugins/notifications/back.js +++ b/plugins/notifications/back.js @@ -39,7 +39,6 @@ const setup = () => { /** @param {Electron.BrowserWindow} win */ module.exports = (win, options) => { - config.init(options); // Register the callback for new song information is.windows() && options.interactive ? require("./interactive")(win) : diff --git a/plugins/notifications/config.js b/plugins/notifications/config.js index 38d8100e0..d0898dc34 100644 --- a/plugins/notifications/config.js +++ b/plugins/notifications/config.js @@ -1,23 +1,5 @@ -const { setOptions, setMenuOptions } = require("../../config/plugins"); -const defaultConfig = require("../../config/defaults"); +const { PluginConfig } = require("../../config/dynamic"); -let config = defaultConfig.plugins["notifications"]; +const config = new PluginConfig("notifications"); -module.exports.init = (options) => { - config = { ...config, ...options }; -}; - -module.exports.setAndMaybeRestart = (option, value) => { - config[option] = value; - setMenuOptions("notifications", config); -}; - -module.exports.set = (option, value) => { - config[option] = value; - setOptions("notifications", config); -}; - -module.exports.get = (option) => { - let res = config[option]; - return res; -}; +module.exports = { ...config }; From 7d93e9f031407be72ffcf76e57c112c9f5f92073 Mon Sep 17 00:00:00 2001 From: Araxeus <78568641+Araxeus@users.noreply.github.com> Date: Sun, 12 Mar 2023 02:04:29 +0200 Subject: [PATCH 3/4] fix `config.setAll()` --- config/dynamic.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/dynamic.js b/config/dynamic.js index 2e995f21f..713379e6f 100644 --- a/config/dynamic.js +++ b/config/dynamic.js @@ -67,7 +67,7 @@ module.exports.PluginConfig = class PluginConfig { }; setAll = (options) => { - this.#config = { ...options }; + this.#config = { ...this.#config, ...options }; this.#save(); }; From a6242d13aecca8b9b6148a0f4bf8b1a504d2b66a Mon Sep 17 00:00:00 2001 From: Araxeus <78568641+Araxeus@users.noreply.github.com> Date: Sun, 19 Mar 2023 03:00:17 +0200 Subject: [PATCH 4/4] add `getActivePlugins` and `isActive` --- config/dynamic.js | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/config/dynamic.js b/config/dynamic.js index 713379e6f..34cb0ac36 100644 --- a/config/dynamic.js +++ b/config/dynamic.js @@ -3,6 +3,30 @@ const { ipcRenderer, ipcMain } = require("electron"); const defaultConfig = require("./defaults"); const { getOptions, setOptions, setMenuOptions } = require("./plugins"); +const activePlugins = {}; +/** + * [!IMPORTANT!] + * The method is **sync** in the main process and **async** in the renderer process. + */ +module.exports.getActivePlugins = + process.type === "renderer" + ? async () => ipcRenderer.invoke("get-active-plugins") + : () => activePlugins; + +if (process.type === "browser") { + ipcMain.handle("get-active-plugins", this.getActivePlugins); +} + +/** + * [!IMPORTANT!] + * The method is **sync** in the main process and **async** in the renderer process. + */ +module.exports.isActive = + process.type === "renderer" + ? async (plugin) => + plugin in (await ipcRenderer.invoke("get-active-plugins")) + : (plugin) => plugin in activePlugins; + /** * This class is used to create a dynamic synced config for plugins. * @@ -17,9 +41,9 @@ const { getOptions, setOptions, setMenuOptions } = require("./plugins"); * const { PluginConfig } = require("../../config/dynamic"); * const config = new PluginConfig("plugin-name", { enableFront: true }); * module.exports = { ...config }; - * + * * // or - * + * * module.exports = (win, options) => { * const config = new PluginConfig("plugin-name", { * enableFront: true, @@ -46,6 +70,8 @@ module.exports.PluginConfig = class PluginConfig { if (this.#enableFront) { this.#setupFront(); } + + activePlugins[name] = this; } get = (option) => { @@ -85,6 +111,7 @@ module.exports.PluginConfig = class PluginConfig { setMenuOptions(this.#name, this.#config); }; + /** Called only from back */ #save() { setOptions(this.#name, this.#config); }