BetterDiscordApp-rauenzi/src/modules/pluginapi.js

321 lines
10 KiB
JavaScript
Raw Normal View History

2019-05-28 23:27:25 +02:00
import Utilities from "./utilities";
2019-06-19 21:24:05 +02:00
import WebpackModules from "./webpackmodules";
import DiscordModules from "./discordmodules";
2019-05-28 23:27:25 +02:00
import DataStore from "./datastore";
2019-06-19 05:09:49 +02:00
import DOMManager from "./dommanager";
import Toasts from "../ui/toasts";
import Modals from "../ui/modals";
2019-09-27 04:50:53 +02:00
import PluginManager from "./pluginmanager";
import ThemeManager from "./thememanager";
2019-05-28 23:27:25 +02:00
const BdApi = {
2019-05-30 07:06:17 +02:00
get React() { return DiscordModules.React; },
get ReactDOM() { return DiscordModules.ReactDOM; },
2019-05-28 20:19:48 +02:00
get WindowConfigFile() {
if (this._windowConfigFile) return this._windowConfigFile;
2019-05-30 07:06:17 +02:00
const electron = require("electron").remote.app;
2019-05-28 20:19:48 +02:00
const path = require("path");
2019-05-30 07:06:17 +02:00
const base = electron.getAppPath();
const roamingBase = electron.getPath("userData");
const roamingLocation = path.resolve(roamingBase, electron.getVersion(), "modules", "discord_desktop_core", "injector", "config.json");
2019-05-28 20:19:48 +02:00
const location = path.resolve(base, "..", "app", "config.json");
const fs = require("fs");
2019-05-30 07:06:17 +02:00
const realLocation = fs.existsSync(location) ? location : fs.existsSync(roamingLocation) ? roamingLocation : null;
if (!realLocation) return this._windowConfigFile = null;
return this._windowConfigFile = realLocation;
2019-05-28 20:19:48 +02:00
}
};
BdApi.getAllWindowPreferences = function() {
2019-05-30 07:06:17 +02:00
if (!this.WindowConfigFile) return {};
2019-05-28 23:27:25 +02:00
return __non_webpack_require__(this.WindowConfigFile);
2019-05-28 20:19:48 +02:00
};
BdApi.getWindowPreference = function(key) {
2019-05-30 07:06:17 +02:00
if (!this.WindowConfigFile) return undefined;
2019-05-28 20:19:48 +02:00
return this.getAllWindowPreferences()[key];
};
BdApi.setWindowPreference = function(key, value) {
2019-05-30 07:06:17 +02:00
if (!this.WindowConfigFile) return;
2019-05-28 20:19:48 +02:00
const fs = require("fs");
const prefs = this.getAllWindowPreferences();
prefs[key] = value;
delete require.cache[this.WindowConfigFile];
fs.writeFileSync(this.WindowConfigFile, JSON.stringify(prefs, null, 4));
};
//Inject CSS to document head
//id = id of element
//css = custom css
BdApi.injectCSS = function (id, css) {
2019-06-20 04:19:34 +02:00
DOMManager.injectStyle(id, css);
2019-05-28 20:19:48 +02:00
};
//Clear css/remove any element
//id = id of element
BdApi.clearCSS = function (id) {
2019-06-20 04:19:34 +02:00
DOMManager.removeStyle(id);
2019-05-28 20:19:48 +02:00
};
//Inject CSS to document head
//id = id of element
//css = custom css
BdApi.linkJS = function (id, url) {
2019-06-20 04:19:34 +02:00
return DOMManager.injectScript(id, url);
2019-05-28 20:19:48 +02:00
};
//Clear css/remove any element
//id = id of element
BdApi.unlinkJS = function (id) {
2019-06-20 04:19:34 +02:00
DOMManager.removeScript(id);
2019-05-28 20:19:48 +02:00
};
/**
* Shows a generic but very customizable modal.
* @param {string} title - title of the modal
* @param {string} content - a string of text to display in the modal
*/
BdApi.alert = function (title, content) {
2019-05-31 07:53:11 +02:00
Modals.alert(title, content);
2019-05-28 20:19:48 +02:00
};
/**
* Shows a generic but very customizable confirmation modal with optional confirm and cancel callbacks.
* @param {string} title - title of the modal
* @param {(string|ReactElement|Array<string|ReactElement>)} children - a single or mixed array of react elements and strings. Everything is wrapped in Discord's `TextElement` component so strings will show and render properly.
* @param {object} [options] - options to modify the modal
* @param {boolean} [options.danger=false] - whether the main button should be red or not
* @param {string} [options.confirmText=Okay] - text for the confirmation/submit button
* @param {string} [options.cancelText=Cancel] - text for the cancel button
* @param {callable} [options.onConfirm=NOOP] - callback to occur when clicking the submit button
* @param {callable} [options.onCancel=NOOP] - callback to occur when clicking the cancel button
*/
BdApi.showConfirmationModal = function (title, content, options = {}) {
2019-05-31 07:53:11 +02:00
return Modals.showConfirmationModal(title, content, options);
2019-05-28 20:19:48 +02:00
};
2019-06-03 22:25:08 +02:00
/**
* This shows a toast similar to android towards the bottom of the screen.
*
* @param {string} content The string to show in the toast.
* @param {object} options Options object. Optional parameter.
* @param {string} [options.type=""] Changes the type of the toast stylistically and semantically. Choices: "", "info", "success", "danger"/"error", "warning"/"warn". Default: ""
* @param {boolean} [options.icon=true] Determines whether the icon should show corresponding to the type. A toast without type will always have no icon. Default: true
* @param {number} [options.timeout=3000] Adjusts the time (in ms) the toast should be shown for before disappearing automatically. Default: 3000
* @param {boolean} [options.forceShow=false] Whether to force showing the toast and ignore the bd setting
*/
2019-05-28 20:19:48 +02:00
BdApi.showToast = function(content, options = {}) {
2019-05-31 07:53:11 +02:00
Toasts.show(content, options);
2019-05-28 20:19:48 +02:00
};
// Finds module
BdApi.findModule = function(filter) {
2019-05-30 07:06:17 +02:00
return WebpackModules.getModule(filter);
2019-05-28 20:19:48 +02:00
};
// Finds module
BdApi.findAllModules = function(filter) {
2019-05-30 07:06:17 +02:00
return WebpackModules.getModule(filter, false);
2019-05-28 20:19:48 +02:00
};
// Finds module
BdApi.findModuleByProps = function(...props) {
2019-05-30 07:06:17 +02:00
return WebpackModules.getByProps(...props);
2019-05-28 20:19:48 +02:00
};
BdApi.findModuleByPrototypes = function(...protos) {
2019-05-30 07:06:17 +02:00
return WebpackModules.getByPrototypes(...protos);
2019-05-28 20:19:48 +02:00
};
BdApi.findModuleByDisplayName = function(name) {
2019-05-30 07:06:17 +02:00
return WebpackModules.getByDisplayName(name);
2019-05-28 20:19:48 +02:00
};
// Gets react instance
BdApi.getInternalInstance = function(node) {
if (!(node instanceof window.jQuery) && !(node instanceof Element)) return undefined;
if (node instanceof jQuery) node = node[0];
2019-06-20 04:19:34 +02:00
return Utilities.getReactInstance(node);
2019-05-28 20:19:48 +02:00
};
// Gets data
BdApi.loadData = function(pluginName, key) {
return DataStore.getPluginData(pluginName, key);
};
BdApi.getData = BdApi.loadData;
// Sets data
BdApi.saveData = function(pluginName, key, data) {
return DataStore.setPluginData(pluginName, key, data);
};
BdApi.setData = BdApi.saveData;
// Deletes data
BdApi.deleteData = function(pluginName, key) {
return DataStore.deletePluginData(pluginName, key);
};
// Patches other functions
BdApi.monkeyPatch = function(what, methodName, options) {
2019-09-27 04:50:53 +02:00
const {before, after, instead, once = false, silent = false, force = false} = options;
const displayName = options.displayName || what.displayName || what.name || what.constructor.displayName || what.constructor.name;
if (!silent) console.log("patch", methodName, "of", displayName); // eslint-disable-line no-console
if (!what[methodName]) {
if (force) what[methodName] = function() {};
else return console.error(methodName, "does not exist for", displayName); // eslint-disable-line no-console
}
const origMethod = what[methodName];
const cancel = () => {
if (!silent) console.log("unpatch", methodName, "of", displayName); // eslint-disable-line no-console
what[methodName] = origMethod;
};
what[methodName] = function() {
const data = {
thisObject: this,
methodArguments: arguments,
cancelPatch: cancel,
originalMethod: origMethod,
callOriginalMethod: () => data.returnValue = data.originalMethod.apply(data.thisObject, data.methodArguments)
};
if (instead) {
const tempRet = Utilities.suppressErrors(instead, "`instead` callback of " + what[methodName].displayName)(data);
if (tempRet !== undefined) data.returnValue = tempRet;
}
else {
if (before) Utilities.suppressErrors(before, "`before` callback of " + what[methodName].displayName)(data);
data.callOriginalMethod();
if (after) Utilities.suppressErrors(after, "`after` callback of " + what[methodName].displayName)(data);
}
if (once) cancel();
return data.returnValue;
};
what[methodName].__monkeyPatched = true;
if (!what[methodName].__originalMethod) what[methodName].__originalMethod = origMethod;
what[methodName].displayName = "patched " + (what[methodName].displayName || methodName);
return cancel;
2019-05-28 20:19:48 +02:00
};
// Event when element is removed
BdApi.onRemoved = function(node, callback) {
2019-05-28 23:27:25 +02:00
return Utilities.onRemoved(node, callback);
2019-05-28 20:19:48 +02:00
};
// Wraps function in try..catch
BdApi.suppressErrors = function(method, message) {
2019-05-28 23:27:25 +02:00
return Utilities.suppressErrors(method, message);
2019-05-28 20:19:48 +02:00
};
// Tests for valid JSON
BdApi.testJSON = function(data) {
2019-05-28 23:27:25 +02:00
return Utilities.testJSON(data);
2019-05-28 20:19:48 +02:00
};
2019-06-08 08:35:43 +02:00
//Get another plugin
//name = name of plugin
2019-09-27 04:50:53 +02:00
BdApi.getPlugin = function (name) {
return PluginManager.addonList.find(a => a.name == name);
};
BdApi.isPluginEnabled = function(name) {
const plugin = this.getPlugin(name);
if (!plugin) return false;
return PluginManager.isEnabled(plugin.id);
};
BdApi.isThemeEnabled = function(name) {
const theme = ThemeManager.addonList.find(a => a.name == name);
if (!theme) return false;
return ThemeManager.isEnabled(theme.id);
};
2019-05-28 20:19:48 +02:00
2020-04-24 00:12:01 +02:00
BdApi.isSettingEnabled = function(name) {
return null;
};
2019-05-28 20:19:48 +02:00
// Gets data
BdApi.getBDData = function(key) {
return DataStore.getBDData(key);
};
// Sets data
BdApi.setBDData = function(key, data) {
return DataStore.setBDData(key, data);
2019-05-28 23:27:25 +02:00
};
2020-04-23 22:01:48 +02:00
// const makeAddonAPI = (cookie, list, manager) => new class AddonAPI {
// get folder() {return manager.folder;}
// isEnabled(name) {
// return !!cookie[name];
// }
// enable(name) {
// return manager.enable(name);
// }
// disable(name) {
// return manager.disable(name);
// }
// toggle(name) {
// if (cookie[name]) this.disable(name);
// else this.enable(name);
// }
// reload(name) {
// return manager.reload(name);
// }
// get(name) {
// if (list.hasOwnProperty(name)) {
// if (list[name].plugin) return list[name].plugin;
// return list[name];
// }
// return null;
// }
// getAll() {
// return Object.keys(list).map(k => this.get(k)).filter(a => a);
// }
// };
// BdApi.Plugins = makeAddonAPI(pluginCookie, bdplugins, pluginModule);
// BdApi.Themes = makeAddonAPI(themeCookie, bdthemes, themeModule);
2020-04-24 00:12:01 +02:00
BdApi.Plugins = BdApi.themes = new class AddonAPI {
get folder() {return "";}
isEnabled(name) {
return null;
}
enable(name) {
return null;
}
disable(name) {
return null;
}
toggle(name) {
return null;
}
reload(name) {
return null;
}
get(name) {
return null;
}
getAll() {
return [];
}
};
2019-05-28 23:27:25 +02:00
export default BdApi;