discordplugins
This commit is contained in:
74
.config/BetterDiscord/plugins/BetterFormattingRedux.config.json
Executable file
74
.config/BetterDiscord/plugins/BetterFormattingRedux.config.json
Executable file
@@ -0,0 +1,74 @@
|
|||||||
|
{
|
||||||
|
"currentVersionInfo": {
|
||||||
|
"version": "2.3.11",
|
||||||
|
"hasShownChangelog": true
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"toolbar": {
|
||||||
|
"bold": true,
|
||||||
|
"italic": true,
|
||||||
|
"underline": true,
|
||||||
|
"strikethrough": true,
|
||||||
|
"spoiler": true,
|
||||||
|
"code": true,
|
||||||
|
"codeblock": true,
|
||||||
|
"superscript": true,
|
||||||
|
"smallcaps": true,
|
||||||
|
"fullwidth": true,
|
||||||
|
"upsidedown": true,
|
||||||
|
"varied": true,
|
||||||
|
"leet": false,
|
||||||
|
"thicc": false
|
||||||
|
},
|
||||||
|
"formats": {
|
||||||
|
"superscript": true,
|
||||||
|
"smallcaps": true,
|
||||||
|
"fullwidth": true,
|
||||||
|
"upsidedown": true,
|
||||||
|
"varied": true,
|
||||||
|
"leet": false,
|
||||||
|
"thicc": false
|
||||||
|
},
|
||||||
|
"wrappers": {
|
||||||
|
"superscript": "^^",
|
||||||
|
"smallcaps": "%%",
|
||||||
|
"fullwidth": "##",
|
||||||
|
"upsidedown": "&&",
|
||||||
|
"varied": "==",
|
||||||
|
"leet": "++",
|
||||||
|
"thicc": "$$"
|
||||||
|
},
|
||||||
|
"formatting": {
|
||||||
|
"fullWidthMap": true,
|
||||||
|
"reorderUpsidedown": true,
|
||||||
|
"fullwidth": true
|
||||||
|
},
|
||||||
|
"plugin": {
|
||||||
|
"hoverOpen": true,
|
||||||
|
"chainFormats": true,
|
||||||
|
"closeOnSend": true
|
||||||
|
},
|
||||||
|
"style": {
|
||||||
|
"icons": true,
|
||||||
|
"rightSide": true,
|
||||||
|
"toolbarOpacity": 1,
|
||||||
|
"fontSize": 85
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"buttonOrder": [
|
||||||
|
"bold",
|
||||||
|
"italic",
|
||||||
|
"underline",
|
||||||
|
"strikethrough",
|
||||||
|
"spoiler",
|
||||||
|
"codeblock",
|
||||||
|
"code",
|
||||||
|
"superscript",
|
||||||
|
"smallcaps",
|
||||||
|
"fullwidth",
|
||||||
|
"upsidedown",
|
||||||
|
"varied",
|
||||||
|
"leet",
|
||||||
|
"thicc"
|
||||||
|
]
|
||||||
|
}
|
||||||
6
.config/BetterDiscord/plugins/BlurNSFW.config.json
Executable file
6
.config/BetterDiscord/plugins/BlurNSFW.config.json
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"currentVersionInfo": {
|
||||||
|
"version": "0.2.5",
|
||||||
|
"hasShownChangelog": true
|
||||||
|
}
|
||||||
|
}
|
||||||
144
.config/BetterDiscord/plugins/BlurNSFW.plugin.js
Executable file
144
.config/BetterDiscord/plugins/BlurNSFW.plugin.js
Executable file
@@ -0,0 +1,144 @@
|
|||||||
|
/**
|
||||||
|
* @name BlurNSFW
|
||||||
|
* @version 0.2.5
|
||||||
|
* @authorLink https://twitter.com/IAmZerebos
|
||||||
|
* @donate https://paypal.me/ZackRauen
|
||||||
|
* @patreon https://patreon.com/Zerebos
|
||||||
|
* @website https://github.com/rauenzi/BetterDiscordAddons/tree/master/Plugins/BlurNSFW
|
||||||
|
* @source https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/BlurNSFW/BlurNSFW.plugin.js
|
||||||
|
* @updateUrl https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/BlurNSFW/BlurNSFW.plugin.js
|
||||||
|
*/
|
||||||
|
/*@cc_on
|
||||||
|
@if (@_jscript)
|
||||||
|
|
||||||
|
// Offer to self-install for clueless users that try to run this directly.
|
||||||
|
var shell = WScript.CreateObject("WScript.Shell");
|
||||||
|
var fs = new ActiveXObject("Scripting.FileSystemObject");
|
||||||
|
var pathPlugins = shell.ExpandEnvironmentStrings("%APPDATA%\\BetterDiscord\\plugins");
|
||||||
|
var pathSelf = WScript.ScriptFullName;
|
||||||
|
// Put the user at ease by addressing them in the first person
|
||||||
|
shell.Popup("It looks like you've mistakenly tried to run me directly. \n(Don't do that!)", 0, "I'm a plugin for BetterDiscord", 0x30);
|
||||||
|
if (fs.GetParentFolderName(pathSelf) === fs.GetAbsolutePathName(pathPlugins)) {
|
||||||
|
shell.Popup("I'm in the correct folder already.", 0, "I'm already installed", 0x40);
|
||||||
|
} else if (!fs.FolderExists(pathPlugins)) {
|
||||||
|
shell.Popup("I can't find the BetterDiscord plugins folder.\nAre you sure it's even installed?", 0, "Can't install myself", 0x10);
|
||||||
|
} else if (shell.Popup("Should I copy myself to BetterDiscord's plugins folder for you?", 0, "Do you need some help?", 0x34) === 6) {
|
||||||
|
fs.CopyFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf)), true);
|
||||||
|
// Show the user where to put plugins in the future
|
||||||
|
shell.Exec("explorer " + pathPlugins);
|
||||||
|
shell.Popup("I'm installed!", 0, "Successfully installed", 0x40);
|
||||||
|
}
|
||||||
|
WScript.Quit();
|
||||||
|
|
||||||
|
@else@*/
|
||||||
|
|
||||||
|
module.exports = (() => {
|
||||||
|
const config = {info:{name:"BlurNSFW",authors:[{name:"Zerebos",discord_id:"249746236008169473",github_username:"rauenzi",twitter_username:"ZackRauen"}],version:"0.2.5",description:"Blurs images in NSFW channels until you hover over it.",github:"https://github.com/rauenzi/BetterDiscordAddons/tree/master/Plugins/BlurNSFW",github_raw:"https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/BlurNSFW/BlurNSFW.plugin.js"},changelog:[{title:"New Option",items:["An option to stop blurring a picture when clicking on it/expanding it was added to settings."]}],defaultConfig:[{type:"slider",id:"blurSize",name:"Blur Size",note:"The size (in px) of the blurred pixels.",value:10,min:0,max:50,units:"px"},{type:"slider",id:"blurTime",name:"Blur Time",note:"The time (in ms) it takes for the blur to disappear and reappear.",value:200,min:0,max:5000,units:"ms"},{type:"switch",id:"blurOnFocus",name:"Blur When Focused",note:"This setting keeps the blur when clicking on/expanding an image.",value:true}],main:"index.js"};
|
||||||
|
|
||||||
|
return !global.ZeresPluginLibrary ? class {
|
||||||
|
constructor() {this._config = config;}
|
||||||
|
getName() {return config.info.name;}
|
||||||
|
getAuthor() {return config.info.authors.map(a => a.name).join(", ");}
|
||||||
|
getDescription() {return config.info.description;}
|
||||||
|
getVersion() {return config.info.version;}
|
||||||
|
load() {
|
||||||
|
BdApi.showConfirmationModal("Library Missing", `The library plugin needed for ${config.info.name} is missing. Please click Download Now to install it.`, {
|
||||||
|
confirmText: "Download Now",
|
||||||
|
cancelText: "Cancel",
|
||||||
|
onConfirm: () => {
|
||||||
|
require("request").get("https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js", async (error, response, body) => {
|
||||||
|
if (error) return require("electron").shell.openExternal("https://betterdiscord.net/ghdl?url=https://raw.githubusercontent.com/rauenzi/BDPluginLibrary/master/release/0PluginLibrary.plugin.js");
|
||||||
|
await new Promise(r => require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0PluginLibrary.plugin.js"), body, r));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
start() {}
|
||||||
|
stop() {}
|
||||||
|
} : (([Plugin, Api]) => {
|
||||||
|
const plugin = (Plugin, Api) => {
|
||||||
|
const {Patcher, WebpackModules, DiscordModules, PluginUtilities, Utilities} = Api;
|
||||||
|
|
||||||
|
const SelectedChannelStore = DiscordModules.SelectedChannelStore;
|
||||||
|
const ChannelStore = DiscordModules.ChannelStore;
|
||||||
|
const ReactDOM = DiscordModules.ReactDOM;
|
||||||
|
const InlineMediaWrapper = WebpackModules.getByProps("ImageReadyStates").default;
|
||||||
|
|
||||||
|
return class BlurNSFW extends Plugin {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.styleTemplate = `
|
||||||
|
{{blurOnFocus}}
|
||||||
|
img.blur:hover,
|
||||||
|
video.blur:hover {
|
||||||
|
transition: {{time}}ms cubic-bezier(.2, .11, 0, 1) !important;
|
||||||
|
filter: blur(0px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.blur,
|
||||||
|
video.blur {
|
||||||
|
filter: blur({{size}}px) !important;
|
||||||
|
transition: {{time}}ms cubic-bezier(.2, .11, 0, 1) !important;
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
onStart() {
|
||||||
|
const blurAccessory = (thisObject) => {
|
||||||
|
const channel = ChannelStore.getChannel(SelectedChannelStore.getChannelId());
|
||||||
|
if (!channel || !channel.isNSFW || !channel.isNSFW()) return;
|
||||||
|
const element = ReactDOM.findDOMNode(thisObject);
|
||||||
|
const mediaElement = element.querySelector("img") || element.querySelector("video");
|
||||||
|
if (!mediaElement) return;
|
||||||
|
|
||||||
|
mediaElement.classList.add("blur");
|
||||||
|
|
||||||
|
if (mediaElement.tagName !== "VIDEO") return;
|
||||||
|
mediaElement.addEventListener("play", () => {
|
||||||
|
if (mediaElement.autoplay) return;
|
||||||
|
mediaElement.classList.remove("blur");
|
||||||
|
});
|
||||||
|
mediaElement.addEventListener("pause", () => {
|
||||||
|
if (mediaElement.autoplay) return;
|
||||||
|
mediaElement.classList.add("blur");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
Patcher.after(InlineMediaWrapper.prototype, "componentDidMount", blurAccessory);
|
||||||
|
Patcher.after(InlineMediaWrapper.prototype, "componentDidUpdate", blurAccessory);
|
||||||
|
|
||||||
|
this.addStyle();
|
||||||
|
}
|
||||||
|
|
||||||
|
onStop() {
|
||||||
|
Patcher.unpatchAll();
|
||||||
|
this.removeStyle();
|
||||||
|
}
|
||||||
|
|
||||||
|
addStyle() {
|
||||||
|
const styleString = Utilities.formatString(this.styleTemplate, {
|
||||||
|
size: Math.round(this.settings.blurSize),
|
||||||
|
time: Math.round(this.settings.blurTime),
|
||||||
|
blurOnFocus: this.settings.blurOnFocus ? "" : ".layer-2KE1M9 img.blur,"
|
||||||
|
});
|
||||||
|
PluginUtilities.addStyle(this.getName(), styleString);
|
||||||
|
}
|
||||||
|
|
||||||
|
removeStyle() {
|
||||||
|
PluginUtilities.removeStyle(this.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
getSettingsPanel() {
|
||||||
|
const panel = this.buildSettingsPanel();
|
||||||
|
panel.addListener(() => {
|
||||||
|
this.removeStyle();
|
||||||
|
this.addStyle();
|
||||||
|
});
|
||||||
|
return panel.getElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
return plugin(Plugin, Api);
|
||||||
|
})(global.ZeresPluginLibrary.buildPlugin(config));
|
||||||
|
})();
|
||||||
|
/*@end@*/
|
||||||
14
.config/BetterDiscord/plugins/CreationDate.config.json
Executable file
14
.config/BetterDiscord/plugins/CreationDate.config.json
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"all": {
|
||||||
|
"dates": {
|
||||||
|
"creationDate": {}
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"displayText": true
|
||||||
|
},
|
||||||
|
"places": {
|
||||||
|
"userPopout": true,
|
||||||
|
"userProfile": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
309
.config/BetterDiscord/plugins/CreationDate.plugin.js
Executable file
309
.config/BetterDiscord/plugins/CreationDate.plugin.js
Executable file
@@ -0,0 +1,309 @@
|
|||||||
|
/**
|
||||||
|
* @name CreationDate
|
||||||
|
* @author DevilBro
|
||||||
|
* @authorId 278543574059057154
|
||||||
|
* @version 1.4.6
|
||||||
|
* @description Displays the Creation Date of an Account in the UserPopout and UserModal
|
||||||
|
* @invite Jx3TjNS
|
||||||
|
* @donate https://www.paypal.me/MircoWittrien
|
||||||
|
* @patreon https://www.patreon.com/MircoWittrien
|
||||||
|
* @website https://mwittrien.github.io/
|
||||||
|
* @source https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/CreationDate/
|
||||||
|
* @updateUrl https://mwittrien.github.io/BetterDiscordAddons/Plugins/CreationDate/CreationDate.plugin.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = (_ => {
|
||||||
|
const config = {
|
||||||
|
"info": {
|
||||||
|
"name": "CreationDate",
|
||||||
|
"author": "DevilBro",
|
||||||
|
"version": "1.4.6",
|
||||||
|
"description": "Displays the Creation Date of an Account in the UserPopout and UserModal"
|
||||||
|
},
|
||||||
|
"changeLog": {
|
||||||
|
"fixed": {
|
||||||
|
"User Popout": "Fixing Stuff for the User Popout Update, thanks Discord"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (window.Lightcord && !Node.prototype.isPrototypeOf(window.Lightcord) || window.LightCord && !Node.prototype.isPrototypeOf(window.LightCord) || window.Astra && !Node.prototype.isPrototypeOf(window.Astra)) ? class {
|
||||||
|
getName () {return config.info.name;}
|
||||||
|
getAuthor () {return config.info.author;}
|
||||||
|
getVersion () {return config.info.version;}
|
||||||
|
getDescription () {return "Do not use LightCord!";}
|
||||||
|
load () {BdApi.alert("Attention!", "By using LightCord you are risking your Discord Account, due to using a 3rd Party Client. Switch to an official Discord Client (https://discord.com/) with the proper BD Injection (https://betterdiscord.app/)");}
|
||||||
|
start() {}
|
||||||
|
stop() {}
|
||||||
|
} : !window.BDFDB_Global || (!window.BDFDB_Global.loaded && !window.BDFDB_Global.started) ? class {
|
||||||
|
getName () {return config.info.name;}
|
||||||
|
getAuthor () {return config.info.author;}
|
||||||
|
getVersion () {return config.info.version;}
|
||||||
|
getDescription () {return `The Library Plugin needed for ${config.info.name} is missing. Open the Plugin Settings to download it. \n\n${config.info.description}`;}
|
||||||
|
|
||||||
|
downloadLibrary () {
|
||||||
|
require("request").get("https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js", (e, r, b) => {
|
||||||
|
if (!e && b && r.statusCode == 200) require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0BDFDB.plugin.js"), b, _ => BdApi.showToast("Finished downloading BDFDB Library", {type: "success"}));
|
||||||
|
else BdApi.alert("Error", "Could not download BDFDB Library Plugin. Try again later or download it manually from GitHub: https://mwittrien.github.io/downloader/?library");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
load () {
|
||||||
|
if (!window.BDFDB_Global || !Array.isArray(window.BDFDB_Global.pluginQueue)) window.BDFDB_Global = Object.assign({}, window.BDFDB_Global, {pluginQueue: []});
|
||||||
|
if (!window.BDFDB_Global.downloadModal) {
|
||||||
|
window.BDFDB_Global.downloadModal = true;
|
||||||
|
BdApi.showConfirmationModal("Library Missing", `The Library Plugin needed for ${config.info.name} is missing. Please click "Download Now" to install it.`, {
|
||||||
|
confirmText: "Download Now",
|
||||||
|
cancelText: "Cancel",
|
||||||
|
onCancel: _ => {delete window.BDFDB_Global.downloadModal;},
|
||||||
|
onConfirm: _ => {
|
||||||
|
delete window.BDFDB_Global.downloadModal;
|
||||||
|
this.downloadLibrary();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!window.BDFDB_Global.pluginQueue.includes(config.info.name)) window.BDFDB_Global.pluginQueue.push(config.info.name);
|
||||||
|
}
|
||||||
|
start () {this.load();}
|
||||||
|
stop () {}
|
||||||
|
getSettingsPanel () {
|
||||||
|
let template = document.createElement("template");
|
||||||
|
template.innerHTML = `<div style="color: var(--header-primary); font-size: 16px; font-weight: 300; white-space: pre; line-height: 22px;">The Library Plugin needed for ${config.info.name} is missing.\nPlease click <a style="font-weight: 500;">Download Now</a> to install it.</div>`;
|
||||||
|
template.content.firstElementChild.querySelector("a").addEventListener("click", this.downloadLibrary);
|
||||||
|
return template.content.firstElementChild;
|
||||||
|
}
|
||||||
|
} : (([Plugin, BDFDB]) => {
|
||||||
|
return class CreationDate extends Plugin {
|
||||||
|
onLoad () {
|
||||||
|
this.defaults = {
|
||||||
|
general: {
|
||||||
|
displayText: {value: true, description: "Display '{{presuffix}}' in the Date"}
|
||||||
|
},
|
||||||
|
places: {
|
||||||
|
userPopout: {value: true, description: "User Popouts"},
|
||||||
|
userProfile: {value: true, description: "User Profile Modal"}
|
||||||
|
},
|
||||||
|
dates: {
|
||||||
|
creationDate: {value: {}, description: "Creation Date"},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.patchedModules = {
|
||||||
|
after: {
|
||||||
|
UserPopoutInfo: "UserPopoutInfo",
|
||||||
|
UserProfileModalHeader: "default"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onStart () {
|
||||||
|
BDFDB.PatchUtils.forceAllUpdates(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
onStop () {
|
||||||
|
BDFDB.PatchUtils.forceAllUpdates(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
getSettingsPanel (collapseStates = {}) {
|
||||||
|
let settingsPanel;
|
||||||
|
return settingsPanel = BDFDB.PluginUtils.createSettingsPanel(this, {
|
||||||
|
collapseStates: collapseStates,
|
||||||
|
children: _ => {
|
||||||
|
let settingsItems = [];
|
||||||
|
|
||||||
|
settingsItems.push(Object.keys(this.defaults.general).map(key => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, {
|
||||||
|
type: "Switch",
|
||||||
|
plugin: this,
|
||||||
|
keys: ["general", key],
|
||||||
|
label: key == "displayText" ? this.defaults.general[key].description.replace("{{presuffix}}", this.labels.created_at.replace("{{time}}", "").trim()) : this.defaults.general[key].description,
|
||||||
|
value: this.settings.general[key]
|
||||||
|
})));
|
||||||
|
|
||||||
|
settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormDivider, {
|
||||||
|
className: BDFDB.disCN.marginbottom8
|
||||||
|
}));
|
||||||
|
|
||||||
|
settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsPanelList, {
|
||||||
|
title: "Add Date in:",
|
||||||
|
children: Object.keys(this.defaults.places).map(key => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, {
|
||||||
|
type: "Switch",
|
||||||
|
plugin: this,
|
||||||
|
keys: ["places", key],
|
||||||
|
label: this.defaults.places[key].description,
|
||||||
|
value: this.settings.places[key]
|
||||||
|
}))
|
||||||
|
}));
|
||||||
|
|
||||||
|
settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormDivider, {
|
||||||
|
className: BDFDB.disCN.marginbottom8
|
||||||
|
}));
|
||||||
|
|
||||||
|
settingsItems.push(Object.keys(this.defaults.dates).map(key => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.DateInput, Object.assign({}, this.settings.dates[key], {
|
||||||
|
label: this.defaults.dates[key].description,
|
||||||
|
prefix: _ => (this.settings.general.displayText && this.labels.created_at.split("{{time}}")[0] || "").trim(),
|
||||||
|
suffix: _ => (this.settings.general.displayText && this.labels.created_at.split("{{time}}")[1] || "").trim(),
|
||||||
|
onChange: valueObj => {
|
||||||
|
this.SettingsUpdated = true;
|
||||||
|
this.settings.dates[key] = valueObj;
|
||||||
|
BDFDB.DataUtils.save(this.settings.dates, this, "dates");
|
||||||
|
}
|
||||||
|
}))));
|
||||||
|
|
||||||
|
return settingsItems.flat(10);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSettingsClosed () {
|
||||||
|
if (this.SettingsUpdated) {
|
||||||
|
delete this.SettingsUpdated;
|
||||||
|
BDFDB.PatchUtils.forceAllUpdates(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processUserPopoutInfo (e) {
|
||||||
|
if (e.instance.props.user && this.settings.places.userPopout) {
|
||||||
|
let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {name: ["DiscordTag", "ColoredFluxTag"]});
|
||||||
|
if (index > -1) this.injectDate(children, index + 1, e.instance.props.user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processUserProfileModalHeader (e) {
|
||||||
|
if (e.instance.props.user && this.settings.places.userProfile) {
|
||||||
|
let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {name: ["DiscordTag", "ColoredFluxTag"]});
|
||||||
|
if (index > -1) this.injectDate(children, index + 1, e.instance.props.user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
injectDate (children, index, user) {
|
||||||
|
let timestamp = BDFDB.LibraryComponents.DateInput.format(this.settings.dates.creationDate, user.createdAt);
|
||||||
|
children.splice(index, 0, BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextScroller, {
|
||||||
|
className: BDFDB.disCNS._creationdatedate + BDFDB.disCNS.userinfodate + BDFDB.disCN.textrow,
|
||||||
|
children: this.settings.general.displayText ? this.labels.created_at.replace("{{time}}", timestamp) : timestamp
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
setLabelsByLanguage () {
|
||||||
|
switch (BDFDB.LanguageUtils.getLanguage().id) {
|
||||||
|
case "bg": // Bulgarian
|
||||||
|
return {
|
||||||
|
created_at: "Създадено на {{time}}"
|
||||||
|
};
|
||||||
|
case "cs": // Czech
|
||||||
|
return {
|
||||||
|
created_at: "Vytvořeno {{time}}"
|
||||||
|
};
|
||||||
|
case "da": // Danish
|
||||||
|
return {
|
||||||
|
created_at: "Oprettet den {{time}}"
|
||||||
|
};
|
||||||
|
case "de": // German
|
||||||
|
return {
|
||||||
|
created_at: "Erstellt am {{time}}"
|
||||||
|
};
|
||||||
|
case "el": // Greek
|
||||||
|
return {
|
||||||
|
created_at: "Δημιουργήθηκε στις {{time}}"
|
||||||
|
};
|
||||||
|
case "es": // Spanish
|
||||||
|
return {
|
||||||
|
created_at: "Creado el {{time}}"
|
||||||
|
};
|
||||||
|
case "fi": // Finnish
|
||||||
|
return {
|
||||||
|
created_at: "Luotu {{time}}"
|
||||||
|
};
|
||||||
|
case "fr": // French
|
||||||
|
return {
|
||||||
|
created_at: "Créé le {{time}}"
|
||||||
|
};
|
||||||
|
case "hi": // Hindi
|
||||||
|
return {
|
||||||
|
created_at: "{{time}} को बनाया गया"
|
||||||
|
};
|
||||||
|
case "hr": // Croatian
|
||||||
|
return {
|
||||||
|
created_at: "Izrađeno {{time}}"
|
||||||
|
};
|
||||||
|
case "hu": // Hungarian
|
||||||
|
return {
|
||||||
|
created_at: "Létrehozva: {{time}}"
|
||||||
|
};
|
||||||
|
case "it": // Italian
|
||||||
|
return {
|
||||||
|
created_at: "Creato il {{time}}"
|
||||||
|
};
|
||||||
|
case "ja": // Japanese
|
||||||
|
return {
|
||||||
|
created_at: "{{time}}に作成"
|
||||||
|
};
|
||||||
|
case "ko": // Korean
|
||||||
|
return {
|
||||||
|
created_at: "{{time}}에 생성됨"
|
||||||
|
};
|
||||||
|
case "lt": // Lithuanian
|
||||||
|
return {
|
||||||
|
created_at: "Sukurta {{time}}"
|
||||||
|
};
|
||||||
|
case "nl": // Dutch
|
||||||
|
return {
|
||||||
|
created_at: "Gemaakt op {{time}}"
|
||||||
|
};
|
||||||
|
case "no": // Norwegian
|
||||||
|
return {
|
||||||
|
created_at: "Opprettet {{time}}"
|
||||||
|
};
|
||||||
|
case "pl": // Polish
|
||||||
|
return {
|
||||||
|
created_at: "Utworzono {{time}}"
|
||||||
|
};
|
||||||
|
case "pt-BR": // Portuguese (Brazil)
|
||||||
|
return {
|
||||||
|
created_at: "Criado em {{time}}"
|
||||||
|
};
|
||||||
|
case "ro": // Romanian
|
||||||
|
return {
|
||||||
|
created_at: "Creat la {{time}}"
|
||||||
|
};
|
||||||
|
case "ru": // Russian
|
||||||
|
return {
|
||||||
|
created_at: "Создано {{time}}"
|
||||||
|
};
|
||||||
|
case "sv": // Swedish
|
||||||
|
return {
|
||||||
|
created_at: "Skapad {{time}}"
|
||||||
|
};
|
||||||
|
case "th": // Thai
|
||||||
|
return {
|
||||||
|
created_at: "สร้างเมื่อ {{time}}"
|
||||||
|
};
|
||||||
|
case "tr": // Turkish
|
||||||
|
return {
|
||||||
|
created_at: "{{time}} tarihinde oluşturuldu"
|
||||||
|
};
|
||||||
|
case "uk": // Ukrainian
|
||||||
|
return {
|
||||||
|
created_at: "Створено {{time}}"
|
||||||
|
};
|
||||||
|
case "vi": // Vietnamese
|
||||||
|
return {
|
||||||
|
created_at: "Được tạo vào {{time}}"
|
||||||
|
};
|
||||||
|
case "zh-CN": // Chinese (China)
|
||||||
|
return {
|
||||||
|
created_at: "创建于{{time}}"
|
||||||
|
};
|
||||||
|
case "zh-TW": // Chinese (Taiwan)
|
||||||
|
return {
|
||||||
|
created_at: "創建於{{time}}"
|
||||||
|
};
|
||||||
|
default: // English
|
||||||
|
return {
|
||||||
|
created_at: "Created on {{time}}"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(window.BDFDB_Global.PluginUtils.buildPlugin(config));
|
||||||
|
})();
|
||||||
681
.config/BetterDiscord/plugins/EditRoles.plugin.js
Executable file
681
.config/BetterDiscord/plugins/EditRoles.plugin.js
Executable file
@@ -0,0 +1,681 @@
|
|||||||
|
/**
|
||||||
|
* @name EditRoles
|
||||||
|
* @author DevilBro
|
||||||
|
* @authorId 278543574059057154
|
||||||
|
* @version 1.0.9
|
||||||
|
* @description Allows you to locally edit Roles
|
||||||
|
* @invite Jx3TjNS
|
||||||
|
* @donate https://www.paypal.me/MircoWittrien
|
||||||
|
* @patreon https://www.patreon.com/MircoWittrien
|
||||||
|
* @website https://mwittrien.github.io/
|
||||||
|
* @source https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/EditRoles/
|
||||||
|
* @updateUrl https://mwittrien.github.io/BetterDiscordAddons/Plugins/EditRoles/EditRoles.plugin.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = (_ => {
|
||||||
|
const config = {
|
||||||
|
"info": {
|
||||||
|
"name": "EditRoles",
|
||||||
|
"author": "DevilBro",
|
||||||
|
"version": "1.0.9",
|
||||||
|
"description": "Allows you to locally edit Roles"
|
||||||
|
},
|
||||||
|
"changeLog": {
|
||||||
|
"fixed": {
|
||||||
|
"Remove Icon": "Now works again"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return !window.BDFDB_Global || (!window.BDFDB_Global.loaded && !window.BDFDB_Global.started) ? class {
|
||||||
|
getName () {return config.info.name;}
|
||||||
|
getAuthor () {return config.info.author;}
|
||||||
|
getVersion () {return config.info.version;}
|
||||||
|
getDescription () {return `The Library Plugin needed for ${config.info.name} is missing. Open the Plugin Settings to download it. \n\n${config.info.description}`;}
|
||||||
|
|
||||||
|
downloadLibrary () {
|
||||||
|
require("request").get("https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js", (e, r, b) => {
|
||||||
|
if (!e && b && r.statusCode == 200) require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0BDFDB.plugin.js"), b, _ => BdApi.showToast("Finished downloading BDFDB Library", {type: "success"}));
|
||||||
|
else BdApi.alert("Error", "Could not download BDFDB Library Plugin. Try again later or download it manually from GitHub: https://mwittrien.github.io/downloader/?library");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
load () {
|
||||||
|
if (!window.BDFDB_Global || !Array.isArray(window.BDFDB_Global.pluginQueue)) window.BDFDB_Global = Object.assign({}, window.BDFDB_Global, {pluginQueue: []});
|
||||||
|
if (!window.BDFDB_Global.downloadModal) {
|
||||||
|
window.BDFDB_Global.downloadModal = true;
|
||||||
|
BdApi.showConfirmationModal("Library Missing", `The Library Plugin needed for ${config.info.name} is missing. Please click "Download Now" to install it.`, {
|
||||||
|
confirmText: "Download Now",
|
||||||
|
cancelText: "Cancel",
|
||||||
|
onCancel: _ => {delete window.BDFDB_Global.downloadModal;},
|
||||||
|
onConfirm: _ => {
|
||||||
|
delete window.BDFDB_Global.downloadModal;
|
||||||
|
this.downloadLibrary();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!window.BDFDB_Global.pluginQueue.includes(config.info.name)) window.BDFDB_Global.pluginQueue.push(config.info.name);
|
||||||
|
}
|
||||||
|
start () {this.load();}
|
||||||
|
stop () {}
|
||||||
|
getSettingsPanel () {
|
||||||
|
let template = document.createElement("template");
|
||||||
|
template.innerHTML = `<div style="color: var(--header-primary); font-size: 16px; font-weight: 300; white-space: pre; line-height: 22px;">The Library Plugin needed for ${config.info.name} is missing.\nPlease click <a style="font-weight: 500;">Download Now</a> to install it.</div>`;
|
||||||
|
template.content.firstElementChild.querySelector("a").addEventListener("click", this.downloadLibrary);
|
||||||
|
return template.content.firstElementChild;
|
||||||
|
}
|
||||||
|
} : (([Plugin, BDFDB]) => {
|
||||||
|
var changedRoles = {}, cachedRoles = {};
|
||||||
|
|
||||||
|
return class EditRoles extends Plugin {
|
||||||
|
onLoad () {
|
||||||
|
this.patchedModules = {
|
||||||
|
before: {
|
||||||
|
MessageHeader: "default",
|
||||||
|
ChannelMembers: "render",
|
||||||
|
MemberListItem: "render",
|
||||||
|
UserPopoutBody: "default"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
onStart () {
|
||||||
|
BDFDB.PatchUtils.patch(this, BDFDB.LibraryModules.GuildStore, "getGuild", {after: e => {
|
||||||
|
if (e.returnValue) e.returnValue = this.changeRolesInGuild(e.returnValue, true);
|
||||||
|
}});
|
||||||
|
BDFDB.PatchUtils.patch(this, BDFDB.LibraryModules.PermissionRoleUtils, "getHighestRole", {after: e => {
|
||||||
|
if (e.returnValue && changedRoles[e.returnValue.id]) {
|
||||||
|
let data = changedRoles[e.returnValue.id];
|
||||||
|
e.returnValue = Object.assign({}, e.returnValue, {
|
||||||
|
name: data.name || e.returnValue.name,
|
||||||
|
color: data.color ? BDFDB.ColorUtils.convert(data.color, "INT") : e.returnValue.color,
|
||||||
|
colorString: data.color ? BDFDB.ColorUtils.convert(data.color, "HEX") : e.returnValue.colorString
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
BDFDB.PatchUtils.patch(this, BDFDB.LibraryModules.MemberStore, "getMember", {after: e => {
|
||||||
|
if (e.returnValue) {
|
||||||
|
let guild = BDFDB.LibraryModules.GuildStore.getGuild(e.methodArguments[0]);
|
||||||
|
if (guild) {
|
||||||
|
let colorRole, iconRole;
|
||||||
|
for (let id of e.returnValue.roles) {
|
||||||
|
if (guild.roles[id] && guild.roles[id].colorString && (!colorRole || colorRole.position < guild.roles[id].position)) colorRole = guild.roles[id];
|
||||||
|
if (guild.roles[id] && guild.roles[id].icon && (!iconRole || iconRole.position < guild.roles[id].position)) iconRole = guild.roles[id];
|
||||||
|
}
|
||||||
|
let color = colorRole && changedRoles[colorRole.id] && changedRoles[colorRole.id].color;
|
||||||
|
if (color) e.returnValue = Object.assign({}, e.returnValue, {colorString: BDFDB.ColorUtils.convert(color, "HEX")});
|
||||||
|
if (iconRole && changedRoles[iconRole.id] && changedRoles[iconRole.id].icon) e.returnValue = Object.assign({}, e.returnValue, {iconRoleId: iconRole.id});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
BDFDB.PatchUtils.patch(this, BDFDB.LibraryModules.RoleIconUtils, "getRoleIconData", {after: e => {
|
||||||
|
if (e.returnValue && e.methodArguments[0].id && changedRoles[e.methodArguments[0].id]) {
|
||||||
|
if (changedRoles[e.methodArguments[0].id].icon) return {customIconSrc: changedRoles[e.methodArguments[0].id].icon};
|
||||||
|
else if (changedRoles[e.methodArguments[0].id].removeIcon) return {customIconSrc: null};
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
BDFDB.PatchUtils.patch(this, BDFDB.LibraryModules.RoleIconUtils, "canGuildUseRoleIcons", {after: e => {
|
||||||
|
if (e.returnValue === false && Object.keys(e.methodArguments[0].roles).some(roleId => changedRoles[roleId] && changedRoles[roleId].icon)) return true;
|
||||||
|
}});
|
||||||
|
|
||||||
|
this.forceUpdateAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
onStop () {
|
||||||
|
this.forceUpdateAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
getSettingsPanel (collapseStates = {}) {
|
||||||
|
let settingsPanel;
|
||||||
|
return settingsPanel = BDFDB.PluginUtils.createSettingsPanel(this, {
|
||||||
|
collapseStates: collapseStates,
|
||||||
|
children: _ => {
|
||||||
|
let settingsItems = [];
|
||||||
|
|
||||||
|
settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, {
|
||||||
|
type: "Button",
|
||||||
|
color: BDFDB.LibraryComponents.Button.Colors.RED,
|
||||||
|
label: "Reset all Roles",
|
||||||
|
onClick: _ => {
|
||||||
|
BDFDB.ModalUtils.confirm(this, this.labels.confirm_resetall, _ => {
|
||||||
|
this.resetRoles();
|
||||||
|
this.forceUpdateAll();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
children: BDFDB.LanguageUtils.LanguageStrings.RESET
|
||||||
|
}));
|
||||||
|
|
||||||
|
return settingsItems.flat(10);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSettingsClosed () {
|
||||||
|
if (this.SettingsUpdated) {
|
||||||
|
delete this.SettingsUpdated;
|
||||||
|
this.forceUpdateAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
forceUpdateAll () {
|
||||||
|
changedRoles = BDFDB.DataUtils.load(this, "roles");
|
||||||
|
|
||||||
|
BDFDB.PatchUtils.forceAllUpdates(this);
|
||||||
|
BDFDB.MessageUtils.rerenderAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
onUserContextMenu (e) {
|
||||||
|
if (e.subType == "useUserRolesItems") {
|
||||||
|
let [children, index] = BDFDB.ContextMenuUtils.findItem(e.returnvalue, {id: "roles"});
|
||||||
|
if (index > -1 && children[index].props && BDFDB.ArrayUtils.is(children[index].props.children)) for (let child of children[index].props.children) {
|
||||||
|
if (child && child.props && typeof child.props.label == "function") {
|
||||||
|
let renderLabel = child.props.label;
|
||||||
|
child.props.label = (...args) => {
|
||||||
|
let label = renderLabel(...args);
|
||||||
|
let onContextMenu = typeof label.props.onContextMenu == "function" ? label.props.onContextMenu : (_ => {});
|
||||||
|
label.props.onContextMenu = event => BDFDB.LibraryModules.ContextMenuUtils.openContextMenu(event, e => BDFDB.ReactUtils.createElement(BDFDB.ModuleUtils.findByName("DeveloperContextMenu"), Object.assign({}, e2, {id: child.props.id})));
|
||||||
|
return label;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onGuildContextMenu (e) {
|
||||||
|
if (e.instance.props.guild) e.instance.props.guild = this.changeRolesInGuild(e.instance.props.guild);
|
||||||
|
}
|
||||||
|
|
||||||
|
onDeveloperContextMenu (e) {
|
||||||
|
let guild = this.getGuildFromRoleId(e.instance.props.id);
|
||||||
|
if (guild) e.returnvalue.props.children = [
|
||||||
|
BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuGroup, {
|
||||||
|
children: BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, {
|
||||||
|
label: this.labels.context_localrolesettings,
|
||||||
|
id: BDFDB.ContextMenuUtils.createItemId(this.name, "settings-submenu"),
|
||||||
|
children: BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuGroup, {
|
||||||
|
children: [
|
||||||
|
BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, {
|
||||||
|
label: this.labels.submenu_rolesettings,
|
||||||
|
id: BDFDB.ContextMenuUtils.createItemId(this.name, "settings-change"),
|
||||||
|
action: _ => {
|
||||||
|
this.openRoleSettingsModal(guild.roles[e.instance.props.id]);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, {
|
||||||
|
label: this.labels.submenu_resetsettings,
|
||||||
|
id: BDFDB.ContextMenuUtils.createItemId(this.name, "settings-reset"),
|
||||||
|
color: BDFDB.LibraryComponents.MenuItems.Colors.DANGER,
|
||||||
|
disabled: !changedRoles[e.instance.props.id],
|
||||||
|
action: event => {
|
||||||
|
let remove = _ => {
|
||||||
|
this.resetRoles(e.instance.props.id);
|
||||||
|
this.forceUpdateAll(true);
|
||||||
|
};
|
||||||
|
if (event.shiftKey) remove();
|
||||||
|
else BDFDB.ModalUtils.confirm(this, this.labels.confirm_reset, remove);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
e.returnvalue.props.children
|
||||||
|
].flat(10).filter(n => n);
|
||||||
|
}
|
||||||
|
|
||||||
|
processChannelMembers (e) {
|
||||||
|
e.instance.props.groups = [].concat(e.instance.props.groups);
|
||||||
|
for (let i in e.instance.props.groups) if (e.instance.props.groups[i].type == "GROUP") {
|
||||||
|
let data = changedRoles[e.instance.props.groups[i].id];
|
||||||
|
if (data && data.name) e.instance.props.groups[i] = Object.assign({}, e.instance.props.groups[i], {title: data.name});
|
||||||
|
}
|
||||||
|
e.instance.props.rows = [].concat(e.instance.props.rows);
|
||||||
|
for (let i in e.instance.props.rows) if (e.instance.props.rows[i].type == "GROUP") {
|
||||||
|
let data = changedRoles[e.instance.props.rows[i].id];
|
||||||
|
if (data && data.name) e.instance.props.rows[i] = Object.assign({}, e.instance.props.rows[i], {title: data.name});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processMemberListItem (e) {
|
||||||
|
if (e.instance.props.user) {
|
||||||
|
let member = BDFDB.LibraryModules.MemberStore.getMember(e.instance.props.guildId, e.instance.props.user.id);
|
||||||
|
if (member) e.instance.props.colorString = member.colorString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
processUserPopoutBody (e) {
|
||||||
|
if (e.instance.props.guild) e.instance.props.guild = this.changeRolesInGuild(e.instance.props.guild);
|
||||||
|
}
|
||||||
|
|
||||||
|
getGuildFromRoleId (roleId) {
|
||||||
|
return BDFDB.LibraryModules.FolderStore.getFlattenedGuilds().find(g => g.roles[roleId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
changeRolesInGuild (guild, useNative) {
|
||||||
|
let changed = false, roles = Object.assign({}, guild.roles);
|
||||||
|
for (let id in guild.roles) {
|
||||||
|
let data = changedRoles[id];
|
||||||
|
if (data) {
|
||||||
|
changed = true;
|
||||||
|
roles[id] = Object.assign({}, roles[id], {
|
||||||
|
name: data.name || roles[id].name,
|
||||||
|
icon: data.icon || roles[id].icon,
|
||||||
|
color: data.color ? BDFDB.ColorUtils.convert(data.color, "INT") : roles[id].color,
|
||||||
|
colorString: data.color ? BDFDB.ColorUtils.convert(data.color, "HEX") : roles[id].colorString
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (useNative && changed && !cachedRoles[guild.id]) cachedRoles[guild.id] = guild.roles;
|
||||||
|
if (useNative) guild.roles = roles;
|
||||||
|
return !changed || useNative ? guild : (new BDFDB.DiscordObjects.Guild(Object.assign({}, guild, {roles})));
|
||||||
|
}
|
||||||
|
|
||||||
|
resetRoles (id) {
|
||||||
|
if (id) {
|
||||||
|
let guild = this.getGuildFromRoleId(id);
|
||||||
|
if (guild && cachedRoles[guild.id]) guild.roles = Object.assign({}, guild.roles, {[id]: cachedRoles[guild.id][id]});
|
||||||
|
BDFDB.DataUtils.remove(this, "roles", id);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (let guild of BDFDB.LibraryModules.FolderStore.getFlattenedGuilds()) if (cachedRoles[guild.id]) guild.roles = cachedRoles[guild.id];
|
||||||
|
cachedRoles = {};
|
||||||
|
BDFDB.DataUtils.remove(this, "roles");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
openRoleSettingsModal (role) {
|
||||||
|
let data = changedRoles[role.id] || {};
|
||||||
|
let newData = Object.assign({}, data);
|
||||||
|
|
||||||
|
let iconInput;
|
||||||
|
|
||||||
|
BDFDB.ModalUtils.open(this, {
|
||||||
|
size: "MEDIUM",
|
||||||
|
header: this.labels.modal_header,
|
||||||
|
subHeader: role.name,
|
||||||
|
children: [
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, {
|
||||||
|
title: BDFDB.LanguageUtils.LanguageStrings.FORM_LABEL_ROLE_NAME,
|
||||||
|
className: BDFDB.disCN.marginbottom20,
|
||||||
|
children: [
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, {
|
||||||
|
value: data.name,
|
||||||
|
placeholder: role.name,
|
||||||
|
autoFocus: true,
|
||||||
|
onChange: value => newData.name = value
|
||||||
|
}),
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormDivider, {
|
||||||
|
className: BDFDB.disCN.dividerdefault
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, {
|
||||||
|
title: BDFDB.LanguageUtils.LanguageStrings.FORM_LABEL_ROLE_COLOR,
|
||||||
|
className: BDFDB.disCN.marginbottom20,
|
||||||
|
children: [
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.ColorSwatches, {
|
||||||
|
color: data.color,
|
||||||
|
defaultCustomColor: role.colorString,
|
||||||
|
pickerConfig: {
|
||||||
|
alpha: false,
|
||||||
|
gradient: false
|
||||||
|
},
|
||||||
|
onColorChange: value => newData.color = value
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
BDFDB.ReactUtils.createElement("div", {
|
||||||
|
className: BDFDB.disCN.marginbottom20,
|
||||||
|
children: [
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormDivider, {
|
||||||
|
className: BDFDB.disCNS.dividerdefault + BDFDB.disCN.marginbottom20
|
||||||
|
}),
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, {
|
||||||
|
className: BDFDB.disCN.marginbottom8,
|
||||||
|
align: BDFDB.LibraryComponents.Flex.Align.CENTER,
|
||||||
|
direction: BDFDB.LibraryComponents.Flex.Direction.HORIZONTAL,
|
||||||
|
children: [
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormTitle, {
|
||||||
|
className: BDFDB.disCN.marginreset,
|
||||||
|
tag: BDFDB.LibraryComponents.FormComponents.FormTitle.Tags.H5,
|
||||||
|
children: BDFDB.LibraryModules.LanguageStore.Messages.FORM_LABEL_ROLE_ICON
|
||||||
|
}),
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, {
|
||||||
|
type: "Switch",
|
||||||
|
margin: 0,
|
||||||
|
grow: 0,
|
||||||
|
label: BDFDB.LanguageUtils.LanguageStrings.REMOVE,
|
||||||
|
tag: BDFDB.LibraryComponents.FormComponents.FormTitle.Tags.H5,
|
||||||
|
value: data.removeIcon,
|
||||||
|
onChange: value => {
|
||||||
|
newData.removeIcon = value;
|
||||||
|
if (value) {
|
||||||
|
delete iconInput.props.success;
|
||||||
|
delete iconInput.props.errorMessage;
|
||||||
|
iconInput.props.disabled = true;
|
||||||
|
BDFDB.ReactUtils.forceUpdate(iconInput);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
iconInput.props.disabled = false;
|
||||||
|
this.checkUrl(iconInput.props.value, iconInput).then(returnValue => newData.icon = returnValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, {
|
||||||
|
success: !data.removeIcon && data.icon,
|
||||||
|
maxLength: 100000000000000000000,
|
||||||
|
value: data.icon,
|
||||||
|
placeholder: role.icon,
|
||||||
|
disabled: data.removeIcon,
|
||||||
|
ref: instance => {if (instance) iconInput = instance;},
|
||||||
|
onChange: (value, instance) => {
|
||||||
|
this.checkUrl(value, instance).then(returnValue => newData.icon = returnValue);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
],
|
||||||
|
buttons: [{
|
||||||
|
contents: BDFDB.LanguageUtils.LanguageStrings.SAVE,
|
||||||
|
color: "BRAND",
|
||||||
|
close: true,
|
||||||
|
onClick: _ => {
|
||||||
|
let changed = false;
|
||||||
|
if (Object.keys(newData).every(key => newData[key] == null || newData[key] == false) && (changed = true)) {
|
||||||
|
this.resetRoles(role.id);
|
||||||
|
}
|
||||||
|
else if (!BDFDB.equals(newData, data) && (changed = true)) {
|
||||||
|
BDFDB.DataUtils.save(newData, this, "roles", role.id);
|
||||||
|
}
|
||||||
|
if (changed) this.forceUpdateAll();
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
checkUrl (url, instance) {
|
||||||
|
return new Promise(callback => {
|
||||||
|
BDFDB.TimeUtils.clear(instance.checkTimeout);
|
||||||
|
url = url && url.trim();
|
||||||
|
if (!url || instance.props.disabled) {
|
||||||
|
delete instance.props.success;
|
||||||
|
delete instance.props.errorMessage;
|
||||||
|
callback("");
|
||||||
|
BDFDB.ReactUtils.forceUpdate(instance);
|
||||||
|
}
|
||||||
|
else instance.checkTimeout = BDFDB.TimeUtils.timeout(_ => {
|
||||||
|
BDFDB.LibraryRequires.request(url, {agentOptions: {rejectUnauthorized: false}}, (error, response, result) => {
|
||||||
|
delete instance.checkTimeout;
|
||||||
|
if (instance.props.disabled) {
|
||||||
|
delete instance.props.success;
|
||||||
|
delete instance.props.errorMessage;
|
||||||
|
callback("");
|
||||||
|
}
|
||||||
|
else if (response && response.headers["content-type"] && response.headers["content-type"].indexOf("image") != -1) {
|
||||||
|
instance.props.success = true;
|
||||||
|
delete instance.props.errorMessage;
|
||||||
|
callback(url);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
delete instance.props.success;
|
||||||
|
instance.props.errorMessage = this.labels.modal_invalidurl;
|
||||||
|
callback("");
|
||||||
|
}
|
||||||
|
BDFDB.ReactUtils.forceUpdate(instance);
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setLabelsByLanguage () {
|
||||||
|
switch (BDFDB.LanguageUtils.getLanguage().id) {
|
||||||
|
case "bg": // Bulgarian
|
||||||
|
return {
|
||||||
|
confirm_reset: "Наистина ли искате да нулирате тази роля?",
|
||||||
|
confirm_resetall: "Наистина ли искате да нулирате всички роли?",
|
||||||
|
context_localrolesettings: "Настройки на местната роля",
|
||||||
|
modal_header: "Настройки на местната роля",
|
||||||
|
submenu_resetsettings: "Нулиране на ролята",
|
||||||
|
submenu_rolesettings: "Промяна на настройките"
|
||||||
|
};
|
||||||
|
case "da": // Danish
|
||||||
|
return {
|
||||||
|
confirm_reset: "Er du sikker på, at du vil nulstille denne rolle?",
|
||||||
|
confirm_resetall: "Er du sikker på, at du vil nulstille alle roller?",
|
||||||
|
context_localrolesettings: "Lokale rolleindstillinger",
|
||||||
|
modal_header: "Lokale rolleindstillinger",
|
||||||
|
submenu_resetsettings: "Nulstil rolle",
|
||||||
|
submenu_rolesettings: "Ændre indstillinger"
|
||||||
|
};
|
||||||
|
case "de": // German
|
||||||
|
return {
|
||||||
|
confirm_reset: "Möchtest du diese Rolle wirklich zurücksetzen?",
|
||||||
|
confirm_resetall: "Möchtest du wirklich alle Rollen zurücksetzen?",
|
||||||
|
context_localrolesettings: "Lokale Rolleneinstellungen",
|
||||||
|
modal_header: "Lokale Rolleneinstellungen",
|
||||||
|
submenu_resetsettings: "Rolle zurücksetzen",
|
||||||
|
submenu_rolesettings: "Einstellungen ändern"
|
||||||
|
};
|
||||||
|
case "el": // Greek
|
||||||
|
return {
|
||||||
|
confirm_reset: "Είστε βέβαιοι ότι θέλετε να επαναφέρετε αυτόν τον ρόλο;",
|
||||||
|
confirm_resetall: "Είστε βέβαιοι ότι θέλετε να επαναφέρετε όλους τους ρόλους;",
|
||||||
|
context_localrolesettings: "Ρυθμίσεις τοπικού ρόλου",
|
||||||
|
modal_header: "Ρυθμίσεις τοπικού ρόλου",
|
||||||
|
submenu_resetsettings: "Επαναφορά ρόλου",
|
||||||
|
submenu_rolesettings: "Αλλαξε ρυθμίσεις"
|
||||||
|
};
|
||||||
|
case "es": // Spanish
|
||||||
|
return {
|
||||||
|
confirm_reset: "¿Está seguro de que desea restablecer este rol?",
|
||||||
|
confirm_resetall: "¿Está seguro de que desea restablecer todos los roles?",
|
||||||
|
context_localrolesettings: "Configuración de roles locales",
|
||||||
|
modal_header: "Configuración de roles locales",
|
||||||
|
submenu_resetsettings: "Restablecer rol",
|
||||||
|
submenu_rolesettings: "Cambiar ajustes"
|
||||||
|
};
|
||||||
|
case "fi": // Finnish
|
||||||
|
return {
|
||||||
|
confirm_reset: "Haluatko varmasti nollata tämän roolin?",
|
||||||
|
confirm_resetall: "Haluatko varmasti nollata kaikki roolit?",
|
||||||
|
context_localrolesettings: "Paikalliset rooliasetukset",
|
||||||
|
modal_header: "Paikalliset rooliasetukset",
|
||||||
|
submenu_resetsettings: "Nollaa rooli",
|
||||||
|
submenu_rolesettings: "Vaihda asetuksia"
|
||||||
|
};
|
||||||
|
case "fr": // French
|
||||||
|
return {
|
||||||
|
confirm_reset: "Voulez-vous vraiment réinitialiser ce rôle?",
|
||||||
|
confirm_resetall: "Voulez-vous vraiment réinitialiser tous les rôles?",
|
||||||
|
context_localrolesettings: "Paramètres de rôle locaux",
|
||||||
|
modal_header: "Paramètres de rôle locaux",
|
||||||
|
submenu_resetsettings: "Réinitialiser le rôle",
|
||||||
|
submenu_rolesettings: "Modifier les paramètres"
|
||||||
|
};
|
||||||
|
case "hr": // Croatian
|
||||||
|
return {
|
||||||
|
confirm_reset: "Jeste li sigurni da želite resetirati ovu ulogu?",
|
||||||
|
confirm_resetall: "Jeste li sigurni da želite resetirati sve uloge?",
|
||||||
|
context_localrolesettings: "Postavke lokalne uloge",
|
||||||
|
modal_header: "Postavke lokalne uloge",
|
||||||
|
submenu_resetsettings: "Resetiraj ulogu",
|
||||||
|
submenu_rolesettings: "Promijeniti postavke"
|
||||||
|
};
|
||||||
|
case "hu": // Hungarian
|
||||||
|
return {
|
||||||
|
confirm_reset: "Biztosan vissza akarja állítani ezt a szerepet?",
|
||||||
|
confirm_resetall: "Biztosan vissza akarja állítani az összes szerepet?",
|
||||||
|
context_localrolesettings: "Helyi szerepbeállítások",
|
||||||
|
modal_header: "Helyi szerepbeállítások",
|
||||||
|
submenu_resetsettings: "A szerepkör visszaállítása",
|
||||||
|
submenu_rolesettings: "Beállítások megváltoztatása"
|
||||||
|
};
|
||||||
|
case "it": // Italian
|
||||||
|
return {
|
||||||
|
confirm_reset: "Sei sicuro di voler reimpostare questo ruolo?",
|
||||||
|
confirm_resetall: "Sei sicuro di voler reimpostare tutti i ruoli?",
|
||||||
|
context_localrolesettings: "Impostazioni ruolo locale",
|
||||||
|
modal_header: "Impostazioni ruolo locale",
|
||||||
|
submenu_resetsettings: "Reimposta ruolo",
|
||||||
|
submenu_rolesettings: "Cambia impostazioni"
|
||||||
|
};
|
||||||
|
case "ja": // Japanese
|
||||||
|
return {
|
||||||
|
confirm_reset: "この役割をリセットしてもよろしいですか?",
|
||||||
|
confirm_resetall: "すべての役割をリセットしてもよろしいですか?",
|
||||||
|
context_localrolesettings: "ローカルロール設定",
|
||||||
|
modal_header: "ローカルロール設定",
|
||||||
|
submenu_resetsettings: "役割をリセット",
|
||||||
|
submenu_rolesettings: "設定を変更する"
|
||||||
|
};
|
||||||
|
case "ko": // Korean
|
||||||
|
return {
|
||||||
|
confirm_reset: "이 역할을 재설정 하시겠습니까?",
|
||||||
|
confirm_resetall: "모든 역할을 재설정 하시겠습니까?",
|
||||||
|
context_localrolesettings: "로컬 역할 설정",
|
||||||
|
modal_header: "로컬 역할 설정",
|
||||||
|
submenu_resetsettings: "역할 재설정",
|
||||||
|
submenu_rolesettings: "설정 변경"
|
||||||
|
};
|
||||||
|
case "lt": // Lithuanian
|
||||||
|
return {
|
||||||
|
confirm_reset: "Ar tikrai norite iš naujo nustatyti šį vaidmenį?",
|
||||||
|
confirm_resetall: "Ar tikrai norite iš naujo nustatyti visus vaidmenis?",
|
||||||
|
context_localrolesettings: "Vietos vaidmens nustatymai",
|
||||||
|
modal_header: "Vietos vaidmens nustatymai",
|
||||||
|
submenu_resetsettings: "Iš naujo nustatyti vaidmenį",
|
||||||
|
submenu_rolesettings: "Pakeisti nustatymus"
|
||||||
|
};
|
||||||
|
case "nl": // Dutch
|
||||||
|
return {
|
||||||
|
confirm_reset: "Weet u zeker dat u deze rol wilt resetten?",
|
||||||
|
confirm_resetall: "Weet u zeker dat u alle rollen opnieuw wilt instellen?",
|
||||||
|
context_localrolesettings: "Lokale rolinstellingen",
|
||||||
|
modal_header: "Lokale rolinstellingen",
|
||||||
|
submenu_resetsettings: "Rol opnieuw instellen",
|
||||||
|
submenu_rolesettings: "Instellingen veranderen"
|
||||||
|
};
|
||||||
|
case "no": // Norwegian
|
||||||
|
return {
|
||||||
|
confirm_reset: "Er du sikker på at du vil tilbakestille denne rollen?",
|
||||||
|
confirm_resetall: "Er du sikker på at du vil tilbakestille alle rollene?",
|
||||||
|
context_localrolesettings: "Lokale rolleinnstillinger",
|
||||||
|
modal_header: "Lokale rolleinnstillinger",
|
||||||
|
submenu_resetsettings: "Tilbakestill rolle",
|
||||||
|
submenu_rolesettings: "Endre innstillinger"
|
||||||
|
};
|
||||||
|
case "pl": // Polish
|
||||||
|
return {
|
||||||
|
confirm_reset: "Czy na pewno chcesz zresetować tę rolę?",
|
||||||
|
confirm_resetall: "Czy na pewno chcesz zresetować wszystkie role?",
|
||||||
|
context_localrolesettings: "Ustawienia roli lokalnej",
|
||||||
|
modal_header: "Ustawienia roli lokalnej",
|
||||||
|
submenu_resetsettings: "Zresetuj rolę",
|
||||||
|
submenu_rolesettings: "Zmień ustawienia"
|
||||||
|
};
|
||||||
|
case "pt-BR": // Portuguese (Brazil)
|
||||||
|
return {
|
||||||
|
confirm_reset: "Tem certeza de que deseja redefinir esta função?",
|
||||||
|
confirm_resetall: "Tem certeza de que deseja redefinir todas as funções?",
|
||||||
|
context_localrolesettings: "Configurações de função local",
|
||||||
|
modal_header: "Configurações de função local",
|
||||||
|
submenu_resetsettings: "Redefinir função",
|
||||||
|
submenu_rolesettings: "Mudar configurações"
|
||||||
|
};
|
||||||
|
case "ro": // Romanian
|
||||||
|
return {
|
||||||
|
confirm_reset: "Sigur doriți să resetați acest rol?",
|
||||||
|
confirm_resetall: "Sigur doriți să resetați toate rolurile?",
|
||||||
|
context_localrolesettings: "Setări rol local",
|
||||||
|
modal_header: "Setări rol local",
|
||||||
|
submenu_resetsettings: "Resetați rolul",
|
||||||
|
submenu_rolesettings: "Schimbă setările"
|
||||||
|
};
|
||||||
|
case "ru": // Russian
|
||||||
|
return {
|
||||||
|
confirm_reset: "Вы уверены, что хотите сбросить эту роль?",
|
||||||
|
confirm_resetall: "Вы уверены, что хотите сбросить все роли?",
|
||||||
|
context_localrolesettings: "Настройки локальной роли",
|
||||||
|
modal_header: "Настройки локальной роли",
|
||||||
|
submenu_resetsettings: "Сбросить роль",
|
||||||
|
submenu_rolesettings: "Изменить настройки"
|
||||||
|
};
|
||||||
|
case "sv": // Swedish
|
||||||
|
return {
|
||||||
|
confirm_reset: "Är du säker på att du vill återställa denna roll?",
|
||||||
|
confirm_resetall: "Är du säker på att du vill återställa alla roller?",
|
||||||
|
context_localrolesettings: "Lokala rollinställningar",
|
||||||
|
modal_header: "Lokala rollinställningar",
|
||||||
|
submenu_resetsettings: "Återställ roll",
|
||||||
|
submenu_rolesettings: "Ändra inställningar"
|
||||||
|
};
|
||||||
|
case "th": // Thai
|
||||||
|
return {
|
||||||
|
confirm_reset: "แน่ใจไหมว่าต้องการรีเซ็ตบทบาทนี้",
|
||||||
|
confirm_resetall: "แน่ใจไหมว่าต้องการรีเซ็ตบทบาททั้งหมด",
|
||||||
|
context_localrolesettings: "การตั้งค่าบทบาทท้องถิ่น",
|
||||||
|
modal_header: "การตั้งค่าบทบาทท้องถิ่น",
|
||||||
|
submenu_resetsettings: "รีเซ็ตบทบาท",
|
||||||
|
submenu_rolesettings: "เปลี่ยนการตั้งค่า"
|
||||||
|
};
|
||||||
|
case "tr": // Turkish
|
||||||
|
return {
|
||||||
|
confirm_reset: "Bu Rolü sıfırlamak istediğinizden emin misiniz?",
|
||||||
|
confirm_resetall: "Tüm Rolleri sıfırlamak istediğinizden emin misiniz?",
|
||||||
|
context_localrolesettings: "Yerel Rol Ayarları",
|
||||||
|
modal_header: "Yerel Rol Ayarları",
|
||||||
|
submenu_resetsettings: "Rolü Sıfırla",
|
||||||
|
submenu_rolesettings: "Ayarları değiştir"
|
||||||
|
};
|
||||||
|
case "uk": // Ukrainian
|
||||||
|
return {
|
||||||
|
confirm_reset: "Ви впевнені, що хочете скинути цю роль?",
|
||||||
|
confirm_resetall: "Ви впевнені, що хочете скинути всі ролі?",
|
||||||
|
context_localrolesettings: "Налаштування локальної ролі",
|
||||||
|
modal_header: "Налаштування локальної ролі",
|
||||||
|
submenu_resetsettings: "Скинути роль",
|
||||||
|
submenu_rolesettings: "Змінити налаштування"
|
||||||
|
};
|
||||||
|
case "vi": // Vietnamese
|
||||||
|
return {
|
||||||
|
confirm_reset: "Bạn có chắc chắn muốn đặt lại Vai trò này không?",
|
||||||
|
confirm_resetall: "Bạn có chắc chắn muốn đặt lại tất cả các Vai trò không?",
|
||||||
|
context_localrolesettings: "Cài đặt vai trò cục bộ",
|
||||||
|
modal_header: "Cài đặt vai trò cục bộ",
|
||||||
|
submenu_resetsettings: "Đặt lại vai trò",
|
||||||
|
submenu_rolesettings: "Thay đổi cài đặt"
|
||||||
|
};
|
||||||
|
case "zh-CN": // Chinese (China)
|
||||||
|
return {
|
||||||
|
confirm_reset: "您确定要重置此角色吗?",
|
||||||
|
confirm_resetall: "您确定要重置所有角色吗?",
|
||||||
|
context_localrolesettings: "本地角色设置",
|
||||||
|
modal_header: "本地角色设置",
|
||||||
|
submenu_resetsettings: "重置角色",
|
||||||
|
submenu_rolesettings: "更改设置"
|
||||||
|
};
|
||||||
|
case "zh-TW": // Chinese (Taiwan)
|
||||||
|
return {
|
||||||
|
confirm_reset: "您確定要重置此角色嗎?",
|
||||||
|
confirm_resetall: "您確定要重置所有角色嗎?",
|
||||||
|
context_localrolesettings: "本地角色設置",
|
||||||
|
modal_header: "本地角色設置",
|
||||||
|
submenu_resetsettings: "重置角色",
|
||||||
|
submenu_rolesettings: "更改設置"
|
||||||
|
};
|
||||||
|
default: // English
|
||||||
|
return {
|
||||||
|
confirm_reset: "Are you sure you want to reset this Role?",
|
||||||
|
confirm_resetall: "Are you sure you want to reset all Roles?",
|
||||||
|
context_localrolesettings: "Local Role Settings",
|
||||||
|
modal_header: "Local Role Settings",
|
||||||
|
submenu_resetsettings: "Reset Role",
|
||||||
|
submenu_rolesettings: "Change Settings"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(window.BDFDB_Global.PluginUtils.buildPlugin(config));
|
||||||
|
})();
|
||||||
6
.config/BetterDiscord/plugins/Freemoji.config.json
Executable file
6
.config/BetterDiscord/plugins/Freemoji.config.json
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"currentVersionInfo": {
|
||||||
|
"version": "1.7.3",
|
||||||
|
"hasShownChangelog": true
|
||||||
|
}
|
||||||
|
}
|
||||||
374
.config/BetterDiscord/plugins/Freemoji.plugin.js
Executable file
374
.config/BetterDiscord/plugins/Freemoji.plugin.js
Executable file
@@ -0,0 +1,374 @@
|
|||||||
|
/**
|
||||||
|
* @name Freemoji
|
||||||
|
* @displayName Freemoji
|
||||||
|
* @description Send emoji external emoji and animated emoji without Nitro.
|
||||||
|
* @author Qb, An0
|
||||||
|
* @authorId 133659541198864384
|
||||||
|
* @license LGPLv3 - https://www.gnu.org/licenses/lgpl-3.0.txt
|
||||||
|
* @version 1.7.3
|
||||||
|
* @invite gj7JFa6mF8
|
||||||
|
* @source https://github.com/QbDesu/BetterDiscordAddons/blob/potato/Plugins/Freemoji
|
||||||
|
* @updateUrl https://raw.githubusercontent.com/QbDesu/BetterDiscordAddons/potato/Plugins/Freemoji/Freemoji.plugin.js
|
||||||
|
*/
|
||||||
|
/*@cc_on
|
||||||
|
@if (@_jscript)
|
||||||
|
|
||||||
|
var shell = WScript.CreateObject("WScript.Shell");
|
||||||
|
shell.Popup("It looks like you've mistakenly tried to run me directly. That's not how you install plugins. \n(So don't do that!)", 0, "I'm a plugin for BetterDiscord", 0x30);
|
||||||
|
|
||||||
|
@else@*/
|
||||||
|
|
||||||
|
module.exports = (() => {
|
||||||
|
const config = {
|
||||||
|
info: {
|
||||||
|
name: 'Freemoji',
|
||||||
|
authors: [
|
||||||
|
{
|
||||||
|
name: 'Qb',
|
||||||
|
discord_id: '133659541198864384',
|
||||||
|
github_username: 'QbDesu'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'An0',
|
||||||
|
github_username: 'An00nymushun'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
version: '1.7.3',
|
||||||
|
description: 'Send emoji external emoji and animated emoji without Nitro.',
|
||||||
|
github: 'https://github.com/QbDesu/BetterDiscordAddons/blob/potato/Plugins/Freemoji',
|
||||||
|
github_raw: 'https://raw.githubusercontent.com/QbDesu/BetterDiscordAddons/potato/Plugins/Freemoji/Freemoji.plugin.js'
|
||||||
|
},
|
||||||
|
changelog: [
|
||||||
|
{ title: 'Bug Fixes', types: 'fixed', items: ['Stopped clyde from warining your about using unavailable emoji.'] }
|
||||||
|
],
|
||||||
|
defaultConfig: [
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
id: 'sendDirectly',
|
||||||
|
name: 'Send Directly',
|
||||||
|
note: 'Send the emoji link in a message directly instead of putting it in the chat box.',
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
id: 'split',
|
||||||
|
name: 'Automatically Split Emoji Messages',
|
||||||
|
note: 'Automatically splits messages containing emoji links so there won\'t be links in the middle of your messages.',
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'slider',
|
||||||
|
id: 'emojiSize',
|
||||||
|
name: 'Emoji Size',
|
||||||
|
note: 'The size of the emoji in pixels. 48 is recommended because it is the size of regular Discord emoji.',
|
||||||
|
value: 48,
|
||||||
|
markers: [32, 40, 48, 60, 64, 80, 96],
|
||||||
|
stickToMarkers: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'dropdown',
|
||||||
|
id: 'removeGrayscale',
|
||||||
|
name: 'Remove Grayscale Filter',
|
||||||
|
note: 'Remove the grayscale filter on emoji that would normally not be usable.',
|
||||||
|
value: 'embedPerms',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'Always',
|
||||||
|
value: 'always'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'With Embed Perms',
|
||||||
|
value: 'embedPerms'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Never',
|
||||||
|
value: 'never'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'dropdown',
|
||||||
|
id: 'missingEmbedPerms',
|
||||||
|
name: 'Missing Embed Perms Behaviour',
|
||||||
|
note: 'What should happen if you select an emoji even though you have no embed permissions.',
|
||||||
|
value: 'showDialog',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'Show Confirmation Dialog',
|
||||||
|
value: 'showDialog'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Insert Anyway',
|
||||||
|
value: 'insert'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Nothing',
|
||||||
|
value: 'nothing'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'dropdown',
|
||||||
|
id: 'external',
|
||||||
|
name: 'Allow External Emoji',
|
||||||
|
note: 'Allow External Emoji for servers that have them disabled.',
|
||||||
|
value: 'showDialog',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'Don\'t Allow',
|
||||||
|
value: 'off'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Show Confirmation Dialog',
|
||||||
|
value: 'showDialog'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Allow',
|
||||||
|
value: 'allow'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
return !global.ZeresPluginLibrary ? class {
|
||||||
|
constructor() { this._config = config; }
|
||||||
|
load() {
|
||||||
|
BdApi.showConfirmationModal('Library plugin is needed',
|
||||||
|
[`The library plugin needed for ${config.info.name} is missing. Please click Download Now to install it.`], {
|
||||||
|
confirmText: 'Download',
|
||||||
|
cancelText: 'Cancel',
|
||||||
|
onConfirm: () => {
|
||||||
|
require('request').get('https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js', async (error, response, body) => {
|
||||||
|
if (error) return require('electron').shell.openExternal('https://betterdiscord.app/Download?id=9');
|
||||||
|
await new Promise(r => require('fs').writeFile(require('path').join(BdApi.Plugins.folder, '0PluginLibrary.plugin.js'), body, r));
|
||||||
|
window.location.reload();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
start() { }
|
||||||
|
stop() { }
|
||||||
|
}
|
||||||
|
: (([Plugin, Api]) => {
|
||||||
|
const plugin = (Plugin, Api) => {
|
||||||
|
const {
|
||||||
|
Patcher,
|
||||||
|
WebpackModules,
|
||||||
|
Toasts,
|
||||||
|
Logger,
|
||||||
|
DiscordModules: {
|
||||||
|
Permissions,
|
||||||
|
DiscordPermissions,
|
||||||
|
UserStore,
|
||||||
|
SelectedChannelStore,
|
||||||
|
ChannelStore,
|
||||||
|
DiscordConstants: {
|
||||||
|
EmojiDisabledReasons,
|
||||||
|
EmojiIntention
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} = Api;
|
||||||
|
|
||||||
|
const Emojis = WebpackModules.findByUniqueProperties(['getDisambiguatedEmojiContext', 'searchWithoutFetchingLatest']);
|
||||||
|
const EmojiParser = WebpackModules.findByUniqueProperties(['parse', 'parsePreprocessor', 'unparse']);
|
||||||
|
const EmojiPicker = WebpackModules.findByUniqueProperties(['useEmojiSelectHandler']);
|
||||||
|
const MessageUtilities = WebpackModules.getByProps("sendMessage");
|
||||||
|
const EmojiFilter = WebpackModules.getByProps('getEmojiUnavailableReason');
|
||||||
|
|
||||||
|
const EmojiPickerListRow = WebpackModules.find(m => m?.default?.displayName == 'EmojiPickerListRow');
|
||||||
|
|
||||||
|
const SIZE_REGEX = /([?&]size=)(\d+)/;
|
||||||
|
const EMOJI_SPLIT_LINK_REGEX = /(https:\/\/cdn\.discordapp\.com\/emojis\/\d+\.(?:png|gif|webp)(?:\?size\=\d+&quality=\w*)?)/
|
||||||
|
|
||||||
|
return class Freemoji extends Plugin {
|
||||||
|
currentUser = null;
|
||||||
|
|
||||||
|
replaceEmoji(text, emoji) {
|
||||||
|
const emojiString = `<${emoji.animated ? "a" : ""}:${emoji.originalName || emoji.name}:${emoji.id}>`;
|
||||||
|
const emojiURL = this.getEmojiUrl(emoji);
|
||||||
|
return text.replace(emojiString, emojiURL + " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
patch() {
|
||||||
|
// make emote pretend locked emoji are unlocked
|
||||||
|
Patcher.after(Emojis, 'searchWithoutFetchingLatest', (_, args, ret) => {
|
||||||
|
ret.unlocked = ret.unlocked.concat(ret.locked);
|
||||||
|
ret.locked.length = [];
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
|
||||||
|
// replace emoji with links in messages
|
||||||
|
Patcher.after(EmojiParser, 'parse', (_, args, ret) => {
|
||||||
|
for (const emoji of ret.invalidEmojis) {
|
||||||
|
ret.content = this.replaceEmoji(ret.content, emoji);
|
||||||
|
}
|
||||||
|
ret.invalidEmojis = [];
|
||||||
|
|
||||||
|
for (const emoji of ret.validNonShortcutEmojis) {
|
||||||
|
if (!emoji.available) {
|
||||||
|
ret.content = this.replaceEmoji(ret.content, emoji);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.settings.external) {
|
||||||
|
for (const emoji of ret.validNonShortcutEmojis) {
|
||||||
|
if (this.getEmojiUnavailableReason(emoji) === EmojiDisabledReasons.DISALLOW_EXTERNAL) {
|
||||||
|
ret.content = this.replaceEmoji(ret.content, emoji);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
|
||||||
|
// override emoji picker to allow selecting emotes
|
||||||
|
Patcher.after(EmojiPicker, 'useEmojiSelectHandler', (_, args, ret) => {
|
||||||
|
const { onSelectEmoji, closePopout, selectedChannel } = args[0];
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
return function (data, state) {
|
||||||
|
if (state.toggleFavorite) return ret.apply(this, arguments);
|
||||||
|
|
||||||
|
const emoji = data.emoji;
|
||||||
|
const isFinalSelection = state.isFinalSelection;
|
||||||
|
|
||||||
|
if (self.getEmojiUnavailableReason(emoji, selectedChannel) === EmojiDisabledReasons.DISALLOW_EXTERNAL) {
|
||||||
|
if (self.settings.external == 'off') return;
|
||||||
|
|
||||||
|
if (self.settings.external == 'showDialog') {
|
||||||
|
BdApi.showConfirmationModal(
|
||||||
|
"Sending External Emoji",
|
||||||
|
[`It looks like you are trying to send an an External Emoji in a server that would normally allow it. Do you still want to send it?`], {
|
||||||
|
confirmText: "Send External Emoji",
|
||||||
|
cancelText: "Cancel",
|
||||||
|
onConfirm: () => {
|
||||||
|
self.selectEmoji({ emoji, isFinalSelection, onSelectEmoji, selectedChannel, closePopout, disabled: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.selectEmoji({ emoji, isFinalSelection, onSelectEmoji, closePopout, selectedChannel, disabled: true });
|
||||||
|
} else if (!emoji.available) {
|
||||||
|
self.selectEmoji({ emoji, isFinalSelection, onSelectEmoji, closePopout, selectedChannel, disabled: true });
|
||||||
|
} else {
|
||||||
|
self.selectEmoji({ emoji, isFinalSelection, onSelectEmoji, closePopout, selectedChannel, disabled: data.isDisabled });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Patcher.after(EmojiFilter, 'getEmojiUnavailableReason', (_, [{ intention, bypassPatch }], ret) => {
|
||||||
|
if (intention !== EmojiIntention.CHAT || bypassPatch || !this.settings.external) return;
|
||||||
|
return ret === EmojiDisabledReasons.DISALLOW_EXTERNAL ? null : ret;
|
||||||
|
});
|
||||||
|
|
||||||
|
Patcher.before(EmojiPickerListRow, 'default', (_, [{ emojiDescriptors }]) => {
|
||||||
|
if (this.settings.removeGrayscale == 'never') return;
|
||||||
|
if (this.settings.removeGrayscale != 'always' && !this.hasEmbedPerms()) return;
|
||||||
|
emojiDescriptors.filter(e => e.isDisabled).forEach(e => { e.isDisabled = false; e.wasDisabled = true; });
|
||||||
|
});
|
||||||
|
Patcher.after(EmojiPickerListRow, 'default', (_, [{ emojiDescriptors }]) => {
|
||||||
|
emojiDescriptors.filter(e => e.wasDisabled).forEach(e => { e.isDisabled = true; delete e.wasDisabled; });
|
||||||
|
});
|
||||||
|
|
||||||
|
BdApi.Plugins.isEnabled("EmoteReplacer") || Patcher.instead(MessageUtilities, 'sendMessage', (thisObj, args, originalFn) => {
|
||||||
|
if (!this.settings.split || BdApi.Plugins.isEnabled("EmoteReplacer")) return originalFn.apply(thisObj, args);
|
||||||
|
const [channel, message] = args;
|
||||||
|
const split = message.content.split(EMOJI_SPLIT_LINK_REGEX).map(s => s.trim()).filter(s => s.length);
|
||||||
|
if (split.length <= 1) return originalFn.apply(thisObj, args);
|
||||||
|
|
||||||
|
|
||||||
|
const promises = [];
|
||||||
|
for (let i = 0; i < split.length; i++) {
|
||||||
|
const text = split[i];
|
||||||
|
promises.push(new Promise((resolve, reject) => {
|
||||||
|
window.setTimeout(() => {
|
||||||
|
originalFn.call(thisObj, channel, { content: text, validNonShortcutEmojis: [] }).then(resolve).catch(reject);
|
||||||
|
}, i * 100);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return Promise.all(promises).then(ret => ret[ret.length - 1]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
selectEmoji({ emoji, isFinalSelection, onSelectEmoji, closePopout, selectedChannel, disabled }) {
|
||||||
|
if (disabled) {
|
||||||
|
const perms = this.hasEmbedPerms(selectedChannel);
|
||||||
|
if (!perms && this.settings.missingEmbedPerms == 'nothing') return;
|
||||||
|
if (!perms && this.settings.missingEmbedPerms == 'showDialog') {
|
||||||
|
BdApi.showConfirmationModal(
|
||||||
|
"Missing Image Embed Permissions",
|
||||||
|
[`It looks like you are trying to send an Emoji using Freemoji but you dont have the permissions to send embeded images in this channel. You can choose to send it anyway but it will only show as a link.`], {
|
||||||
|
confirmText: "Send Anyway",
|
||||||
|
cancelText: "Cancel",
|
||||||
|
onConfirm: () => {
|
||||||
|
if (this.settings.sendDirectly) {
|
||||||
|
MessageUtilities.sendMessage(selectedChannel.id, { content: this.getEmojiUrl(emoji) });
|
||||||
|
} else {
|
||||||
|
onSelectEmoji(emoji, isFinalSelection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.settings.sendDirectly) {
|
||||||
|
MessageUtilities.sendMessage(SelectedChannelStore.getChannelId(), { content: this.getEmojiUrl(emoji) });
|
||||||
|
} else {
|
||||||
|
onSelectEmoji(emoji, isFinalSelection);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
onSelectEmoji(emoji, isFinalSelection);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFinalSelection) closePopout();
|
||||||
|
}
|
||||||
|
|
||||||
|
getEmojiUnavailableReason(emoji, channel, intention) {
|
||||||
|
return EmojiFilter.getEmojiUnavailableReason({
|
||||||
|
channel: channel || ChannelStore.getChannel(SelectedChannelStore.getChannelId()),
|
||||||
|
emoji,
|
||||||
|
intention: EmojiIntention.CHAT || intention,
|
||||||
|
bypassPatch: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getEmojiUrl(emoji) {
|
||||||
|
return emoji.url.includes("size=") ?
|
||||||
|
emoji.url.replace(SIZE_REGEX, `$1${this.settings.emojiSize}`) :
|
||||||
|
`${emoji.url}&size=${this.settings.emojiSize}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasEmbedPerms(channelParam) {
|
||||||
|
try {
|
||||||
|
if (!this.currentUser) this.currentUser = UserStore.getCurrentUser();
|
||||||
|
const channel = channelParam || ChannelStore.getChannel(SelectedChannelStore.getChannelId());
|
||||||
|
if (!channel.guild_id) return true;
|
||||||
|
return Permissions.can({permission: DiscordPermissions.EMBED_LINKS, user: this.currentUser.id, context: channel});
|
||||||
|
} catch (e) {
|
||||||
|
Logger.error("Error while detecting embed permissions", e);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
Patcher.unpatchAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
onStart() {
|
||||||
|
try {
|
||||||
|
this.patch();
|
||||||
|
} catch (e) {
|
||||||
|
Toasts.error(`${config.info.name}: An error occured during intialiation: ${e}`);
|
||||||
|
Logger.error(`Error while patching: ${e}`);
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onStop() {
|
||||||
|
this.cleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
getSettingsPanel() { return this.buildSettingsPanel().getElement(); }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
return plugin(Plugin, Api);
|
||||||
|
})(global.ZeresPluginLibrary.buildPlugin(config));
|
||||||
|
})();
|
||||||
|
/*@end@*/
|
||||||
59
.config/BetterDiscord/plugins/ImageUtilities.config.json
Executable file
59
.config/BetterDiscord/plugins/ImageUtilities.config.json
Executable file
@@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"all": {
|
||||||
|
"amounts": {
|
||||||
|
"hoverDelay": 0
|
||||||
|
},
|
||||||
|
"detailsSettings": {
|
||||||
|
"footnote": true,
|
||||||
|
"tooltip": false,
|
||||||
|
"tooltipDelay": 0
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"_all": true,
|
||||||
|
"Baidu": true,
|
||||||
|
"Bing": true,
|
||||||
|
"Google": true,
|
||||||
|
"ImgOps": true,
|
||||||
|
"IQDB": true,
|
||||||
|
"Reddit": true,
|
||||||
|
"SauceNAO": true,
|
||||||
|
"Sogou": true,
|
||||||
|
"TinEye": true,
|
||||||
|
"WhatAnime": true,
|
||||||
|
"Yandex": true
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"nsfwMode": true
|
||||||
|
},
|
||||||
|
"places": {
|
||||||
|
"userAvatars": true,
|
||||||
|
"groupIcons": true,
|
||||||
|
"guildIcons": true,
|
||||||
|
"emojis": true
|
||||||
|
},
|
||||||
|
"rescaleSettings": {
|
||||||
|
"messages": "NONE",
|
||||||
|
"imageViewer": "NONE"
|
||||||
|
},
|
||||||
|
"resizeSettings": {
|
||||||
|
"messages": false,
|
||||||
|
"imageViewer": false
|
||||||
|
},
|
||||||
|
"scaleSettings": {
|
||||||
|
"messages": "NONE",
|
||||||
|
"imageViewer": "NONE"
|
||||||
|
},
|
||||||
|
"viewerSettings": {
|
||||||
|
"zoomMode": true,
|
||||||
|
"galleryMode": true,
|
||||||
|
"details": true,
|
||||||
|
"copyImage": true,
|
||||||
|
"saveImage": true
|
||||||
|
},
|
||||||
|
"zoomSettings": {
|
||||||
|
"lensSize": 1459,
|
||||||
|
"pixelMode": false,
|
||||||
|
"zoomLevel": 1.8000000000000016
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2005
.config/BetterDiscord/plugins/ImageUtilities.plugin.js
Executable file
2005
.config/BetterDiscord/plugins/ImageUtilities.plugin.js
Executable file
File diff suppressed because it is too large
Load Diff
10
.config/BetterDiscord/plugins/InvisibleTyping.config.json
Executable file
10
.config/BetterDiscord/plugins/InvisibleTyping.config.json
Executable file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"currentVersionInfo": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"hasShownChangelog": true
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"exclude": [],
|
||||||
|
"autoEnable": false
|
||||||
|
}
|
||||||
|
}
|
||||||
690
.config/BetterDiscord/plugins/InvisibleTyping.plugin.js
Executable file
690
.config/BetterDiscord/plugins/InvisibleTyping.plugin.js
Executable file
@@ -0,0 +1,690 @@
|
|||||||
|
/**
|
||||||
|
* @name InvisibleTyping
|
||||||
|
* @author Strencher
|
||||||
|
* @version 1.2.2
|
||||||
|
* @description Enhanced version of silent typing.
|
||||||
|
* @source https://github.com/Strencher/BetterDiscordStuff/blob/master/InvisibleTyping/InvisibleTyping.plugin.js
|
||||||
|
* @updateUrl https://raw.githubusercontent.com/Strencher/BetterDiscordStuff/master/InvisibleTyping/InvisibleTyping.plugin.js
|
||||||
|
*/
|
||||||
|
/*@cc_on
|
||||||
|
@if (@_jscript)
|
||||||
|
|
||||||
|
// Offer to self-install for clueless users that try to run this directly.
|
||||||
|
var shell = WScript.CreateObject("WScript.Shell");
|
||||||
|
var fs = new ActiveXObject("Scripting.FileSystemObject");
|
||||||
|
var pathPlugins = shell.ExpandEnvironmentStrings("%APPDATA%\BetterDiscord\plugins");
|
||||||
|
var pathSelf = WScript.ScriptFullName;
|
||||||
|
// Put the user at ease by addressing them in the first person
|
||||||
|
shell.Popup("It looks like you've mistakenly tried to run me directly. \n(Don't do that!)", 0, "I'm a plugin for BetterDiscord", 0x30);
|
||||||
|
if (fs.GetParentFolderName(pathSelf) === fs.GetAbsolutePathName(pathPlugins)) {
|
||||||
|
shell.Popup("I'm in the correct folder already.", 0, "I'm already installed", 0x40);
|
||||||
|
} else if (!fs.FolderExists(pathPlugins)) {
|
||||||
|
shell.Popup("I can't find the BetterDiscord plugins folder.\nAre you sure it's even installed?", 0, "Can't install myself", 0x10);
|
||||||
|
} else if (shell.Popup("Should I copy myself to BetterDiscord's plugins folder for you?", 0, "Do you need some help?", 0x34) === 6) {
|
||||||
|
fs.CopyFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf)), true);
|
||||||
|
// Show the user where to put plugins in the future
|
||||||
|
shell.Exec("explorer " + pathPlugins);
|
||||||
|
shell.Popup("I'm installed!", 0, "Successfully installed", 0x40);
|
||||||
|
}
|
||||||
|
WScript.Quit();
|
||||||
|
@else@*/
|
||||||
|
/* Generated Code */
|
||||||
|
const config = {
|
||||||
|
"info": {
|
||||||
|
"name": "InvisibleTyping",
|
||||||
|
"authors": [{
|
||||||
|
"name": "Strencher",
|
||||||
|
"discord_id": "415849376598982656",
|
||||||
|
"github_username": "Strencher",
|
||||||
|
"twitter_username": "Strencher3"
|
||||||
|
}],
|
||||||
|
"version": "1.2.2",
|
||||||
|
"description": "Enhanced version of silent typing.",
|
||||||
|
"github": "https://github.com/Strencher/BetterDiscordStuff/blob/master/InvisibleTyping/InvisibleTyping.plugin.js",
|
||||||
|
"github_raw": "https://raw.githubusercontent.com/Strencher/BetterDiscordStuff/master/InvisibleTyping/InvisibleTyping.plugin.js"
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"copy": true,
|
||||||
|
"zlibrary": true,
|
||||||
|
"production": true,
|
||||||
|
"release": {
|
||||||
|
"source": true,
|
||||||
|
"readme": true,
|
||||||
|
"public": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"changelog": [{
|
||||||
|
"type": "fixed",
|
||||||
|
"title": "Fixed",
|
||||||
|
"items": [
|
||||||
|
"Fixed latest discord update."
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
function buildPlugin([BasePlugin, PluginApi]) {
|
||||||
|
const module = {
|
||||||
|
exports: {}
|
||||||
|
};
|
||||||
|
(() => {
|
||||||
|
"use strict";
|
||||||
|
class StyleLoader {
|
||||||
|
static styles = "";
|
||||||
|
static element = null;
|
||||||
|
static append(module, css) {
|
||||||
|
this.styles += `/* ${module} */\n${css}`;
|
||||||
|
}
|
||||||
|
static inject(name = config.info.name) {
|
||||||
|
if (this.element) this.element.remove();
|
||||||
|
this.element = document.head.appendChild(Object.assign(document.createElement("style"), {
|
||||||
|
id: name,
|
||||||
|
textContent: this.styles
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
static remove() {
|
||||||
|
if (this.element) {
|
||||||
|
this.element.remove();
|
||||||
|
this.element = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function ___createMemoize___(instance, name, value) {
|
||||||
|
value = value();
|
||||||
|
Object.defineProperty(instance, name, {
|
||||||
|
value,
|
||||||
|
configurable: true
|
||||||
|
});
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
const Modules = {
|
||||||
|
get 'react-spring'() {
|
||||||
|
return ___createMemoize___(this, 'react-spring', () => BdApi.findModuleByProps('useSpring'))
|
||||||
|
},
|
||||||
|
'@discord/utils': {
|
||||||
|
get 'joinClassNames'() {
|
||||||
|
return ___createMemoize___(this, 'joinClassNames', () => BdApi.findModule(e => e.toString().indexOf('return e.join(" ")') > 200))
|
||||||
|
},
|
||||||
|
get 'useForceUpdate'() {
|
||||||
|
return ___createMemoize___(this, 'useForceUpdate', () => BdApi.findModuleByProps('useForceUpdate')?.useForceUpdate)
|
||||||
|
},
|
||||||
|
get 'Logger'() {
|
||||||
|
return ___createMemoize___(this, 'Logger', () => BdApi.findModuleByProps('setLogFn')?.default)
|
||||||
|
},
|
||||||
|
get 'Navigation'() {
|
||||||
|
return ___createMemoize___(this, 'Navigation', () => BdApi.findModuleByProps('replaceWith', 'currentRouteIsPeekView'))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'@discord/components': {
|
||||||
|
get 'Tooltip'() {
|
||||||
|
return ___createMemoize___(this, 'Tooltip', () => BdApi.findModuleByDisplayName('Tooltip'))
|
||||||
|
},
|
||||||
|
get 'TooltipContainer'() {
|
||||||
|
return ___createMemoize___(this, 'TooltipContainer', () => BdApi.findModuleByProps('TooltipContainer')?.TooltipContainer)
|
||||||
|
},
|
||||||
|
get 'TextInput'() {
|
||||||
|
return ___createMemoize___(this, 'TextInput', () => BdApi.findModuleByDisplayName('TextInput'))
|
||||||
|
},
|
||||||
|
get 'SlideIn'() {
|
||||||
|
return ___createMemoize___(this, 'SlideIn', () => BdApi.findModuleByDisplayName('SlideIn'))
|
||||||
|
},
|
||||||
|
get 'SettingsNotice'() {
|
||||||
|
return ___createMemoize___(this, 'SettingsNotice', () => BdApi.findModuleByDisplayName('SettingsNotice'))
|
||||||
|
},
|
||||||
|
get 'TransitionGroup'() {
|
||||||
|
return ___createMemoize___(this, 'TransitionGroup', () => BdApi.findModuleByDisplayName('TransitionGroup'))
|
||||||
|
},
|
||||||
|
get 'Button'() {
|
||||||
|
return ___createMemoize___(this, 'Button', () => BdApi.findModule(m => 'DropdownSizes' in m && typeof(m) === 'function'))
|
||||||
|
},
|
||||||
|
get 'Popout'() {
|
||||||
|
return ___createMemoize___(this, 'Popout', () => BdApi.findModuleByDisplayName('Popout'))
|
||||||
|
},
|
||||||
|
get 'Flex'() {
|
||||||
|
return ___createMemoize___(this, 'Flex', () => BdApi.findModuleByDisplayName('Flex'))
|
||||||
|
},
|
||||||
|
get 'Text'() {
|
||||||
|
return ___createMemoize___(this, 'Text', () => BdApi.findModuleByDisplayName('LegacyText'))
|
||||||
|
},
|
||||||
|
get 'Card'() {
|
||||||
|
return ___createMemoize___(this, 'Card', () => BdApi.findModuleByDisplayName('Card'))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'@discord/modules': {
|
||||||
|
get 'Dispatcher'() {
|
||||||
|
return ___createMemoize___(this, 'Dispatcher', () => BdApi.findModuleByProps('dispatch', 'isDispatching'))
|
||||||
|
},
|
||||||
|
get 'ComponentDispatcher'() {
|
||||||
|
return ___createMemoize___(this, 'ComponentDispatcher', () => BdApi.findModuleByProps('ComponentDispatch')?.ComponentDispatch)
|
||||||
|
},
|
||||||
|
get 'EmojiUtils'() {
|
||||||
|
return ___createMemoize___(this, 'EmojiUtils', () => BdApi.findModuleByProps('uploadEmoji'))
|
||||||
|
},
|
||||||
|
get 'PermissionUtils'() {
|
||||||
|
return ___createMemoize___(this, 'PermissionUtils', () => BdApi.findModuleByProps('computePermissions', 'canManageUser'))
|
||||||
|
},
|
||||||
|
get 'DMUtils'() {
|
||||||
|
return ___createMemoize___(this, 'DMUtils', () => BdApi.findModuleByProps('openPrivateChannel'))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'@discord/stores': {
|
||||||
|
get 'Messages'() {
|
||||||
|
return ___createMemoize___(this, 'Messages', () => BdApi.findModuleByProps('getMessage', 'getMessages'))
|
||||||
|
},
|
||||||
|
get 'Channels'() {
|
||||||
|
return ___createMemoize___(this, 'Channels', () => BdApi.findModuleByProps('getChannel', 'getDMFromUserId'))
|
||||||
|
},
|
||||||
|
get 'Guilds'() {
|
||||||
|
return ___createMemoize___(this, 'Guilds', () => BdApi.findModuleByProps('getGuild'))
|
||||||
|
},
|
||||||
|
get 'SelectedGuilds'() {
|
||||||
|
return ___createMemoize___(this, 'SelectedGuilds', () => BdApi.findModuleByProps('getGuildId', 'getLastSelectedGuildId'))
|
||||||
|
},
|
||||||
|
get 'SelectedChannels'() {
|
||||||
|
return ___createMemoize___(this, 'SelectedChannels', () => BdApi.findModuleByProps('getChannelId', 'getLastSelectedChannelId'))
|
||||||
|
},
|
||||||
|
get 'Info'() {
|
||||||
|
return ___createMemoize___(this, 'Info', () => BdApi.findModuleByProps('getSessionId'))
|
||||||
|
},
|
||||||
|
get 'Status'() {
|
||||||
|
return ___createMemoize___(this, 'Status', () => BdApi.findModuleByProps('getStatus', 'getActivities', 'getState'))
|
||||||
|
},
|
||||||
|
get 'Users'() {
|
||||||
|
return ___createMemoize___(this, 'Users', () => BdApi.findModuleByProps('getUser', 'getCurrentUser'))
|
||||||
|
},
|
||||||
|
get 'SettingsStore'() {
|
||||||
|
return ___createMemoize___(this, 'SettingsStore', () => BdApi.findModuleByProps('afkTimeout', 'status'))
|
||||||
|
},
|
||||||
|
get 'UserProfile'() {
|
||||||
|
return ___createMemoize___(this, 'UserProfile', () => BdApi.findModuleByProps('getUserProfile'))
|
||||||
|
},
|
||||||
|
get 'Members'() {
|
||||||
|
return ___createMemoize___(this, 'Members', () => BdApi.findModuleByProps('getMember'))
|
||||||
|
},
|
||||||
|
get 'Activities'() {
|
||||||
|
return ___createMemoize___(this, 'Activities', () => BdApi.findModuleByProps('getActivities'))
|
||||||
|
},
|
||||||
|
get 'Games'() {
|
||||||
|
return ___createMemoize___(this, 'Games', () => BdApi.findModuleByProps('getGame', 'games'))
|
||||||
|
},
|
||||||
|
get 'Auth'() {
|
||||||
|
return ___createMemoize___(this, 'Auth', () => BdApi.findModuleByProps('getId', 'isGuest'))
|
||||||
|
},
|
||||||
|
get 'TypingUsers'() {
|
||||||
|
return ___createMemoize___(this, 'TypingUsers', () => BdApi.findModuleByProps('isTyping'))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'@discord/actions': {
|
||||||
|
get 'ProfileActions'() {
|
||||||
|
return ___createMemoize___(this, 'ProfileActions', () => BdApi.findModuleByProps('fetchProfile'))
|
||||||
|
},
|
||||||
|
get 'GuildActions'() {
|
||||||
|
return ___createMemoize___(this, 'GuildActions', () => BdApi.findModuleByProps('requestMembersById'))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
get '@discord/i18n'() {
|
||||||
|
return ___createMemoize___(this, '@discord/i18n', () => BdApi.findModule(m => m.Messages?.CLOSE && typeof(m.getLocale) === 'function'))
|
||||||
|
},
|
||||||
|
get '@discord/constants'() {
|
||||||
|
return ___createMemoize___(this, '@discord/constants', () => BdApi.findModuleByProps('API_HOST'))
|
||||||
|
},
|
||||||
|
get '@discord/contextmenu'() {
|
||||||
|
return ___createMemoize___(this, '@discord/contextmenu', () => {
|
||||||
|
const ctx = Object.assign({}, BdApi.findModuleByProps('openContextMenu'), BdApi.findModuleByProps('MenuItem'));
|
||||||
|
ctx.Menu = ctx.default;
|
||||||
|
return ctx;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
get '@discord/forms'() {
|
||||||
|
return ___createMemoize___(this, '@discord/forms', () => BdApi.findModuleByProps('FormItem'))
|
||||||
|
},
|
||||||
|
get '@discord/scrollbars'() {
|
||||||
|
return ___createMemoize___(this, '@discord/scrollbars', () => BdApi.findModuleByProps('ScrollerAuto'))
|
||||||
|
},
|
||||||
|
get '@discord/native'() {
|
||||||
|
return ___createMemoize___(this, '@discord/native', () => BdApi.findModuleByProps('requireModule'))
|
||||||
|
},
|
||||||
|
get '@discord/flux'() {
|
||||||
|
return ___createMemoize___(this, '@discord/flux', () => Object.assign({}, BdApi.findModuleByProps('useStateFromStores').default, BdApi.findModuleByProps('useStateFromStores')))
|
||||||
|
},
|
||||||
|
get '@discord/modal'() {
|
||||||
|
return ___createMemoize___(this, '@discord/modal', () => Object.assign({}, BdApi.findModuleByProps('ModalRoot'), BdApi.findModuleByProps('openModal', 'closeAllModals')))
|
||||||
|
},
|
||||||
|
get '@discord/connections'() {
|
||||||
|
return ___createMemoize___(this, '@discord/connections', () => BdApi.findModuleByProps('get', 'isSupported', 'map'))
|
||||||
|
},
|
||||||
|
get '@discord/sanitize'() {
|
||||||
|
return ___createMemoize___(this, '@discord/sanitize', () => BdApi.findModuleByProps('stringify', 'parse', 'encode'))
|
||||||
|
},
|
||||||
|
get '@discord/icons'() {
|
||||||
|
return ___createMemoize___(this, '@discord/icons', () => BdApi.findAllModules(m => m.displayName && ~m.toString().indexOf('currentColor')).reduce((icons, icon) => (icons[icon.displayName] = icon, icons), {}))
|
||||||
|
},
|
||||||
|
'@discord/classes': {
|
||||||
|
get 'Timestamp'() {
|
||||||
|
return ___createMemoize___(this, 'Timestamp', () => BdApi.findModuleByPrototypes('toDate', 'month'))
|
||||||
|
},
|
||||||
|
get 'Message'() {
|
||||||
|
return ___createMemoize___(this, 'Message', () => BdApi.findModuleByPrototypes('getReaction', 'isSystemDM'))
|
||||||
|
},
|
||||||
|
get 'User'() {
|
||||||
|
return ___createMemoize___(this, 'User', () => BdApi.findModuleByPrototypes('tag'))
|
||||||
|
},
|
||||||
|
get 'Channel'() {
|
||||||
|
return ___createMemoize___(this, 'Channel', () => BdApi.findModuleByPrototypes('isOwner', 'isCategory'))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var __webpack_modules__ = {
|
||||||
|
646: (module, __webpack_exports__, __webpack_require__) => {
|
||||||
|
__webpack_require__.d(__webpack_exports__, {
|
||||||
|
Z: () => __WEBPACK_DEFAULT_EXPORT__
|
||||||
|
});
|
||||||
|
var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(645);
|
||||||
|
var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__);
|
||||||
|
var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()((function(i) {
|
||||||
|
return i[1];
|
||||||
|
}));
|
||||||
|
___CSS_LOADER_EXPORT___.push([module.id, ".InvisibleTyping-settings-panel{color:#ddd}", ""]);
|
||||||
|
___CSS_LOADER_EXPORT___.locals = {
|
||||||
|
panel: "InvisibleTyping-settings-panel"
|
||||||
|
};
|
||||||
|
StyleLoader.append(module.id, ___CSS_LOADER_EXPORT___.toString());
|
||||||
|
const __WEBPACK_DEFAULT_EXPORT__ = Object.assign(___CSS_LOADER_EXPORT___, ___CSS_LOADER_EXPORT___.locals);
|
||||||
|
},
|
||||||
|
166: (module, __webpack_exports__, __webpack_require__) => {
|
||||||
|
__webpack_require__.d(__webpack_exports__, {
|
||||||
|
Z: () => __WEBPACK_DEFAULT_EXPORT__
|
||||||
|
});
|
||||||
|
var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(645);
|
||||||
|
var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = __webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__);
|
||||||
|
var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()((function(i) {
|
||||||
|
return i[1];
|
||||||
|
}));
|
||||||
|
___CSS_LOADER_EXPORT___.push([module.id, ".InvisibleTyping-typingButton-invisibleTypingButton svg{color:var(--interactive-normal);overflow:visible}.InvisibleTyping-typingButton-invisibleTypingButton .InvisibleTyping-typingButton-disabledStrokeThrough{position:absolute;transform:translateX(-15px) translateY(530px) rotate(-45deg)}.InvisibleTyping-typingButton-invisibleTypingButton{margin-top:3px;background:rgba(0,0,0,0)}.InvisibleTyping-typingButton-invisibleTypingButton:hover:not(.InvisibleTyping-typingButton-disabled) svg{color:var(--interactive-hover)}.InvisibleTyping-typingButton-invisibleTypingTooltip{display:inline-flex}", ""]);
|
||||||
|
___CSS_LOADER_EXPORT___.locals = {
|
||||||
|
invisibleTypingButton: "InvisibleTyping-typingButton-invisibleTypingButton",
|
||||||
|
disabledStrokeThrough: "InvisibleTyping-typingButton-disabledStrokeThrough",
|
||||||
|
disabled: "InvisibleTyping-typingButton-disabled",
|
||||||
|
invisibleTypingTooltip: "InvisibleTyping-typingButton-invisibleTypingTooltip"
|
||||||
|
};
|
||||||
|
StyleLoader.append(module.id, ___CSS_LOADER_EXPORT___.toString());
|
||||||
|
const __WEBPACK_DEFAULT_EXPORT__ = Object.assign(___CSS_LOADER_EXPORT___, ___CSS_LOADER_EXPORT___.locals);
|
||||||
|
},
|
||||||
|
645: module => {
|
||||||
|
module.exports = function(cssWithMappingToString) {
|
||||||
|
var list = [];
|
||||||
|
list.toString = function toString() {
|
||||||
|
return this.map((function(item) {
|
||||||
|
var content = cssWithMappingToString(item);
|
||||||
|
if (item[2]) return "@media ".concat(item[2], " {").concat(content, "}");
|
||||||
|
return content;
|
||||||
|
})).join("");
|
||||||
|
};
|
||||||
|
list.i = function(modules, mediaQuery, dedupe) {
|
||||||
|
if ("string" === typeof modules) modules = [
|
||||||
|
[null, modules, ""]
|
||||||
|
];
|
||||||
|
var alreadyImportedModules = {};
|
||||||
|
if (dedupe)
|
||||||
|
for (var i = 0; i < this.length; i++) {
|
||||||
|
var id = this[i][0];
|
||||||
|
if (null != id) alreadyImportedModules[id] = true;
|
||||||
|
}
|
||||||
|
for (var _i = 0; _i < modules.length; _i++) {
|
||||||
|
var item = [].concat(modules[_i]);
|
||||||
|
if (dedupe && alreadyImportedModules[item[0]]) continue;
|
||||||
|
if (mediaQuery)
|
||||||
|
if (!item[2]) item[2] = mediaQuery;
|
||||||
|
else item[2] = "".concat(mediaQuery, " and ").concat(item[2]);
|
||||||
|
list.push(item);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return list;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
113: module => {
|
||||||
|
module.exports = BdApi.React;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var __webpack_module_cache__ = {};
|
||||||
|
function __webpack_require__(moduleId) {
|
||||||
|
var cachedModule = __webpack_module_cache__[moduleId];
|
||||||
|
if (void 0 !== cachedModule) return cachedModule.exports;
|
||||||
|
var module = __webpack_module_cache__[moduleId] = {
|
||||||
|
id: moduleId,
|
||||||
|
exports: {}
|
||||||
|
};
|
||||||
|
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
||||||
|
return module.exports;
|
||||||
|
}
|
||||||
|
(() => {
|
||||||
|
__webpack_require__.n = module => {
|
||||||
|
var getter = module && module.__esModule ? () => module["default"] : () => module;
|
||||||
|
__webpack_require__.d(getter, {
|
||||||
|
a: getter
|
||||||
|
});
|
||||||
|
return getter;
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
(() => {
|
||||||
|
__webpack_require__.d = (exports, definition) => {
|
||||||
|
for (var key in definition)
|
||||||
|
if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) Object.defineProperty(exports, key, {
|
||||||
|
enumerable: true,
|
||||||
|
get: definition[key]
|
||||||
|
});
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
(() => {
|
||||||
|
__webpack_require__.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop);
|
||||||
|
})();
|
||||||
|
(() => {
|
||||||
|
__webpack_require__.r = exports => {
|
||||||
|
if ("undefined" !== typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports, Symbol.toStringTag, {
|
||||||
|
value: "Module"
|
||||||
|
});
|
||||||
|
Object.defineProperty(exports, "__esModule", {
|
||||||
|
value: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
var __webpack_exports__ = {};
|
||||||
|
(() => {
|
||||||
|
__webpack_require__.r(__webpack_exports__);
|
||||||
|
__webpack_require__.d(__webpack_exports__, {
|
||||||
|
default: () => InvisibleTyping
|
||||||
|
});
|
||||||
|
const external_PluginApi_namespaceObject = PluginApi;
|
||||||
|
const external_BasePlugin_namespaceObject = BasePlugin;
|
||||||
|
var external_BasePlugin_default = __webpack_require__.n(external_BasePlugin_namespaceObject);
|
||||||
|
const utils_namespaceObject = Modules["@discord/utils"];
|
||||||
|
const components_namespaceObject = Modules["@discord/components"];
|
||||||
|
var external_BdApi_React_ = __webpack_require__(113);
|
||||||
|
var external_BdApi_React_default = __webpack_require__.n(external_BdApi_React_);
|
||||||
|
const flux_namespaceObject = Modules["@discord/flux"];
|
||||||
|
const modules_namespaceObject = Modules["@discord/modules"];
|
||||||
|
function _defineProperty(obj, key, value) {
|
||||||
|
if (key in obj) Object.defineProperty(obj, key, {
|
||||||
|
value,
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true,
|
||||||
|
writable: true
|
||||||
|
});
|
||||||
|
else obj[key] = value;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
class SettingsManager extends flux_namespaceObject.Store {
|
||||||
|
constructor(pluginName, defaultSettings = {}) {
|
||||||
|
super(modules_namespaceObject.Dispatcher, {});
|
||||||
|
_defineProperty(this, "settings", void 0);
|
||||||
|
_defineProperty(this, "pluginName", void 0);
|
||||||
|
_defineProperty(this, "get", ((key, defaultValue) => this.settings[key] ?? defaultValue));
|
||||||
|
_defineProperty(this, "set", ((key, value) => {
|
||||||
|
this.settings[key] = value;
|
||||||
|
external_PluginApi_namespaceObject.PluginUtilities.saveSettings(this.pluginName, this.settings);
|
||||||
|
this.emitChange();
|
||||||
|
return value;
|
||||||
|
}));
|
||||||
|
this.pluginName = pluginName;
|
||||||
|
this.settings = external_PluginApi_namespaceObject.PluginUtilities.loadSettings(pluginName, defaultSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const package_namespaceObject = JSON.parse('{"um":{"u2":"InvisibleTyping"}}');
|
||||||
|
const Settings = new SettingsManager(package_namespaceObject.um.u2);
|
||||||
|
const settings = Settings;
|
||||||
|
var typingButton = __webpack_require__(166);
|
||||||
|
function Keyboard({
|
||||||
|
disabled,
|
||||||
|
...props
|
||||||
|
}) {
|
||||||
|
return external_BdApi_React_default().createElement("svg", Object.assign({}, props, {
|
||||||
|
width: "25",
|
||||||
|
height: "25",
|
||||||
|
viewBox: "0 0 576 512"
|
||||||
|
}), external_BdApi_React_default().createElement("path", {
|
||||||
|
fill: "currentColor",
|
||||||
|
d: "M528 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h480c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48zM128 180v-40c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-336 96v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm-336 96v-40c0-6.627-5.373-12-12-12H76c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12zm288 0v-40c0-6.627-5.373-12-12-12H172c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h232c6.627 0 12-5.373 12-12zm96 0v-40c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v40c0 6.627 5.373 12 12 12h40c6.627 0 12-5.373 12-12z"
|
||||||
|
}), disabled ? external_BdApi_React_default().createElement("rect", {
|
||||||
|
className: typingButton.Z.disabledStrokeThrough,
|
||||||
|
x: "10",
|
||||||
|
y: "10",
|
||||||
|
width: "600pt",
|
||||||
|
height: "70px",
|
||||||
|
fill: "#f04747"
|
||||||
|
}) : null);
|
||||||
|
}
|
||||||
|
const contextmenu_namespaceObject = Modules["@discord/contextmenu"];
|
||||||
|
const TypingModule = external_PluginApi_namespaceObject.WebpackModules.getByProps("startTyping");
|
||||||
|
const removeItem = function(array, item) {
|
||||||
|
while (array.includes(item)) array.splice(array.indexOf(item), 1);
|
||||||
|
return array;
|
||||||
|
};
|
||||||
|
function InvisibleTypingContextMenu({
|
||||||
|
channelId
|
||||||
|
}) {
|
||||||
|
const enabled = (0, flux_namespaceObject.useStateFromStores)([settings], (() => settings.get("autoEnable", true)));
|
||||||
|
return external_BdApi_React_default().createElement(contextmenu_namespaceObject.Menu, {
|
||||||
|
navId: "invisible-typing-context-menu",
|
||||||
|
onClose: contextmenu_namespaceObject.closeContextMenu
|
||||||
|
}, external_BdApi_React_default().createElement(contextmenu_namespaceObject.MenuItem, {
|
||||||
|
id: "globally-disable-or-enable-typing",
|
||||||
|
label: enabled ? "Disable Globally" : "Enable Globally",
|
||||||
|
action: () => {
|
||||||
|
settings.set("autoEnable", !enabled);
|
||||||
|
}
|
||||||
|
}), external_BdApi_React_default().createElement(contextmenu_namespaceObject.MenuItem, {
|
||||||
|
color: "colorDanger",
|
||||||
|
label: "Reset Config",
|
||||||
|
disabled: !settings.get("exclude", []).length,
|
||||||
|
id: "reset-config",
|
||||||
|
action: () => {
|
||||||
|
settings.set("exclude", []);
|
||||||
|
external_PluginApi_namespaceObject.Toasts.success("Successfully reset config for all channels.");
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
function InvisibleTypingButton({
|
||||||
|
channel,
|
||||||
|
isEmpty
|
||||||
|
}) {
|
||||||
|
const enabled = (0, flux_namespaceObject.useStateFromStores)([settings], InvisibleTypingButton.getState.bind(this, channel.id));
|
||||||
|
const handleClick = (0, external_BdApi_React_.useCallback)((() => {
|
||||||
|
const excludeList = [...settings.get("exclude", [])];
|
||||||
|
if (excludeList.includes(channel.id)) {
|
||||||
|
removeItem(excludeList, channel.id);
|
||||||
|
TypingModule.stopTyping(channel.id);
|
||||||
|
} else {
|
||||||
|
excludeList.push(channel.id);
|
||||||
|
if (!isEmpty) TypingModule.startTyping(channel.id);
|
||||||
|
}
|
||||||
|
settings.set("exclude", excludeList);
|
||||||
|
}), [enabled]);
|
||||||
|
const handleContextMenu = (0, external_BdApi_React_.useCallback)((event => {
|
||||||
|
(0, contextmenu_namespaceObject.openContextMenu)(event, (() => external_BdApi_React_default().createElement(InvisibleTypingContextMenu, {
|
||||||
|
channelId: channel.id
|
||||||
|
})));
|
||||||
|
}), [enabled]);
|
||||||
|
return external_BdApi_React_default().createElement(components_namespaceObject.TooltipContainer, {
|
||||||
|
text: enabled ? "Typing Enabled" : "Typing Disabled",
|
||||||
|
position: "top",
|
||||||
|
className: typingButton.Z.invisibleTypingTooltip
|
||||||
|
}, external_BdApi_React_default().createElement("button", {
|
||||||
|
className: (0, utils_namespaceObject.joinClassNames)(typingButton.Z.invisibleTypingButton, {
|
||||||
|
enabled,
|
||||||
|
disabled: !enabled
|
||||||
|
}),
|
||||||
|
onClick: handleClick,
|
||||||
|
onContextMenu: handleContextMenu
|
||||||
|
}, external_BdApi_React_default().createElement(Keyboard, {
|
||||||
|
disabled: !enabled
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
InvisibleTypingButton.getState = function(channelId) {
|
||||||
|
const isGlobal = settings.get("autoEnable", true);
|
||||||
|
const isExcluded = settings.get("exclude", []).includes(channelId);
|
||||||
|
if (isGlobal && isExcluded) return false;
|
||||||
|
if (isExcluded && !isGlobal) return true;
|
||||||
|
return isGlobal;
|
||||||
|
};
|
||||||
|
const external_StyleLoader_namespaceObject = StyleLoader;
|
||||||
|
var external_StyleLoader_default = __webpack_require__.n(external_StyleLoader_namespaceObject);
|
||||||
|
var React = __webpack_require__(113);
|
||||||
|
const createUpdateWrapper = (Component, valueProp = "value", changeProp = "onChange", valueIndex = 0) => props => {
|
||||||
|
const [value, setValue] = React.useState(props[valueProp]);
|
||||||
|
return React.createElement(Component, Object.assign({}, props, {
|
||||||
|
[valueProp]: value,
|
||||||
|
[changeProp]: (...args) => {
|
||||||
|
const value = args[valueIndex];
|
||||||
|
if ("function" === typeof props[changeProp]) props[changeProp](value);
|
||||||
|
setValue(value);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
const hooks_createUpdateWrapper = createUpdateWrapper;
|
||||||
|
var components_settings = __webpack_require__(646);
|
||||||
|
const SwitchItem = hooks_createUpdateWrapper(external_PluginApi_namespaceObject.WebpackModules.getByDisplayName("SwitchItem"));
|
||||||
|
function SettingsPanel() {
|
||||||
|
const disabledChannels = (0, flux_namespaceObject.useStateFromStores)([settings], (() => settings.get("exclude", [])));
|
||||||
|
return external_BdApi_React_default().createElement(external_BdApi_React_default().Fragment, null, external_BdApi_React_default().createElement(SwitchItem, {
|
||||||
|
note: "Automatically enables the typing indicator for each channel that isn't manually disabled.",
|
||||||
|
value: settings.get("autoEnable", true),
|
||||||
|
onChange: value => settings.set("autoEnable", value)
|
||||||
|
}, "Automatically enable"), external_BdApi_React_default().createElement(components_namespaceObject.Flex, {
|
||||||
|
justify: components_namespaceObject.Flex.Justify.END,
|
||||||
|
direction: components_namespaceObject.Flex.Direction.VERTICAL
|
||||||
|
}, external_BdApi_React_default().createElement("p", {
|
||||||
|
className: components_settings.Z.panel
|
||||||
|
}, "Current disabled channels: ", disabledChannels.length), external_BdApi_React_default().createElement(components_namespaceObject.Button, {
|
||||||
|
look: components_namespaceObject.Button.Looks.OUTLINED,
|
||||||
|
color: components_namespaceObject.Button.Colors.RED,
|
||||||
|
disabled: !Boolean(disabledChannels.length),
|
||||||
|
size: components_namespaceObject.Button.Sizes.SMALL,
|
||||||
|
onClick: () => {
|
||||||
|
settings.set("exclude", []);
|
||||||
|
}
|
||||||
|
}, "Reset")));
|
||||||
|
}
|
||||||
|
const constants_namespaceObject = Modules["@discord/constants"];
|
||||||
|
const stores_namespaceObject = Modules["@discord/stores"];
|
||||||
|
var InvisibleTyping_React = __webpack_require__(113);
|
||||||
|
function InvisibleTyping_defineProperty(obj, key, value) {
|
||||||
|
if (key in obj) Object.defineProperty(obj, key, {
|
||||||
|
value,
|
||||||
|
enumerable: true,
|
||||||
|
configurable: true,
|
||||||
|
writable: true
|
||||||
|
});
|
||||||
|
else obj[key] = value;
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
const ChannelTextAreaContainer = external_PluginApi_namespaceObject.WebpackModules.find((m => "ChannelTextAreaContainer" === m?.type?.render?.displayName))?.type;
|
||||||
|
const ChannelTextAreaButtons = external_PluginApi_namespaceObject.WebpackModules.find((m => m.type && "ChannelTextAreaButtons" === m.type.displayName));
|
||||||
|
const DMChannels = [constants_namespaceObject.ChannelTypes.DM, constants_namespaceObject.ChannelTypes.GROUP_DM];
|
||||||
|
const canViewChannel = function(channel) {
|
||||||
|
if (!channel) return false;
|
||||||
|
if (DMChannels.includes(channel.type)) return true;
|
||||||
|
try {
|
||||||
|
return modules_namespaceObject.PermissionUtils.can(constants_namespaceObject.Permissions.SEND_MESSAGES, channel, stores_namespaceObject.Users.getCurrentUser());
|
||||||
|
} catch (error) {
|
||||||
|
external_PluginApi_namespaceObject.Logger.error("Failed to request permissions:", error);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class InvisibleTyping extends(external_BasePlugin_default()) {
|
||||||
|
static setUpdating(state) {
|
||||||
|
this._updating = state;
|
||||||
|
}
|
||||||
|
onStart() {
|
||||||
|
external_StyleLoader_default().inject();
|
||||||
|
external_PluginApi_namespaceObject.Utilities.suppressErrors(this.patchTextAreaButtons.bind(this), "textarea buttons patch")();
|
||||||
|
external_PluginApi_namespaceObject.Utilities.suppressErrors(this.patchStartTyping.bind(this), "start typing patch")();
|
||||||
|
}
|
||||||
|
getSettingsPanel() {
|
||||||
|
return InvisibleTyping_React.createElement(SettingsPanel, null);
|
||||||
|
}
|
||||||
|
async patchTextAreaButtons() {
|
||||||
|
const shouldShow = function(children, props) {
|
||||||
|
if ("profile_bio_input" === props.type?.analyticsName) return false;
|
||||||
|
if (!Array.isArray(children)) return false;
|
||||||
|
if (children.some((child => child && child.type === InvisibleTyping))) return false;
|
||||||
|
if (!canViewChannel(props.channel)) return false;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
if (ChannelTextAreaButtons) {
|
||||||
|
external_PluginApi_namespaceObject.Patcher.after(ChannelTextAreaButtons, "type", ((_, [props], returnValue) => {
|
||||||
|
const children = returnValue && returnValue.props && returnValue.props.children;
|
||||||
|
if (!shouldShow(children, props)) return;
|
||||||
|
children.unshift(InvisibleTyping_React.createElement(InvisibleTypingButton, props));
|
||||||
|
}));
|
||||||
|
this.forceUpdate();
|
||||||
|
} else external_PluginApi_namespaceObject.Patcher.after(ChannelTextAreaContainer, "render", ((_, [props], returnValue) => {
|
||||||
|
const tree = external_PluginApi_namespaceObject.Utilities.findInReactTree(returnValue, (e => e?.className?.indexOf("buttons-") > -1));
|
||||||
|
if (!tree || !shouldShow(tree.children, props)) return returnValue;
|
||||||
|
tree.children.unshift(InvisibleTyping_React.createElement(InvisibleTypingButton, Object.assign({}, props, {
|
||||||
|
isEmpty: !!props.textValue
|
||||||
|
})));
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
forceUpdate() {
|
||||||
|
if (InvisibleTyping._updating) return;
|
||||||
|
InvisibleTyping.setUpdating(true);
|
||||||
|
external_PluginApi_namespaceObject.Patcher.after(ChannelTextAreaContainer, "render", (function() {
|
||||||
|
const [, , returnValue] = arguments;
|
||||||
|
this.unpatch();
|
||||||
|
InvisibleTyping.setUpdating(false);
|
||||||
|
const buttons = external_PluginApi_namespaceObject.Utilities.findInReactTree(returnValue, (e => e && e.type === ChannelTextAreaButtons));
|
||||||
|
if (!buttons) return;
|
||||||
|
buttons.key = Math.random().toString();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
async patchStartTyping() {
|
||||||
|
const TypingModule = external_PluginApi_namespaceObject.WebpackModules.getByProps("startTyping");
|
||||||
|
external_PluginApi_namespaceObject.Patcher.instead(TypingModule, "startTyping", ((_, [channelId], originalMethod) => {
|
||||||
|
if (InvisibleTypingButton.getState(channelId)) originalMethod(channelId);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
onStop() {
|
||||||
|
external_PluginApi_namespaceObject.Patcher.unpatchAll();
|
||||||
|
external_StyleLoader_default().remove();
|
||||||
|
if (ChannelTextAreaButtons) this.forceUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
InvisibleTyping_defineProperty(InvisibleTyping, "_updating", false);
|
||||||
|
})();
|
||||||
|
module.exports.LibraryPluginHack = __webpack_exports__;
|
||||||
|
})();
|
||||||
|
const PluginExports = module.exports.LibraryPluginHack;
|
||||||
|
return PluginExports?.__esModule ? PluginExports.default : PluginExports;
|
||||||
|
}
|
||||||
|
module.exports = window.hasOwnProperty("ZeresPluginLibrary") ?
|
||||||
|
buildPlugin(window.ZeresPluginLibrary.buildPlugin(config)) :
|
||||||
|
class {
|
||||||
|
getName() {
|
||||||
|
return config.info.name;
|
||||||
|
}
|
||||||
|
getAuthor() {
|
||||||
|
return config.info.authors.map(a => a.name).join(", ");
|
||||||
|
}
|
||||||
|
getDescription() {
|
||||||
|
return `${config.info.description}. __**ZeresPluginLibrary was not found! This plugin will not work!**__`;
|
||||||
|
}
|
||||||
|
getVersion() {
|
||||||
|
return config.info.version;
|
||||||
|
}
|
||||||
|
load() {
|
||||||
|
BdApi.showConfirmationModal(
|
||||||
|
"Library plugin is needed",
|
||||||
|
[`The library plugin needed for ${config.info.name} is missing. Please click Download to install it.`], {
|
||||||
|
confirmText: "Download",
|
||||||
|
cancelText: "Cancel",
|
||||||
|
onConfirm: () => {
|
||||||
|
require("request").get("https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js", async (error, response, body) => {
|
||||||
|
if (error) return require("electron").shell.openExternal("https://betterdiscord.net/ghdl?url=https://raw.githubusercontent.com/rauenzi/BDPluginLibrary/master/release/0PluginLibrary.plugin.js");
|
||||||
|
await new Promise(r => require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0PluginLibrary.plugin.js"), body, r));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
start() {}
|
||||||
|
stop() {}
|
||||||
|
};
|
||||||
|
/*@end@*/
|
||||||
252
.config/BetterDiscord/plugins/NotificationSounds.config.json
Executable file
252
.config/BetterDiscord/plugins/NotificationSounds.config.json
Executable file
File diff suppressed because one or more lines are too long
747
.config/BetterDiscord/plugins/NotificationSounds.plugin.js
Normal file
747
.config/BetterDiscord/plugins/NotificationSounds.plugin.js
Normal file
@@ -0,0 +1,747 @@
|
|||||||
|
/**
|
||||||
|
* @name NotificationSounds
|
||||||
|
* @author DevilBro
|
||||||
|
* @authorId 278543574059057154
|
||||||
|
* @version 3.7.2
|
||||||
|
* @description Allows you to replace the native Sounds with custom Sounds
|
||||||
|
* @invite Jx3TjNS
|
||||||
|
* @donate https://www.paypal.me/MircoWittrien
|
||||||
|
* @patreon https://www.patreon.com/MircoWittrien
|
||||||
|
* @website https://mwittrien.github.io/
|
||||||
|
* @source https://github.com/mwittrien/BetterDiscordAddons/tree/master/Plugins/NotificationSounds/
|
||||||
|
* @updateUrl https://mwittrien.github.io/BetterDiscordAddons/Plugins/NotificationSounds/NotificationSounds.plugin.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = (_ => {
|
||||||
|
const config = {
|
||||||
|
"info": {
|
||||||
|
"name": "NotificationSounds",
|
||||||
|
"author": "DevilBro",
|
||||||
|
"version": "3.7.2",
|
||||||
|
"description": "Allows you to replace the native Sounds with custom Sounds"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return !window.BDFDB_Global || (!window.BDFDB_Global.loaded && !window.BDFDB_Global.started) ? class {
|
||||||
|
getName () {return config.info.name;}
|
||||||
|
getAuthor () {return config.info.author;}
|
||||||
|
getVersion () {return config.info.version;}
|
||||||
|
getDescription () {return `The Library Plugin needed for ${config.info.name} is missing. Open the Plugin Settings to download it. \n\n${config.info.description}`;}
|
||||||
|
|
||||||
|
downloadLibrary () {
|
||||||
|
require("request").get("https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js", (e, r, b) => {
|
||||||
|
if (!e && b && r.statusCode == 200) require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0BDFDB.plugin.js"), b, _ => BdApi.showToast("Finished downloading BDFDB Library", {type: "success"}));
|
||||||
|
else BdApi.alert("Error", "Could not download BDFDB Library Plugin. Try again later or download it manually from GitHub: https://mwittrien.github.io/downloader/?library");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
load () {
|
||||||
|
if (!window.BDFDB_Global || !Array.isArray(window.BDFDB_Global.pluginQueue)) window.BDFDB_Global = Object.assign({}, window.BDFDB_Global, {pluginQueue: []});
|
||||||
|
if (!window.BDFDB_Global.downloadModal) {
|
||||||
|
window.BDFDB_Global.downloadModal = true;
|
||||||
|
BdApi.showConfirmationModal("Library Missing", `The Library Plugin needed for ${config.info.name} is missing. Please click "Download Now" to install it.`, {
|
||||||
|
confirmText: "Download Now",
|
||||||
|
cancelText: "Cancel",
|
||||||
|
onCancel: _ => {delete window.BDFDB_Global.downloadModal;},
|
||||||
|
onConfirm: _ => {
|
||||||
|
delete window.BDFDB_Global.downloadModal;
|
||||||
|
this.downloadLibrary();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!window.BDFDB_Global.pluginQueue.includes(config.info.name)) window.BDFDB_Global.pluginQueue.push(config.info.name);
|
||||||
|
}
|
||||||
|
start () {this.load();}
|
||||||
|
stop () {}
|
||||||
|
getSettingsPanel () {
|
||||||
|
let template = document.createElement("template");
|
||||||
|
template.innerHTML = `<div style="color: var(--header-primary); font-size: 16px; font-weight: 300; white-space: pre; line-height: 22px;">The Library Plugin needed for ${config.info.name} is missing.\nPlease click <a style="font-weight: 500;">Download Now</a> to install it.</div>`;
|
||||||
|
template.content.firstElementChild.querySelector("a").addEventListener("click", this.downloadLibrary);
|
||||||
|
return template.content.firstElementChild;
|
||||||
|
}
|
||||||
|
} : (([Plugin, BDFDB]) => {
|
||||||
|
var audios, choices, firedEvents;
|
||||||
|
var volumes = {};
|
||||||
|
|
||||||
|
const removeAllKey = "REMOVE_ALL_BDFDB_DEVILBRO_DO_NOT_COPY";
|
||||||
|
const defaultDevice = "default";
|
||||||
|
|
||||||
|
var currentDevice = defaultDevice, createdAudios = {}, repatchIncoming;
|
||||||
|
|
||||||
|
let types = {};
|
||||||
|
|
||||||
|
const message1Types = {
|
||||||
|
dm: {src: "./message3.mp3", name: "Message (Direct Message)", force: null, focus: true},
|
||||||
|
groupdm: {src: "./message3.mp3", name: "Message (Group Message)", force: null, focus: true},
|
||||||
|
mentioned: {src: "./message2.mp3", name: "Message Mentioned", force: false, focus: true},
|
||||||
|
reply: {src: "./message2.mp3", name: "Message Mentioned (reply)", force: false, focus: true},
|
||||||
|
role: {src: "./mention1.mp3", name: "Message Mentioned (role)", force: false, focus: true},
|
||||||
|
everyone: {src: "./mention2.mp3", name: "Message Mentioned (@everyone)", force: false, focus: true},
|
||||||
|
here: {src: "./mention3.mp3", name: "Message Mentioned (@here)", force: false, focus: true}
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultAudios = {
|
||||||
|
"---": {
|
||||||
|
"---": null
|
||||||
|
},
|
||||||
|
"Discord": {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const WebAudioSound = class WebAudioSound {
|
||||||
|
constructor (type) {
|
||||||
|
this._name = type;
|
||||||
|
this._src = audios[choices[type].category][choices[type].sound] || types[type].src;
|
||||||
|
this._volume = choices[type].volume;
|
||||||
|
}
|
||||||
|
loop () {
|
||||||
|
this._ensureAudio().then(audio => {
|
||||||
|
audio.loop = true;
|
||||||
|
audio.play();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
play () {
|
||||||
|
this._ensureAudio().then(audio => {
|
||||||
|
audio.loop = false;
|
||||||
|
audio.play();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
pause () {
|
||||||
|
this._audio.then(audio => {
|
||||||
|
audio.pause();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
stop () {
|
||||||
|
this._destroyAudio();
|
||||||
|
}
|
||||||
|
setTime (time) {
|
||||||
|
this._audio.then(audio => {
|
||||||
|
audio.currentTime = time;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setLoop (loop) {
|
||||||
|
this._audio.then(audio => {
|
||||||
|
audio.loop = loop;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
_destroyAudio () {
|
||||||
|
if (this._audio) {
|
||||||
|
this._audio.then(audio => {
|
||||||
|
audio.pause();
|
||||||
|
audio.src = "";
|
||||||
|
});
|
||||||
|
this._audio = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ensureAudio () {
|
||||||
|
return this._audio = this._audio || new Promise((callback, errorCallback) => {
|
||||||
|
let audio = new Audio;
|
||||||
|
audio.src = this._src && this._src.startsWith("data") ? this._src.replace(/ /g, "") : this._src;
|
||||||
|
audio.onloadeddata = _ => {
|
||||||
|
audio.volume = Math.min((BDFDB.LibraryModules.MediaDeviceUtils.getOutputVolume() / 100) * (this._volume / 100) * (volumes.globalVolume / 100), 1);
|
||||||
|
BDFDB.LibraryModules.PlatformUtils.embedded && audio.setSinkId(currentDevice || defaultDevice);
|
||||||
|
callback(audio);
|
||||||
|
};
|
||||||
|
audio.onerror = _ => errorCallback(new Error("could not play audio"));
|
||||||
|
audio.onended = _ => this._destroyAudio();
|
||||||
|
audio.load();
|
||||||
|
}), this._audio;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return class NotificationSounds extends Plugin {
|
||||||
|
onLoad () {
|
||||||
|
audios = {};
|
||||||
|
choices = {};
|
||||||
|
firedEvents = {};
|
||||||
|
|
||||||
|
this.defaults = {
|
||||||
|
volumes: {
|
||||||
|
globalVolume: {value: 100, description: "Global Notification Sounds Volume"}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.patchPriority = 9;
|
||||||
|
|
||||||
|
const soundKeys = BDFDB.LibraryModules.SoundParser.keys();
|
||||||
|
for (let key of soundKeys) {
|
||||||
|
const id = key.replace("./", "").replace(".mp3", "");
|
||||||
|
const name = id == "reconnect" ? "Invited To Speak" : id.replace("ddr-", "HotKeys_").replace("ptt_", "Push2Talk_").split("_").map(BDFDB.LibraryModules.StringUtils.upperCaseFirstChar).join(" ").replace(/1$/g, "");
|
||||||
|
const src = BDFDB.LibraryModules.SoundParser(key);
|
||||||
|
|
||||||
|
let soundPackName = id.split("_")[0];
|
||||||
|
if (soundPackName != id && soundKeys.filter(n => n.indexOf(`./${soundPackName}`) > -1).length > 10) {
|
||||||
|
soundPackName = BDFDB.LibraryModules.StringUtils.upperCaseFirstChar(soundPackName);
|
||||||
|
if (!defaultAudios[soundPackName]) defaultAudios[soundPackName] = {};
|
||||||
|
defaultAudios[soundPackName][name.replace(new RegExp(`${soundPackName} `, "i"), "").replace(/bootup/i, "Discodo")] = src;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
defaultAudios.Discord[name] = src;
|
||||||
|
if (this.isSoundUsedAnywhere(id)) types[id] = {
|
||||||
|
name: name,
|
||||||
|
src: src,
|
||||||
|
mute: id.startsWith("call_") ? null : false,
|
||||||
|
force: id == "message1" ? false : null,
|
||||||
|
focus: id == "message1" ? true : false
|
||||||
|
};
|
||||||
|
if (id == "message1") {
|
||||||
|
types[id].mute = true;
|
||||||
|
for (let subType in message1Types) types[subType] = {
|
||||||
|
name: message1Types[subType].name,
|
||||||
|
src: BDFDB.LibraryModules.SoundParser(message1Types[subType].src),
|
||||||
|
mute: true,
|
||||||
|
force: message1Types[subType].force,
|
||||||
|
focus: message1Types[subType].focus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
types = BDFDB.ObjectUtils.sort(types, "name");
|
||||||
|
}
|
||||||
|
for (let pack in defaultAudios) defaultAudios[pack] = BDFDB.ObjectUtils.sort(defaultAudios[pack]);
|
||||||
|
}
|
||||||
|
|
||||||
|
onStart () {
|
||||||
|
if (BDFDB.LibraryModules.PlatformUtils.embedded) {
|
||||||
|
let change = _ => {
|
||||||
|
if (window.navigator.mediaDevices && window.navigator.mediaDevices.enumerateDevices) {
|
||||||
|
window.navigator.mediaDevices.enumerateDevices().then(enumeratedDevices => {
|
||||||
|
let id = BDFDB.LibraryModules.MediaDeviceUtils.getOutputDeviceId();
|
||||||
|
let allDevices = BDFDB.LibraryModules.MediaDeviceUtils.getOutputDevices();
|
||||||
|
let filteredDevices = enumeratedDevices.filter(d => d.kind == "audiooutput" && d.deviceId != "communications");
|
||||||
|
let deviceIndex = BDFDB.LibraryModules.ArrayUtils(allDevices).sortBy(d => d.index).findIndex(d => d.id == id);
|
||||||
|
let deviceViaId = allDevices[id];
|
||||||
|
let deviceViaIndex = filteredDevices[deviceIndex];
|
||||||
|
if (deviceViaId && deviceViaIndex && deviceViaIndex.label != deviceViaId.name) deviceViaIndex = filteredDevices.find(d => d.label == deviceViaId.name);
|
||||||
|
currentDevice = deviceViaIndex ? deviceViaIndex.deviceId : defaultDevice;
|
||||||
|
}).catch(_ => {
|
||||||
|
currentDevice = defaultDevice;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
BDFDB.StoreChangeUtils.add(this, BDFDB.LibraryModules.MediaDeviceUtils, change);
|
||||||
|
change();
|
||||||
|
}
|
||||||
|
|
||||||
|
BDFDB.PatchUtils.patch(this, BDFDB.LibraryModules.DispatchApiUtils, "dispatch", {before: e => {
|
||||||
|
if (BDFDB.ObjectUtils.is(e.methodArguments[0]) && e.methodArguments[0].type == "MESSAGE_CREATE" && e.methodArguments[0].message) {
|
||||||
|
const message = e.methodArguments[0].message;
|
||||||
|
const guildId = message.guild_id || null;
|
||||||
|
if (message.author.id != BDFDB.UserUtils.me.id && !BDFDB.LibraryModules.RelationshipStore.isBlocked(message.author.id)) {
|
||||||
|
const channel = BDFDB.LibraryModules.ChannelStore.getChannel(message.channel_id);
|
||||||
|
const isGroupDM = channel.isGroupDM();
|
||||||
|
const muted = BDFDB.LibraryModules.MutedUtils.isGuildOrCategoryOrChannelMuted(guildId, channel.id);
|
||||||
|
const focused = document.hasFocus() && BDFDB.LibraryModules.LastChannelStore.getChannelId() == channel.id;
|
||||||
|
if (!guildId && !muted && !(choices[isGroupDM ? "groupdm" : "dm"].focus && focused)) {
|
||||||
|
this.fireEvent(isGroupDM ? "groupdm" : "dm");
|
||||||
|
this.playAudio(isGroupDM ? "groupdm" : "dm");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (guildId) {
|
||||||
|
if (BDFDB.LibraryModules.MentionUtils.isRawMessageMentioned({rawMessage: message, userId: BDFDB.UserUtils.me.id})) {
|
||||||
|
if (message.mentions.length && !this.isSuppressMentionsEnabled(guildId, channel.id)) for (const mention of message.mentions) if (mention.id == BDFDB.UserUtils.me.id) {
|
||||||
|
if (message.message_reference && !message.interaction && (!muted || choices.reply.force) && !(choices.reply.focus && focused)) {
|
||||||
|
this.fireEvent("reply");
|
||||||
|
this.playAudio("reply");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!message.message_reference && (!muted || choices.mentioned.force) && !(choices.mentioned.focus && focused)) {
|
||||||
|
this.fireEvent("mentioned");
|
||||||
|
this.playAudio("mentioned");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (message.mention_roles.length && !BDFDB.LibraryModules.MutedUtils.isSuppressRolesEnabled(guildId, channel.id) && (!muted || choices.role.force) && !(choices.role.focus && focused)) {
|
||||||
|
const member = BDFDB.LibraryModules.MemberStore.getMember(guildId, BDFDB.UserUtils.me.id);
|
||||||
|
if (member && member.roles.length) for (const roleId of message.mention_roles) if (member.roles.includes(roleId)) {
|
||||||
|
this.fireEvent("role");
|
||||||
|
this.playAudio("role");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (message.mention_everyone && !BDFDB.LibraryModules.MutedUtils.isSuppressEveryoneEnabled(guildId, channel.id)) {
|
||||||
|
if (message.content.indexOf("@everyone") > -1 && (!muted || choices.everyone.force) && !(choices.everyone.focus && focused)) {
|
||||||
|
this.fireEvent("everyone");
|
||||||
|
this.playAudio("everyone");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (message.content.indexOf("@here") > -1 && (!muted || choices.here.force) && !(choices.here.focus && focused)) {
|
||||||
|
this.fireEvent("here");
|
||||||
|
this.playAudio("here");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (BDFDB.LibraryModules.MutedUtils.allowAllMessages(channel) && (!muted || choices.message1.force) && !(choices.message1.focus && focused)) {
|
||||||
|
this.fireEvent("message1");
|
||||||
|
this.playAudio("message1");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
|
||||||
|
BDFDB.PatchUtils.patch(this, BDFDB.LibraryModules.DesktopNotificationUtils, "showNotification", {before: e => {
|
||||||
|
let soundObjIndex = Array.from(e.methodArguments).findIndex(n => n && n.sound);
|
||||||
|
if (soundObjIndex && e.methodArguments[soundObjIndex].sound.includes("message")) e.methodArguments[soundObjIndex].sound = null;
|
||||||
|
}});
|
||||||
|
BDFDB.PatchUtils.patch(this, BDFDB.LibraryModules.SoundUtils, "playSound", {instead: e => {
|
||||||
|
let type = e.methodArguments[0];
|
||||||
|
if (type && choices[type]) {
|
||||||
|
e.stopOriginalMethodCall();
|
||||||
|
BDFDB.TimeUtils.timeout(_ => {
|
||||||
|
if (type == "message1") {
|
||||||
|
let called = false;
|
||||||
|
for (let subType of [type].concat(Object.keys(message1Types))) if (firedEvents[subType]) {
|
||||||
|
delete firedEvents[subType];
|
||||||
|
called = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!called) this.playAudio(type);
|
||||||
|
}
|
||||||
|
else this.playAudio(type);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else e.callOriginalMethodAfterwards();
|
||||||
|
}});
|
||||||
|
BDFDB.PatchUtils.patch(this, BDFDB.LibraryModules.SoundUtils, "createSound", {after: e => {
|
||||||
|
let type = e.methodArguments[0];
|
||||||
|
if (type && choices[type]) {
|
||||||
|
let audio = new WebAudioSound(type);
|
||||||
|
createdAudios[type] = audio;
|
||||||
|
return audio;
|
||||||
|
}
|
||||||
|
else BDFDB.LogUtils.warn(`Could not create Sound for "${type}".`, this);
|
||||||
|
}});
|
||||||
|
|
||||||
|
this.loadAudios();
|
||||||
|
this.loadChoices();
|
||||||
|
|
||||||
|
let callListenerModule = BDFDB.ModuleUtils.findByProperties("handleRingUpdate");
|
||||||
|
if (callListenerModule) {
|
||||||
|
callListenerModule.terminate();
|
||||||
|
BDFDB.PatchUtils.patch(this, callListenerModule, "handleRingUpdate", {instead: e => {
|
||||||
|
if (BDFDB.LibraryModules.CallUtils.getCalls().filter(call => call.ringing.length > 0 && BDFDB.LibraryModules.VoiceUtils.getCurrentClientVoiceChannelId() === call.channelId).length > 0 && !BDFDB.LibraryModules.SoundStateUtils.isSoundDisabled("call_calling") && !BDFDB.LibraryModules.StreamerModeStore.disableSounds) {
|
||||||
|
createdAudios["call_calling"].loop();
|
||||||
|
}
|
||||||
|
else createdAudios["call_calling"].stop();
|
||||||
|
}});
|
||||||
|
callListenerModule.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.forceUpdateAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
onStop () {
|
||||||
|
for (let type in createdAudios) if (createdAudios[type]) createdAudios[type].stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
getSettingsPanel (collapseStates = {}) {
|
||||||
|
let successSavedAudio = data => {
|
||||||
|
BDFDB.NotificationUtils.toast(`Sound ${data.sound} was added to category ${data.category}.`, {type: "success"});
|
||||||
|
if (!audios[data.category]) audios[data.category] = {};
|
||||||
|
audios[data.category][data.sound] = data.source;
|
||||||
|
BDFDB.DataUtils.save(audios, this, "audios");
|
||||||
|
BDFDB.PluginUtils.refreshSettingsPanel(this, settingsPanel, collapseStates);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
let settingsPanel;
|
||||||
|
return settingsPanel = BDFDB.PluginUtils.createSettingsPanel(this, {
|
||||||
|
collapseStates: collapseStates,
|
||||||
|
children: _ => {
|
||||||
|
let settingsItems = [];
|
||||||
|
|
||||||
|
settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.CollapseContainer, {
|
||||||
|
title: "Settings",
|
||||||
|
collapseStates: collapseStates,
|
||||||
|
children: Object.keys(volumes).map(key => BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsSaveItem, {
|
||||||
|
type: "Slider",
|
||||||
|
plugin: this,
|
||||||
|
keys: ["volumes", key],
|
||||||
|
basis: "50%",
|
||||||
|
label: this.defaults.volumes[key].description,
|
||||||
|
value: volumes[key]
|
||||||
|
}))
|
||||||
|
}));
|
||||||
|
|
||||||
|
settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.CollapseContainer, {
|
||||||
|
title: "Add new Sound",
|
||||||
|
collapseStates: collapseStates,
|
||||||
|
children: [
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, {
|
||||||
|
className: BDFDB.disCN.margintop4,
|
||||||
|
children: [
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, {
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, {
|
||||||
|
title: "Categoryname",
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, {
|
||||||
|
className: "input-newsound input-category",
|
||||||
|
value: "",
|
||||||
|
placeholder: "Categoryname"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, {
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, {
|
||||||
|
title: "Soundname",
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, {
|
||||||
|
className: "input-newsound input-sound",
|
||||||
|
value: "",
|
||||||
|
placeholder: "Soundname"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, {
|
||||||
|
className: BDFDB.disCN.margintop4,
|
||||||
|
align: BDFDB.LibraryComponents.Flex.Align.END,
|
||||||
|
children: [
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, {
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, {
|
||||||
|
title: "Source",
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TextInput, {
|
||||||
|
className: "input-newsound input-source",
|
||||||
|
type: "file",
|
||||||
|
filter: ["audio", "video"],
|
||||||
|
useFilePath: true,
|
||||||
|
value: "",
|
||||||
|
placeholder: "Source"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Button, {
|
||||||
|
style: {marginBottom: 1},
|
||||||
|
onClick: _ => {
|
||||||
|
for (let input of settingsPanel.props._node.querySelectorAll(".input-newsound " + BDFDB.dotCN.input)) if (!input.value || input.value.length == 0 || input.value.trim().length == 0) return BDFDB.NotificationUtils.toast("Fill out all fields to add a new sound", {type: "danger"});
|
||||||
|
let category = settingsPanel.props._node.querySelector(".input-category " + BDFDB.dotCN.input).value.trim();
|
||||||
|
let sound = settingsPanel.props._node.querySelector(".input-sound " + BDFDB.dotCN.input).value.trim();
|
||||||
|
let source = settingsPanel.props._node.querySelector(".input-source " + BDFDB.dotCN.input).value.trim();
|
||||||
|
if (source.indexOf("http") == 0) BDFDB.LibraryRequires.request(source, (error, response, result) => {
|
||||||
|
if (response) {
|
||||||
|
let type = response.headers["content-type"];
|
||||||
|
if (type && (type.indexOf("octet-stream") > -1 || type.indexOf("audio") > -1 || type.indexOf("video") > -1)) return successSavedAudio({category, sound, source});
|
||||||
|
}
|
||||||
|
BDFDB.NotificationUtils.toast("Use a valid direct link to a video or audio source, they usually end on something like .mp3, .mp4 or .wav", {type: "danger"});
|
||||||
|
});
|
||||||
|
else BDFDB.LibraryRequires.fs.readFile(source, (error, response) => {
|
||||||
|
if (error) BDFDB.NotificationUtils.toast("Could not fetch file. Please make sure the file exists", {type: "danger"});
|
||||||
|
else return successSavedAudio({category, sound, source: `data:audio/mpeg;base64,${response.toString("base64")}`});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
children: BDFDB.LanguageUtils.LanguageStrings.SAVE
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
|
||||||
|
settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.CollapseContainer, {
|
||||||
|
title: "Sound Configuration",
|
||||||
|
collapseStates: collapseStates,
|
||||||
|
children: Object.keys(types).map(type => [
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, {
|
||||||
|
className: BDFDB.disCN.marginbottom8,
|
||||||
|
align: BDFDB.LibraryComponents.Flex.Align.CENTER,
|
||||||
|
direction: BDFDB.LibraryComponents.Flex.Direction.HORIZONTAL,
|
||||||
|
children: [
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsLabel, {
|
||||||
|
label: types[type].name
|
||||||
|
}),
|
||||||
|
types[type].force != null ? BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, {
|
||||||
|
type: "Switch",
|
||||||
|
mini: true,
|
||||||
|
grow: 0,
|
||||||
|
label: "Force Play",
|
||||||
|
labelChildren: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, {
|
||||||
|
text: "Plays the Sound even if the Channel, the Message was sent in, is muted",
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, {
|
||||||
|
name: BDFDB.LibraryComponents.SvgIcon.Names.QUESTIONMARK,
|
||||||
|
style: {marginLeft: 4, marginRight: -2},
|
||||||
|
width: 14,
|
||||||
|
height: 14
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
value: choices[type].force,
|
||||||
|
onChange: value => {
|
||||||
|
choices[type].force = value;
|
||||||
|
this.saveChoice(type, false);
|
||||||
|
}
|
||||||
|
}) : null,
|
||||||
|
types[type].focus != null ? BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, {
|
||||||
|
type: "Switch",
|
||||||
|
mini: true,
|
||||||
|
grow: 0,
|
||||||
|
label: "Focus Mute",
|
||||||
|
labelChildren: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.TooltipContainer, {
|
||||||
|
text: "Does not play the Sound when the Channel, the Message was sent in, is currently opened",
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, {
|
||||||
|
name: BDFDB.LibraryComponents.SvgIcon.Names.QUESTIONMARK,
|
||||||
|
style: {marginLeft: 4, marginRight: -2},
|
||||||
|
width: 14,
|
||||||
|
height: 14
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
value: choices[type].focus,
|
||||||
|
onChange: value => {
|
||||||
|
choices[type].focus = value;
|
||||||
|
this.saveChoice(type, false);
|
||||||
|
}
|
||||||
|
}) : null,
|
||||||
|
types[type].mute !== null && BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SettingsItem, {
|
||||||
|
type: "Switch",
|
||||||
|
mini: true,
|
||||||
|
grow: 0,
|
||||||
|
label: "Mute in",
|
||||||
|
labelChildren: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Status, {
|
||||||
|
style: {marginLeft: 6},
|
||||||
|
size: 12,
|
||||||
|
status: BDFDB.DiscordConstants.StatusTypes.DND
|
||||||
|
}),
|
||||||
|
value: choices[type].mute,
|
||||||
|
onChange: value => {
|
||||||
|
choices[type].mute = value;
|
||||||
|
this.saveChoice(type, false);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
].filter(n => n)
|
||||||
|
}),
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, {
|
||||||
|
className: BDFDB.disCN.marginbottom8,
|
||||||
|
children: [
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, {
|
||||||
|
grow: 0,
|
||||||
|
shrink: 0,
|
||||||
|
basis: "31%",
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, {
|
||||||
|
title: "Category",
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Select, {
|
||||||
|
value: choices[type].category,
|
||||||
|
options: Object.keys(audios).map(name => ({value: name, label: name})),
|
||||||
|
searchable: true,
|
||||||
|
onChange: value => {
|
||||||
|
const categorySounds = audios[value] || {};
|
||||||
|
choices[type].category = value;
|
||||||
|
choices[type].sound = categorySounds[types[type].name] ? types[type].name : Object.keys(categorySounds)[0];
|
||||||
|
this.saveChoice(type, true);
|
||||||
|
BDFDB.PluginUtils.refreshSettingsPanel(this, settingsPanel, collapseStates);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, {
|
||||||
|
grow: 0,
|
||||||
|
shrink: 0,
|
||||||
|
basis: "31%",
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, {
|
||||||
|
title: "Sound",
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Select, {
|
||||||
|
value: choices[type].sound,
|
||||||
|
options: Object.keys(audios[choices[type].category] || {}).map(name => ({value: name, label: name})),
|
||||||
|
searchable: true,
|
||||||
|
onChange: value => {
|
||||||
|
choices[type].sound = value;
|
||||||
|
this.saveChoice(type, true);
|
||||||
|
BDFDB.PluginUtils.refreshSettingsPanel(this, settingsPanel, collapseStates);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, {
|
||||||
|
grow: 0,
|
||||||
|
shrink: 0,
|
||||||
|
basis: "31%",
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, {
|
||||||
|
title: "Volume",
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Slider, {
|
||||||
|
defaultValue: choices[type].volume,
|
||||||
|
digits: 1,
|
||||||
|
onValueRender: value => {
|
||||||
|
return value + "%";
|
||||||
|
},
|
||||||
|
onValueChange: value => {
|
||||||
|
choices[type].volume = value;
|
||||||
|
this.saveChoice(type, true);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormDivider, {
|
||||||
|
className: BDFDB.disCN.marginbottom8
|
||||||
|
})
|
||||||
|
]).flat(10).filter(n => n)
|
||||||
|
}));
|
||||||
|
|
||||||
|
let removeableCategories = [{value: removeAllKey, label: BDFDB.LanguageUtils.LanguageStrings.FORM_LABEL_ALL}].concat(Object.keys(audios).filter(category => !(defaultAudios[category] && !Object.keys(audios[category] || {}).filter(sound => defaultAudios[category][sound] === undefined).length)).map(name => ({value: name, label: name})));
|
||||||
|
let removeableSounds = {};
|
||||||
|
for (let category of removeableCategories) removeableSounds[category.value] = [{value: removeAllKey, label: BDFDB.LanguageUtils.LanguageStrings.FORM_LABEL_ALL}].concat(Object.keys(audios[category.value] || {}).filter(sound => !(defaultAudios[category.value] && defaultAudios[category.value][sound] !== undefined)).map(name => ({value: name, label: name})));
|
||||||
|
settingsItems.push(BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.CollapseContainer, {
|
||||||
|
title: "Remove Sounds",
|
||||||
|
collapseStates: collapseStates,
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex, {
|
||||||
|
className: BDFDB.disCN.margintop4,
|
||||||
|
align: BDFDB.LibraryComponents.Flex.Align.END,
|
||||||
|
children: [
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, {
|
||||||
|
grow: 0,
|
||||||
|
shrink: 0,
|
||||||
|
basis: "35%",
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, {
|
||||||
|
title: "Category",
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Select, {
|
||||||
|
key: "REMOVE_CATEGORY",
|
||||||
|
value: removeAllKey,
|
||||||
|
options: removeableCategories,
|
||||||
|
searchable: true,
|
||||||
|
onChange: (category, instance) => {
|
||||||
|
let soundSelectIns = BDFDB.ReactUtils.findOwner(BDFDB.ReactUtils.findOwner(instance, {name: ["BDFDB_Modal", "BDFDB_SettingsPanel"], up: true}), {key: "REMOVE_SOUND"});
|
||||||
|
if (soundSelectIns && removeableSounds[category.value]) {
|
||||||
|
soundSelectIns.props.options = removeableSounds[category.value];
|
||||||
|
soundSelectIns.props.value = removeAllKey;
|
||||||
|
BDFDB.ReactUtils.forceUpdate(soundSelectIns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, {
|
||||||
|
grow: 0,
|
||||||
|
shrink: 0,
|
||||||
|
basis: "35%",
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.FormComponents.FormItem, {
|
||||||
|
title: "Sound",
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Select, {
|
||||||
|
key: "REMOVE_SOUND",
|
||||||
|
value: removeAllKey,
|
||||||
|
options: removeableSounds[removeAllKey],
|
||||||
|
searchable: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Flex.Child, {
|
||||||
|
grow: 0,
|
||||||
|
shrink: 1,
|
||||||
|
basis: "25%",
|
||||||
|
children: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Button, {
|
||||||
|
style: {marginBottom: 1},
|
||||||
|
color: BDFDB.LibraryComponents.Button.Colors.RED,
|
||||||
|
onClick: (event, instance) => {
|
||||||
|
let wrapperIns = BDFDB.ReactUtils.findOwner(instance, {name: ["BDFDB_Modal", "BDFDB_SettingsPanel"], up: true});
|
||||||
|
let categorySelectIns = BDFDB.ReactUtils.findOwner(wrapperIns, {key: "REMOVE_CATEGORY"});
|
||||||
|
let soundSelectIns = BDFDB.ReactUtils.findOwner(wrapperIns, {key: "REMOVE_SOUND"});
|
||||||
|
if (categorySelectIns && soundSelectIns) {
|
||||||
|
let soundAmount = 0;
|
||||||
|
let catAll = categorySelectIns.props.value == removeAllKey;
|
||||||
|
let soundAll = soundSelectIns.props.value == removeAllKey;
|
||||||
|
if (catAll) soundAmount = BDFDB.ArrayUtils.sum(Object.keys(audios).map(category => Object.keys(audios[category] || {}).filter(sound => !(defaultAudios[category] && defaultAudios[category][sound] !== undefined)).length));
|
||||||
|
else if (soundAll) soundAmount = Object.keys(audios[categorySelectIns.props.value] || {}).filter(sound => !(defaultAudios[categorySelectIns.props.value] && defaultAudios[categorySelectIns.props.value][sound] !== undefined)).length;
|
||||||
|
else if (audios[categorySelectIns.props.value][soundSelectIns.props.value]) soundAmount = 1;
|
||||||
|
|
||||||
|
if (soundAmount) BDFDB.ModalUtils.confirm(this, `Are you sure you want to delete ${soundAmount} added Sound${soundAmount == 1 ? "" : "s"}?`, _ => {
|
||||||
|
if (catAll) BDFDB.DataUtils.remove(this, "audios");
|
||||||
|
else if (soundAll) BDFDB.DataUtils.remove(this, "audios", categorySelectIns.props.value);
|
||||||
|
else {
|
||||||
|
delete audios[categorySelectIns.props.value][soundSelectIns.props.value];
|
||||||
|
if (BDFDB.ObjectUtils.isEmpty(audios[categorySelectIns.props.value])) delete audios[categorySelectIns.props.value];
|
||||||
|
BDFDB.DataUtils.save(audios, this, "audios");
|
||||||
|
}
|
||||||
|
this.loadAudios();
|
||||||
|
this.loadChoices();
|
||||||
|
BDFDB.PluginUtils.refreshSettingsPanel(this, settingsPanel, collapseStates);
|
||||||
|
});
|
||||||
|
else BDFDB.NotificationUtils.toast("No Sounds to delete", {type: "danger"});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
children: BDFDB.LanguageUtils.LanguageStrings.DELETE
|
||||||
|
})
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
|
||||||
|
return settingsItems;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
onSettingsClosed () {
|
||||||
|
if (this.SettingsUpdated) {
|
||||||
|
delete this.SettingsUpdated;
|
||||||
|
for (let type in createdAudios) if (createdAudios[type]) createdAudios[type].stop();
|
||||||
|
createdAudios = {};
|
||||||
|
this.forceUpdateAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
forceUpdateAll () {
|
||||||
|
repatchIncoming = true;
|
||||||
|
createdAudios["call_calling"] = BDFDB.LibraryModules.SoundUtils.createSound("call_calling");
|
||||||
|
volumes = BDFDB.DataUtils.get(this, "volumes");
|
||||||
|
BDFDB.PatchUtils.forceAllUpdates(this);
|
||||||
|
BDFDB.DiscordUtils.rerenderAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadAudios () {
|
||||||
|
audios = Object.assign({}, BDFDB.DataUtils.load(this, "audios"), defaultAudios);
|
||||||
|
BDFDB.DataUtils.save(BDFDB.ObjectUtils.exclude(audios, Object.keys(defaultAudios)), this, "audios");
|
||||||
|
}
|
||||||
|
|
||||||
|
loadChoices () {
|
||||||
|
let loadedChoices = BDFDB.DataUtils.load(this, "choices");
|
||||||
|
for (let type in types) {
|
||||||
|
let choice = loadedChoices[type] || {}, soundFound = false;
|
||||||
|
for (let category in audios) if (choice.category == category) for (let sound in audios[category]) if (choice.sound == sound) {
|
||||||
|
soundFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!soundFound) choice = {
|
||||||
|
category: "---",
|
||||||
|
sound: "---",
|
||||||
|
volume: 100,
|
||||||
|
mute: types[type].mute,
|
||||||
|
focus: types[type].focus
|
||||||
|
};
|
||||||
|
choices[type] = choice;
|
||||||
|
this.saveChoice(type, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveChoice (type, play) {
|
||||||
|
if (!choices[type]) return;
|
||||||
|
BDFDB.DataUtils.save(choices[type], this, "choices", type);
|
||||||
|
if (play) {
|
||||||
|
this.SettingsUpdated = true;
|
||||||
|
this.playAudio(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
playAudio (type) {
|
||||||
|
if (this.dontPlayAudio(type) || BDFDB.LibraryModules.StreamerModeStore.disableSounds) return;
|
||||||
|
if (createdAudios[type]) createdAudios[type].stop();
|
||||||
|
createdAudios[type] = new WebAudioSound(type);
|
||||||
|
createdAudios[type].play();
|
||||||
|
}
|
||||||
|
|
||||||
|
isSuppressMentionsEnabled (guildId, channelId) {
|
||||||
|
let channelSettings = BDFDB.LibraryModules.MutedUtils.getChannelMessageNotifications(guildId, channelId);
|
||||||
|
return channelSettings && (channelSettings == BDFDB.DiscordConstants.UserNotificationSettings.NO_MESSAGES || channelSettings == BDFDB.DiscordConstants.UserNotificationSettings.NULL && BDFDB.LibraryModules.MutedUtils.getMessageNotifications(guildId) == BDFDB.DiscordConstants.UserNotificationSettings.NO_MESSAGES);
|
||||||
|
}
|
||||||
|
|
||||||
|
dontPlayAudio (type) {
|
||||||
|
let status = BDFDB.UserUtils.getStatus();
|
||||||
|
return choices[type].mute && (status == "dnd" || status == "streaming");
|
||||||
|
}
|
||||||
|
|
||||||
|
fireEvent (type) {
|
||||||
|
firedEvents[type] = true;
|
||||||
|
BDFDB.TimeUtils.timeout(_ => delete firedEvents[type], 3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
isSoundUsedAnywhere (type) {
|
||||||
|
return type != "human_man" && type != "robot_man" && type != "discodo" && type != "overlayunlock" && type != "call_ringing_beat" && !(type != "message1" && /\d$/.test(type));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})(window.BDFDB_Global.PluginUtils.buildPlugin(config));
|
||||||
|
})();
|
||||||
6
.config/BetterDiscord/plugins/PermissionsViewer.config.json
Executable file
6
.config/BetterDiscord/plugins/PermissionsViewer.config.json
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"currentVersionInfo": {
|
||||||
|
"version": "0.2.2",
|
||||||
|
"hasShownChangelog": true
|
||||||
|
}
|
||||||
|
}
|
||||||
736
.config/BetterDiscord/plugins/PermissionsViewer.plugin.js
Executable file
736
.config/BetterDiscord/plugins/PermissionsViewer.plugin.js
Executable file
@@ -0,0 +1,736 @@
|
|||||||
|
/**
|
||||||
|
* @name PermissionsViewer
|
||||||
|
* @version 0.2.2
|
||||||
|
* @authorLink https://twitter.com/IAmZerebos
|
||||||
|
* @website https://github.com/rauenzi/BetterDiscordAddons/tree/master/Plugins/PermissionsViewer
|
||||||
|
* @source https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/PermissionsViewer/PermissionsViewer.plugin.js
|
||||||
|
* @updateUrl https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/PermissionsViewer/PermissionsViewer.plugin.js
|
||||||
|
*/
|
||||||
|
/*@cc_on
|
||||||
|
@if (@_jscript)
|
||||||
|
|
||||||
|
// Offer to self-install for clueless users that try to run this directly.
|
||||||
|
var shell = WScript.CreateObject("WScript.Shell");
|
||||||
|
var fs = new ActiveXObject("Scripting.FileSystemObject");
|
||||||
|
var pathPlugins = shell.ExpandEnvironmentStrings("%APPDATA%\\BetterDiscord\\plugins");
|
||||||
|
var pathSelf = WScript.ScriptFullName;
|
||||||
|
// Put the user at ease by addressing them in the first person
|
||||||
|
shell.Popup("It looks like you've mistakenly tried to run me directly. \n(Don't do that!)", 0, "I'm a plugin for BetterDiscord", 0x30);
|
||||||
|
if (fs.GetParentFolderName(pathSelf) === fs.GetAbsolutePathName(pathPlugins)) {
|
||||||
|
shell.Popup("I'm in the correct folder already.", 0, "I'm already installed", 0x40);
|
||||||
|
} else if (!fs.FolderExists(pathPlugins)) {
|
||||||
|
shell.Popup("I can't find the BetterDiscord plugins folder.\nAre you sure it's even installed?", 0, "Can't install myself", 0x10);
|
||||||
|
} else if (shell.Popup("Should I copy myself to BetterDiscord's plugins folder for you?", 0, "Do you need some help?", 0x34) === 6) {
|
||||||
|
fs.CopyFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf)), true);
|
||||||
|
// Show the user where to put plugins in the future
|
||||||
|
shell.Exec("explorer " + pathPlugins);
|
||||||
|
shell.Popup("I'm installed!", 0, "Successfully installed", 0x40);
|
||||||
|
}
|
||||||
|
WScript.Quit();
|
||||||
|
|
||||||
|
@else@*/
|
||||||
|
|
||||||
|
module.exports = (() => {
|
||||||
|
const config = {info:{name:"PermissionsViewer",authors:[{name:"Zerebos",discord_id:"249746236008169473",github_username:"rauenzi",twitter_username:"ZackRauen"}],version:"0.2.2",description:"Allows you to view a user's permissions. Thanks to Noodlebox for the idea!",github:"https://github.com/rauenzi/BetterDiscordAddons/tree/master/Plugins/PermissionsViewer",github_raw:"https://raw.githubusercontent.com/rauenzi/BetterDiscordAddons/master/Plugins/PermissionsViewer/PermissionsViewer.plugin.js"},changelog:[{title:"Fixes",type:"fixed",items:["Can select other roles in the modal."]}],defaultConfig:[{type:"switch",id:"contextMenus",name:"Context Menus",value:true},{type:"switch",id:"popouts",name:"Popouts",value:true},{type:"radio",id:"displayMode",name:"Modal Display Mode",value:"compact",options:[{name:"Cozy",value:"cozy"},{name:"Compact",value:"compact"}]}],strings:{es:{contextMenuLabel:"Permisos",popoutLabel:"Permisos",modal:{header:"Permisos de ${name}",rolesLabel:"Roles",permissionsLabel:"Permisos",owner:"@propietario"},settings:{popouts:{name:"Mostrar en Popouts",note:"Mostrar los permisos de usuario en popouts como los roles."},contextMenus:{name:"Botón de menú contextual",note:"Añadir un botón para ver permisos en los menús contextuales."}}},pt:{contextMenuLabel:"Permissões",popoutLabel:"Permissões",modal:{header:"Permissões de ${name}",rolesLabel:"Cargos",permissionsLabel:"Permissões",owner:"@dono"},settings:{popouts:{name:"Mostrar em Popouts",note:"Mostrar as permissões em popouts como os cargos."},contextMenus:{name:"Botão do menu de contexto",note:"Adicionar um botão parar ver permissões ao menu de contexto."}}},de:{contextMenuLabel:"Berechtigungen",popoutLabel:"Berechtigungen",modal:{header:"${name}s Berechtigungen",rolesLabel:"Rollen",permissionsLabel:"Berechtigungen",owner:"@eigentümer"},settings:{popouts:{name:"In Popouts anzeigen",note:"Zeigt die Gesamtberechtigungen eines Benutzers in seinem Popup ähnlich den Rollen an."},contextMenus:{name:"Kontextmenü-Schaltfläche",note:"Fügt eine Schaltfläche hinzu, um die Berechtigungen mithilfe von Kontextmenüs anzuzeigen."}}},en:{contextMenuLabel:"Permissions",popoutLabel:"Permissions",modal:{header:"${name}'s Permissions",rolesLabel:"Roles",permissionsLabel:"Permissions",owner:"@owner"},settings:{popouts:{name:"Show In Popouts",note:"Shows a user's total permissions in their popout similar to roles."},contextMenus:{name:"Context Menu Button",note:"Adds a button to view the permissions modal to select context menus."},displayMode:{name:"Modal Display Mode"}}},ru:{contextMenuLabel:"Полномочия",popoutLabel:"Полномочия",modal:{header:"Полномочия ${name}",rolesLabel:"Роли",permissionsLabel:"Полномочия",owner:"Владелец"},settings:{popouts:{name:"Показать во всплывающих окнах",note:"Отображает полномочия пользователя в их всплывающем окне, аналогичном ролям."},contextMenus:{name:"Кнопка контекстного меню",note:"Добавить кнопку для отображения полномочий с помощью контекстных меню."}}}},main:"index.js"};
|
||||||
|
|
||||||
|
return !global.ZeresPluginLibrary ? class {
|
||||||
|
constructor() {this._config = config;}
|
||||||
|
getName() {return config.info.name;}
|
||||||
|
getAuthor() {return config.info.authors.map(a => a.name).join(", ");}
|
||||||
|
getDescription() {return config.info.description;}
|
||||||
|
getVersion() {return config.info.version;}
|
||||||
|
load() {
|
||||||
|
BdApi.showConfirmationModal("Library Missing", `The library plugin needed for ${config.info.name} is missing. Please click Download Now to install it.`, {
|
||||||
|
confirmText: "Download Now",
|
||||||
|
cancelText: "Cancel",
|
||||||
|
onConfirm: () => {
|
||||||
|
require("request").get("https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js", async (error, response, body) => {
|
||||||
|
if (error) return require("electron").shell.openExternal("https://betterdiscord.net/ghdl?url=https://raw.githubusercontent.com/rauenzi/BDPluginLibrary/master/release/0PluginLibrary.plugin.js");
|
||||||
|
await new Promise(r => require("fs").writeFile(require("path").join(BdApi.Plugins.folder, "0PluginLibrary.plugin.js"), body, r));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
start() {}
|
||||||
|
stop() {}
|
||||||
|
} : (([Plugin, Api]) => {
|
||||||
|
const plugin = (Plugin, Api) => {
|
||||||
|
const {Patcher, DiscordModules, WebpackModules, PluginUtilities, Toasts, DiscordClasses, Utilities, DOMTools, ColorConverter, DCM, Structs, ReactTools} = Api;
|
||||||
|
|
||||||
|
const GuildStore = DiscordModules.GuildStore;
|
||||||
|
const SelectedGuildStore = DiscordModules.SelectedGuildStore;
|
||||||
|
const MemberStore = DiscordModules.GuildMemberStore;
|
||||||
|
const UserStore = DiscordModules.UserStore;
|
||||||
|
const DiscordPerms = Object.assign({}, DiscordModules.DiscordConstants.Permissions);
|
||||||
|
const AvatarDefaults = WebpackModules.getByProps("DEFAULT_AVATARS");
|
||||||
|
const UserPopoutSelectors = Object.assign({}, WebpackModules.getByProps("userPopout"), WebpackModules.getByProps("rolesList"));
|
||||||
|
for (const key in UserPopoutSelectors) UserPopoutSelectors[key] = new Structs.Selector(UserPopoutSelectors[key]);
|
||||||
|
const escapeHTML = DOMTools.escapeHTML ? DOMTools.escapeHTML : function(html) {
|
||||||
|
const textNode = document.createTextNode("");
|
||||||
|
const spanElement = document.createElement("span");
|
||||||
|
spanElement.append(textNode);
|
||||||
|
textNode.nodeValue = html;
|
||||||
|
return spanElement.innerHTML;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (DiscordPerms.STREAM) {
|
||||||
|
DiscordPerms.VIDEO = DiscordPerms.STREAM;
|
||||||
|
delete DiscordPerms.STREAM;
|
||||||
|
}
|
||||||
|
if (DiscordPerms.MANAGE_GUILD) {
|
||||||
|
DiscordPerms.MANAGE_SERVER = DiscordPerms.MANAGE_GUILD;
|
||||||
|
delete DiscordPerms.MANAGE_GUILD;
|
||||||
|
}
|
||||||
|
|
||||||
|
return class PermissionsViewer extends Plugin {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.css = `.member-perms-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-perms {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin-top: 2px;
|
||||||
|
max-height: 160px;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-perms .member-perm .perm-circle {
|
||||||
|
border-radius: 50%;
|
||||||
|
height: 12px;
|
||||||
|
margin-right: 4px;
|
||||||
|
width: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-perms .member-perm .name {
|
||||||
|
margin-right: 4px;
|
||||||
|
max-width: 200px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.perm-details-button {
|
||||||
|
cursor: pointer;
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.perm-details {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-perm-details {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-perm-details-button {
|
||||||
|
fill: #72767d;
|
||||||
|
height: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Modal */
|
||||||
|
|
||||||
|
@keyframes permissions-backdrop {
|
||||||
|
to { opacity: 0.85; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes permissions-modal-wrapper {
|
||||||
|
to { transform: scale(1); opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes permissions-backdrop-closing {
|
||||||
|
to { opacity: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes permissions-modal-wrapper-closing {
|
||||||
|
to { transform: scale(0.7); opacity: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper {
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper .callout-backdrop {
|
||||||
|
animation: permissions-backdrop 250ms ease;
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
opacity: 0;
|
||||||
|
background-color: rgb(0, 0, 0);
|
||||||
|
transform: translateZ(0px);
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper.closing .callout-backdrop {
|
||||||
|
animation: permissions-backdrop-closing 200ms linear;
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
animation-delay: 50ms;
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper.closing .modal-wrapper {
|
||||||
|
animation: permissions-modal-wrapper-closing 250ms cubic-bezier(0.19, 1, 0.22, 1);
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper .modal-wrapper {
|
||||||
|
animation: permissions-modal-wrapper 250ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||||
|
animation-fill-mode: forwards;
|
||||||
|
transform: scale(0.7);
|
||||||
|
transform-origin: 50% 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
contain: content;
|
||||||
|
justify-content: center;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
user-select: none;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper .modal-body {
|
||||||
|
background-color: #36393f;
|
||||||
|
height: 440px;
|
||||||
|
width: auto;
|
||||||
|
/*box-shadow: 0 0 0 1px rgba(32,34,37,.6), 0 2px 10px 0 rgba(0,0,0,.2);*/
|
||||||
|
flex-direction: row;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
contain: layout;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper #permissions-modal {
|
||||||
|
display: flex;
|
||||||
|
contain: layout;
|
||||||
|
flex-direction: column;
|
||||||
|
pointer-events: auto;
|
||||||
|
border: 1px solid rgba(28,36,43,.6);
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 2px 10px 0 rgba(0,0,0,.2);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper .header {
|
||||||
|
background-color: #35393e;
|
||||||
|
box-shadow: 0 2px 3px 0 rgba(0,0,0,.2);
|
||||||
|
padding: 12px 20px;
|
||||||
|
z-index: 1;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 700;
|
||||||
|
line-height: 19px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-side, .perm-side {
|
||||||
|
flex-direction: column;
|
||||||
|
padding-left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.role-scroller, .perm-scroller {
|
||||||
|
contain: layout;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 1px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper .scroller-title {
|
||||||
|
color: #fff;
|
||||||
|
padding: 8px 0 4px 4px;
|
||||||
|
margin-right: 8px;
|
||||||
|
border-bottom: 1px solid rgba(0,0,0,0.3);
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper .role-side {
|
||||||
|
width: auto;
|
||||||
|
min-width: 150px;
|
||||||
|
background: #2f3136;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 1px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper .role-scroller {
|
||||||
|
contain: layout;
|
||||||
|
flex: 1;
|
||||||
|
min-height: 1px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper .role-item {
|
||||||
|
display: flex;
|
||||||
|
border-radius: 2px;
|
||||||
|
padding: 6px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #dcddde;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper .role-item:hover {
|
||||||
|
background-color: rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper .role-item.selected {
|
||||||
|
background-color: rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper .perm-side {
|
||||||
|
width: 250px;
|
||||||
|
background-color: #36393f;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 1px;
|
||||||
|
position: relative;
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper .perm-item {
|
||||||
|
box-shadow: inset 0 -1px 0 rgba(79,84,92,.3);
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 44px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper .perm-item.allowed svg {
|
||||||
|
fill: #43B581;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper .perm-item.denied svg {
|
||||||
|
fill: #F04747;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper .perm-name {
|
||||||
|
display: inline;
|
||||||
|
flex: 1;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 400;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
user-select: text;
|
||||||
|
color: #dcddde;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.member-perms::-webkit-scrollbar-thumb, .member-perms::-webkit-scrollbar-track,
|
||||||
|
#permissions-modal-wrapper *::-webkit-scrollbar-thumb, #permissions-modal-wrapper *::-webkit-scrollbar-track {
|
||||||
|
background-clip: padding-box;
|
||||||
|
border-radius: 7.5px;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 3px;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-perms:hover::-webkit-scrollbar-thumb, .member-perms:hover::-webkit-scrollbar-track,
|
||||||
|
#permissions-modal-wrapper *:hover::-webkit-scrollbar-thumb, #permissions-modal-wrapper *:hover::-webkit-scrollbar-track {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-perms::-webkit-scrollbar-track,
|
||||||
|
#permissions-modal-wrapper *::-webkit-scrollbar-track {
|
||||||
|
border-width: initial;
|
||||||
|
background-color: transparent;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-perms::-webkit-scrollbar-thumb,
|
||||||
|
#permissions-modal-wrapper *::-webkit-scrollbar-thumb {
|
||||||
|
border: 2px solid transparent;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: move;
|
||||||
|
background-color: rgba(32,34,37,.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.member-perms::-webkit-scrollbar,
|
||||||
|
#permissions-modal-wrapper *::-webkit-scrollbar {
|
||||||
|
height: 8px;
|
||||||
|
width: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.theme-light #permissions-modal-wrapper #permissions-modal {
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light #permissions-modal-wrapper .modal-body {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light #permissions-modal-wrapper .header {
|
||||||
|
background: transparent;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light #permissions-modal-wrapper .role-side {
|
||||||
|
background: rgba(0,0,0,.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light #permissions-modal-wrapper .perm-side {
|
||||||
|
background: rgba(0,0,0,.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-light #permissions-modal-wrapper .role-item,
|
||||||
|
.theme-light #permissions-modal-wrapper .perm-name {
|
||||||
|
color: #000;
|
||||||
|
}`;
|
||||||
|
this.jumbo = `#permissions-modal-wrapper #permissions-modal {
|
||||||
|
height: 840px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal-wrapper #permissions-modal .perm-side {
|
||||||
|
width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal .perm-scroller {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-content: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
#permissions-modal .perm-item {
|
||||||
|
width: 50%;
|
||||||
|
}`;
|
||||||
|
this.listHTML = `<div id="permissions-popout">
|
||||||
|
<div class="member-perms-header \${bodyTitle}">
|
||||||
|
<div class="member-perms-title">\${label}</div>
|
||||||
|
<span class="perm-details">
|
||||||
|
<svg name="Details" viewBox="0 0 24 24" class="perm-details-button" fill="currentColor">
|
||||||
|
<path d="M0 0h24v24H0z" fill="none"/>
|
||||||
|
<path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<ul class="member-perms \${root} \${rolesList} \${endBodySection}"></ul>
|
||||||
|
</div>`;
|
||||||
|
this.itemHTML = `<li class="member-perm \${role}">
|
||||||
|
<div class="perm-circle \${roleCircle}"></div>
|
||||||
|
<div class="name \${roleName}"></div>
|
||||||
|
</li>`;
|
||||||
|
this.modalHTML = `<div id="permissions-modal-wrapper">
|
||||||
|
<div class="callout-backdrop \${backdrop}"></div>
|
||||||
|
<div class="modal-wrapper \${modal}">
|
||||||
|
<div id="permissions-modal" class="\${inner}">
|
||||||
|
<div class="header"><div class="title">\${header}</div></div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="role-side">
|
||||||
|
<span class="scroller-title role-list-title">\${rolesLabel}</span>
|
||||||
|
<div class="role-scroller">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="perm-side">
|
||||||
|
<span class="scroller-title perm-list-title">\${permissionsLabel}</span>
|
||||||
|
<div class="perm-scroller">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
this.modalItem = `<div class="perm-item"><span class="perm-name"></span></div>`;
|
||||||
|
this.modalButton = `<div class="role-item"><span class="role-name"></span></div>`;
|
||||||
|
this.modalButtonUser = `<div class="role-item"><div class="wrapper-2F3Zv8 xsmall-3afG_L"><div class="image-33JSyf xsmall-3afG_L" style="background-image: url('\${avatarUrl}');"></div></div><span class="role-name marginLeft8-1YseBe"></span></div>`;
|
||||||
|
this.permAllowedIcon = `<svg height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>`;
|
||||||
|
this.permDeniedIcon = `<svg height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.42 0-8-3.58-8-8 0-1.85.63-3.55 1.69-4.9L16.9 18.31C15.55 19.37 13.85 20 12 20zm6.31-3.1L7.1 5.69C8.45 4.63 10.15 4 12 4c4.42 0 8 3.58 8 8 0 1.85-.63 3.55-1.69 4.9z"/></svg>`;
|
||||||
|
|
||||||
|
this.cancelUserPopout = () => {};
|
||||||
|
this.contextMenuPatches = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
onStart() {
|
||||||
|
PluginUtilities.addStyle(this.getName(), this.css);
|
||||||
|
|
||||||
|
this.listHTML = Utilities.formatTString(this.listHTML, DiscordClasses.UserPopout);
|
||||||
|
this.listHTML = Utilities.formatTString(this.listHTML, DiscordClasses.PopoutRoles);
|
||||||
|
this.itemHTML = Utilities.formatTString(this.itemHTML, DiscordClasses.PopoutRoles);
|
||||||
|
this.modalHTML = Utilities.formatTString(this.modalHTML, DiscordClasses.Backdrop);
|
||||||
|
this.modalHTML = Utilities.formatTString(this.modalHTML, DiscordClasses.Modals);
|
||||||
|
|
||||||
|
this.promises = {state: {cancelled: false}, cancel() {this.state.cancelled = true;}};
|
||||||
|
if (this.settings.popouts) this.bindPopouts();
|
||||||
|
if (this.settings.contextMenus) this.bindContextMenus();
|
||||||
|
this.setDisplayMode(this.settings.displayMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
onStop() {
|
||||||
|
PluginUtilities.removeStyle(this.getName());
|
||||||
|
this.promises.cancel();
|
||||||
|
this.unbindPopouts();
|
||||||
|
this.unbindContextMenus();
|
||||||
|
}
|
||||||
|
|
||||||
|
setDisplayMode(mode) {
|
||||||
|
if (mode === "cozy") PluginUtilities.addStyle(this.getName() + "-jumbo", this.jumbo);
|
||||||
|
else PluginUtilities.removeStyle(this.getName() + "-jumbo");
|
||||||
|
}
|
||||||
|
|
||||||
|
async bindPopouts() {
|
||||||
|
const popoutMount = (props) => {
|
||||||
|
const popout = document.querySelector(UserPopoutSelectors.userPopout);
|
||||||
|
if (!popout || popout.querySelector("#permissions-popout")) return;
|
||||||
|
const user = MemberStore.getMember(props.guildId, props.user.id);
|
||||||
|
const guild = GuildStore.getGuild(props.guildId);
|
||||||
|
const name = MemberStore.getNick(props.guildId, props.user.id) ?? props.user.username;
|
||||||
|
if (!user || !guild || !name) return;
|
||||||
|
|
||||||
|
const userRoles = user.roles.slice(0);
|
||||||
|
userRoles.push(guild.id);
|
||||||
|
userRoles.reverse();
|
||||||
|
let perms = 0n;
|
||||||
|
|
||||||
|
const permBlock = DOMTools.createElement(Utilities.formatTString(this.listHTML, {label: this.strings.popoutLabel}));
|
||||||
|
const memberPerms = permBlock.querySelector(".member-perms");
|
||||||
|
const strings = DiscordModules.Strings;
|
||||||
|
|
||||||
|
for (let r = 0; r < userRoles.length; r++) {
|
||||||
|
const role = userRoles[r];
|
||||||
|
if (!guild.roles[role]) continue;
|
||||||
|
perms = perms | guild.roles[role].permissions;
|
||||||
|
for (const perm in DiscordPerms) {
|
||||||
|
const permName = strings[perm] || perm.split("_").map(n => n[0].toUpperCase() + n.slice(1).toLowerCase()).join(" ");
|
||||||
|
const hasPerm = (perms & DiscordPerms[perm]) == DiscordPerms[perm];
|
||||||
|
if (hasPerm && !memberPerms.querySelector(`[data-name="${permName}"]`)) {
|
||||||
|
const element = DOMTools.createElement(this.itemHTML);
|
||||||
|
let roleColor = guild.roles[role].colorString;
|
||||||
|
element.querySelector(".name").textContent = permName;
|
||||||
|
element.setAttribute("data-name", permName);
|
||||||
|
if (!roleColor) roleColor = "#B9BBBE";
|
||||||
|
element.querySelector(".perm-circle").style.backgroundColor = ColorConverter.rgbToAlpha(roleColor, 1);
|
||||||
|
element.style.borderColor = ColorConverter.rgbToAlpha(roleColor, 0.6);
|
||||||
|
memberPerms.prepend(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
permBlock.querySelector(".perm-details").addEventListener("click", () => {
|
||||||
|
this.showModal(this.createModalUser(name, user, guild));
|
||||||
|
});
|
||||||
|
const roleList = popout.querySelector(UserPopoutSelectors.rolesList);
|
||||||
|
roleList.parentNode.insertBefore(permBlock, roleList.nextSibling);
|
||||||
|
|
||||||
|
|
||||||
|
const popoutInstance = ReactTools.getOwnerInstance(popout, {include: ["Popout"]});
|
||||||
|
if (!popoutInstance || !popoutInstance.updateOffsets) return;
|
||||||
|
popoutInstance.updateOffsets();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
this.cancelUserPopout = Patcher.after(DiscordModules.UserPopout, "type", (_, __, retVal) => popoutMount(retVal.props));
|
||||||
|
}
|
||||||
|
|
||||||
|
unbindPopouts() {
|
||||||
|
this.cancelUserPopout();
|
||||||
|
}
|
||||||
|
|
||||||
|
async bindContextMenus() {
|
||||||
|
this.patchChannelContextMenu();
|
||||||
|
this.patchGuildContextMenu();
|
||||||
|
this.patchUserContextMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
unbindContextMenus() {
|
||||||
|
for (const cancel of this.contextMenuPatches) cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
async patchGuildContextMenu() {
|
||||||
|
const GuildContextMenu = await DCM.getDiscordMenu("GuildContextMenu");
|
||||||
|
if (this.promises.state.cancelled) return;
|
||||||
|
this.contextMenuPatches.push(Patcher.after(GuildContextMenu, "default", (_, [props], retVal) => {
|
||||||
|
const original = retVal.props.children[0].props.children;
|
||||||
|
const newOne = DCM.buildMenuItem({
|
||||||
|
label: this.strings.contextMenuLabel,
|
||||||
|
action: () => {
|
||||||
|
this.showModal(this.createModalGuild(props.guild.name, props.guild));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (Array.isArray(original)) original.splice(1, 0, newOne);
|
||||||
|
else retVal.props.children[0].props.children = [original, newOne];
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
patchChannelContextMenu() {
|
||||||
|
const patch = (_, [props], retVal) => {
|
||||||
|
const original = retVal.props.children[0].props.children;
|
||||||
|
const newOne = DCM.buildMenuItem({
|
||||||
|
label: this.strings.contextMenuLabel,
|
||||||
|
action: () => {
|
||||||
|
const channel = props.channel;
|
||||||
|
if (!Object.keys(channel.permissionOverwrites).length) return Toasts.info(`#${channel.name} has no permission overrides`);
|
||||||
|
this.showModal(this.createModalChannel(channel.name, channel, props.guild));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (Array.isArray(original)) original.splice(1, 0, newOne);
|
||||||
|
else retVal.props.children[0].props.children = [original, newOne];
|
||||||
|
};
|
||||||
|
|
||||||
|
DCM.getDiscordMenu("ChannelListVoiceChannelContextMenu").then(VoiceChannelContextMenu => {
|
||||||
|
if (this.promises.state.cancelled) return;
|
||||||
|
this.contextMenuPatches.push(Patcher.after(VoiceChannelContextMenu, "default", patch));
|
||||||
|
});
|
||||||
|
|
||||||
|
DCM.getDiscordMenu(m => m.displayName === "ChannelListTextChannelContextMenu" && !m.toString().includes("AnalyticsLocations.CONTEXT_MENU")).then(TextChannelContextMenu => {
|
||||||
|
if (this.promises.state.cancelled) return;
|
||||||
|
this.contextMenuPatches.push(Patcher.after(TextChannelContextMenu, "default", patch));
|
||||||
|
});
|
||||||
|
|
||||||
|
DCM.getDiscordMenu(m => m.displayName === "ChannelListTextChannelContextMenu" && m.toString().includes("AnalyticsLocations.CONTEXT_MENU")).then(CategoryChannelContextMenu => {
|
||||||
|
if (this.promises.state.cancelled) return;
|
||||||
|
this.contextMenuPatches.push(Patcher.after(CategoryChannelContextMenu, "default", patch));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async patchUserContextMenu() {
|
||||||
|
const UserContextMenu = await DCM.getDiscordMenu("GuildChannelUserContextMenu");
|
||||||
|
if (this.promises.state.cancelled) return;
|
||||||
|
this.contextMenuPatches.push(Patcher.after(UserContextMenu, "default", (_, [props], retVal) => {
|
||||||
|
const guildId = SelectedGuildStore.getGuildId();
|
||||||
|
const guild = GuildStore.getGuild(guildId);
|
||||||
|
if (!guild) return;
|
||||||
|
const original = retVal.props.children.props.children[1].props.children;
|
||||||
|
const newOne = DCM.buildMenuItem({
|
||||||
|
label: this.strings.contextMenuLabel,
|
||||||
|
action: () => {
|
||||||
|
const user = MemberStore.getMember(guildId, props.user.id);
|
||||||
|
const name = user.nick ? user.nick : UserStore.getUser(user.userId).username;
|
||||||
|
this.showModal(this.createModalUser(name, user, guild));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (Array.isArray(original)) original.splice(1, 0, newOne);
|
||||||
|
else retVal.props.children.props.children[1].props.children = [original, newOne];
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
showModal(modal) {
|
||||||
|
const popout = document.querySelector(UserPopoutSelectors.userPopout);
|
||||||
|
if (popout) popout.style.display = "none";
|
||||||
|
const app = document.querySelector(".app-19_DXt");
|
||||||
|
if (app) app.append(modal);
|
||||||
|
else document.querySelector("#app-mount").append(modal);
|
||||||
|
}
|
||||||
|
|
||||||
|
createModalChannel(name, channel, guild) {
|
||||||
|
return this.createModal(`#${name}`, channel.permissionOverwrites, guild.roles, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
createModalUser(name, user, guild) {
|
||||||
|
const userRoles = user.roles.slice(0);
|
||||||
|
const guildRoles = Object.assign({}, guild.roles);
|
||||||
|
|
||||||
|
userRoles.push(guild.id);
|
||||||
|
userRoles.sort((a, b) => {return guildRoles[b].position - guildRoles[a].position;});
|
||||||
|
|
||||||
|
if (user.userId == guild.ownerId) {
|
||||||
|
const ALL_PERMISSIONS = Object.values(DiscordModules.DiscordConstants.Permissions).reduce((all, p) => all | p);
|
||||||
|
userRoles.push(user.userId);
|
||||||
|
guildRoles[user.userId] = {name: this.strings.modal.owner, permissions: ALL_PERMISSIONS};
|
||||||
|
}
|
||||||
|
return this.createModal(name, userRoles, guildRoles);
|
||||||
|
}
|
||||||
|
|
||||||
|
createModalGuild(name, guild) {
|
||||||
|
return this.createModal(name, guild.roles);
|
||||||
|
}
|
||||||
|
|
||||||
|
createModal(title, displayRoles, referenceRoles, isOverride = false) {
|
||||||
|
if (!referenceRoles) referenceRoles = displayRoles;
|
||||||
|
const modal = DOMTools.createElement(Utilities.formatTString(Utilities.formatTString(this.modalHTML, this.strings.modal), {name: escapeHTML(title)}));
|
||||||
|
modal.querySelector(".callout-backdrop").addEventListener("click", () => {
|
||||||
|
modal.classList.add("closing");
|
||||||
|
setTimeout(() => {modal.remove();}, 300);
|
||||||
|
});
|
||||||
|
|
||||||
|
const strings = DiscordModules.Strings;
|
||||||
|
for (const r in displayRoles) {
|
||||||
|
const role = Array.isArray(displayRoles) ? displayRoles[r] : r;
|
||||||
|
const user = UserStore.getUser(role) || {avatarURL: AvatarDefaults.DEFAULT_AVATARS[Math.floor(Math.random() * AvatarDefaults.DEFAULT_AVATARS.length)], username: role};
|
||||||
|
const member = MemberStore.getMember(SelectedGuildStore.getGuildId(), role) || {colorString: ""};
|
||||||
|
const item = DOMTools.createElement(!isOverride || displayRoles[role].type == 0 ? this.modalButton : Utilities.formatTString(this.modalButtonUser, {avatarUrl: user.avatarURL}));
|
||||||
|
if (!isOverride || displayRoles[role].type == 0) item.style.color = referenceRoles[role].colorString;
|
||||||
|
else item.style.color = member.colorString;
|
||||||
|
if (isOverride) item.querySelector(".role-name").innerHTML = escapeHTML(displayRoles[role].type == 0 ? referenceRoles[role].name : user.username);
|
||||||
|
else item.querySelector(".role-name").innerHTML = escapeHTML(referenceRoles[role].name);
|
||||||
|
modal.querySelector(".role-scroller").append(item);
|
||||||
|
item.addEventListener("click", () => {
|
||||||
|
modal.querySelectorAll(".role-item.selected").forEach(e => e.classList.remove("selected"));
|
||||||
|
item.classList.add("selected");
|
||||||
|
const allowed = isOverride ? displayRoles[role].allow : referenceRoles[role].permissions;
|
||||||
|
const denied = isOverride ? displayRoles[role].deny : null;
|
||||||
|
|
||||||
|
const permList = modal.querySelector(".perm-scroller");
|
||||||
|
permList.innerHTML = "";
|
||||||
|
for (const perm in DiscordPerms) {
|
||||||
|
const element = DOMTools.createElement(this.modalItem);
|
||||||
|
const permAllowed = (allowed & DiscordPerms[perm]) == DiscordPerms[perm];
|
||||||
|
const permDenied = isOverride ? (denied & DiscordPerms[perm]) == DiscordPerms[perm] : !permAllowed;
|
||||||
|
if (!permAllowed && !permDenied) continue;
|
||||||
|
if (permAllowed) {
|
||||||
|
element.classList.add("allowed");
|
||||||
|
element.prepend(DOMTools.createElement(this.permAllowedIcon));
|
||||||
|
}
|
||||||
|
if (permDenied) {
|
||||||
|
element.classList.add("denied");
|
||||||
|
element.prepend(DOMTools.createElement(this.permDeniedIcon));
|
||||||
|
}
|
||||||
|
element.querySelector(".perm-name").textContent = strings[perm] || perm.split("_").map(n => n[0].toUpperCase() + n.slice(1).toLowerCase()).join(" ");
|
||||||
|
permList.append(element);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
item.addEventListener("contextmenu", (e) => {
|
||||||
|
DCM.openContextMenu(e, DCM.buildMenu([
|
||||||
|
{label: DiscordModules.Strings.COPY_ID, action: () => {DiscordModules.ElectronModule.copy(role);}}
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
modal.querySelector(".role-item").click();
|
||||||
|
|
||||||
|
return modal;
|
||||||
|
}
|
||||||
|
|
||||||
|
getSettingsPanel() {
|
||||||
|
const panel = this.buildSettingsPanel();
|
||||||
|
panel.addListener((id, checked) => {
|
||||||
|
if (id == "popouts") {
|
||||||
|
if (checked) this.bindPopouts();
|
||||||
|
else this.unbindPopouts();
|
||||||
|
}
|
||||||
|
if (id == "contextMenus") {
|
||||||
|
if (checked) this.bindContextMenus();
|
||||||
|
this.unbindContextMenus();
|
||||||
|
}
|
||||||
|
if (id == "displayMode") this.setDisplayMode(checked);
|
||||||
|
});
|
||||||
|
return panel.getElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
return plugin(Plugin, Api);
|
||||||
|
})(global.ZeresPluginLibrary.buildPlugin(config));
|
||||||
|
})();
|
||||||
|
/*@end@*/
|
||||||
52
.config/BetterDiscord/plugins/PinDMs.config.json
Executable file
52
.config/BetterDiscord/plugins/PinDMs.config.json
Executable file
@@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"all": {
|
||||||
|
"general": {
|
||||||
|
"pinIcon": true,
|
||||||
|
"unreadAmount": true,
|
||||||
|
"channelAmount": true
|
||||||
|
},
|
||||||
|
"pinned": {
|
||||||
|
"662731831908761636": {
|
||||||
|
"channelList": {
|
||||||
|
"6103412714032048": {
|
||||||
|
"id": "6103412714032048",
|
||||||
|
"name": "Pins",
|
||||||
|
"dms": [
|
||||||
|
"851263280551165977",
|
||||||
|
"709081938622939166",
|
||||||
|
"736308155964850176",
|
||||||
|
"662733504534020118",
|
||||||
|
"740325591684874305",
|
||||||
|
"815678838809296926"
|
||||||
|
],
|
||||||
|
"pos": 0,
|
||||||
|
"collapsed": false,
|
||||||
|
"color": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"preCategories": {
|
||||||
|
"friends": {
|
||||||
|
"enabled": false,
|
||||||
|
"collapsed": false
|
||||||
|
},
|
||||||
|
"blocked": {
|
||||||
|
"enabled": false,
|
||||||
|
"collapsed": false
|
||||||
|
},
|
||||||
|
"bots": {
|
||||||
|
"enabled": false,
|
||||||
|
"collapsed": false
|
||||||
|
},
|
||||||
|
"groups": {
|
||||||
|
"enabled": false,
|
||||||
|
"collapsed": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"recentOrder": {
|
||||||
|
"channelList": false,
|
||||||
|
"guildList": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1346
.config/BetterDiscord/plugins/PinDMs.plugin.js
Executable file
1346
.config/BetterDiscord/plugins/PinDMs.plugin.js
Executable file
File diff suppressed because it is too large
Load Diff
16
.config/BetterDiscord/plugins/PluginRepo.config.json
Executable file
16
.config/BetterDiscord/plugins/PluginRepo.config.json
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"all": {
|
||||||
|
"cached": "2 7 8 9 11 14 15 17 28 29 30 31 59 60 61 62 63 64 65 66 67 68 69 70 71 73 74 75 76 77 78 80 81 82 83 84 85 86 87 88 89 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 116 120 122 126 127 131 132 133 134 137 138 139 146 157 158 159 160 162 164 171 173 176 179 181 182 183 184 185 186 188 189 190 192 193 195 196 197 200 201 220 228 234 236 237 238 240 245 247 253 262 272 274 278 284 287 291 292 293 295 301 306 312 314 317 318 323 331 336 337 338 340 344 349 350 351 352 353 354 356 361 364 366 368 370 377 379 381 382 383 390 395 398 401 404 407 420 421 429 438 441 442 476 479 489 509 518 519 520 521 523 525 535 538 539 547 554 557 566 577 579 589 592 593 598 599 606 608 611 614 620 621 627 638 644 645 670 671 686 692 693 694",
|
||||||
|
"filters": {
|
||||||
|
"updated": true,
|
||||||
|
"outdated": true,
|
||||||
|
"downloadable": true
|
||||||
|
},
|
||||||
|
"general": {
|
||||||
|
"notifyOutdated": true,
|
||||||
|
"notifyNewEntries": false,
|
||||||
|
"startDownloaded": false,
|
||||||
|
"startUpdated": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1128
.config/BetterDiscord/plugins/PluginRepo.plugin.js
Executable file
1128
.config/BetterDiscord/plugins/PluginRepo.plugin.js
Executable file
File diff suppressed because it is too large
Load Diff
6
.config/BetterDiscord/plugins/ZeresPluginLibrary.config.json
Executable file
6
.config/BetterDiscord/plugins/ZeresPluginLibrary.config.json
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"currentVersionInfo": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"hasShownChangelog": true
|
||||||
|
}
|
||||||
|
}
|
||||||
9
.config/BetterDiscord/plugins/noDoubleBack.plugin.js
Executable file
9
.config/BetterDiscord/plugins/noDoubleBack.plugin.js
Executable file
@@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* @name No_Double_Back
|
||||||
|
*/
|
||||||
|
const {ipcRenderer} = require('electron')
|
||||||
|
module.exports = class noDoubleBack {
|
||||||
|
load() { this.DISCORD_NAVIGATE_BACK = ipcRenderer._events.DISCORD_NAVIGATE_BACK}
|
||||||
|
start() { ipcRenderer.removeListener('DISCORD_NAVIGATE_BACK', ipcRenderer._events.DISCORD_NAVIGATE_BACK) }
|
||||||
|
stop() { ipcRenderer.addListener('DISCORD_NAVIGATE_BACK', this.DISCORD_NAVIGATE_BACK) }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user