diff --git a/.config/BetterDiscord/plugins/BlurNSFW.config.json b/.config/BetterDiscord/plugins/BlurNSFW.config.json index a9d7282..57cab7f 100755 --- a/.config/BetterDiscord/plugins/BlurNSFW.config.json +++ b/.config/BetterDiscord/plugins/BlurNSFW.config.json @@ -1,6 +1,9 @@ { "currentVersionInfo": { - "version": "0.2.5", + "version": "1.0.1", "hasShownChangelog": true - } + }, + "blurred": [], + "sen": [], + "seen": [] } \ No newline at end of file diff --git a/.config/BetterDiscord/plugins/BlurNSFW.plugin.js b/.config/BetterDiscord/plugins/BlurNSFW.plugin.js index 3ce00aa..1b05541 100755 --- a/.config/BetterDiscord/plugins/BlurNSFW.plugin.js +++ b/.config/BetterDiscord/plugins/BlurNSFW.plugin.js @@ -1,12 +1,11 @@ /** * @name BlurNSFW - * @version 0.2.5 - * @authorLink https://twitter.com/IAmZerebos - * @donate https://paypal.me/ZackRauen - * @patreon https://patreon.com/Zerebos + * @description Blurs images and videos until you hover over them. + * @version 1.0.1 + * @author Zerebos + * @authorId 249746236008169473 * @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) @@ -31,100 +30,243 @@ 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)); +const config = { + info: { + name: "BlurNSFW", + authors: [ + { + name: "Zerebos", + discord_id: "249746236008169473", + github_username: "rauenzi", + twitter_username: "ZackRauen" + } + ], + version: "1.0.1", + description: "Blurs images and videos until you hover over them.", + 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: "What's New?", + type: "fixed", + items: [ + "Context menu and blurring should work again!", + "Blurring and unblurring happen quicker and using less resources now!" + ] + }, + { + title: "Known Issues", + items: [ + "The checkbox in the context menu won't update after clicking.", + "This is just a visual issue, the functionality is fine." + ] + } + ], + defaultConfig: [ + { + type: "switch", + id: "blurNSFW", + name: "Blur NSFW Channels", + note: "This setting automatically blurs media in channels marked NSFW.", + value: true + }, + { + 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" +}; +class Dummy { + constructor() {this._config = config;} + start() {} + stop() {} +} + +if (!global.ZeresPluginLibrary) { + BdApi.showConfirmationModal("Library Missing", `The library plugin needed for ${config.name ?? config.info.name} is missing. Please click Download Now to install it.`, { + confirmText: "Download Now", + cancelText: "Cancel", + onConfirm: () => { + require("request").get("https://betterdiscord.app/gh-redirect?id=9", async (err, resp, body) => { + if (err) return require("electron").shell.openExternal("https://betterdiscord.app/Download?id=9"); + if (resp.statusCode === 302) { + require("request").get(resp.headers.location, async (error, response, content) => { + 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"), content, r)); }); } + else { + 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; + }); +} + +module.exports = !global.ZeresPluginLibrary ? Dummy : (([Plugin, Api]) => { + const plugin = (Plugin, Api) => { + const {ContextMenu, DOM, Webpack, Patcher} = window.BdApi; - const SelectedChannelStore = DiscordModules.SelectedChannelStore; - const ChannelStore = DiscordModules.ChannelStore; - const ReactDOM = DiscordModules.ReactDOM; - const InlineMediaWrapper = WebpackModules.getByProps("ImageReadyStates").default; + const SelectedChannelStore = Webpack.getModule(m => m.getCurrentlySelectedChannelId); + const ChannelStore = Webpack.getModule(m => m.getDMFromUserId); + const InlineMediaWrapper = Webpack.getModule(m => m.toString().includes("renderAccessory")); + const WrapperClasses = Webpack.getModule(m => m.wrapperPlaying); + const Events = require("events"); + const Dispatcher = new Events(); - return class BlurNSFW extends Plugin { - constructor() { + const formatString = (string, values) => { + for (const val in values) { + let replacement = values[val]; + if (Array.isArray(replacement)) replacement = JSON.stringify(replacement); + if (typeof(replacement) === "object" && replacement !== null) replacement = replacement.toString(); + string = string.replace(new RegExp(`{{${val}}}`, "g"), replacement); + } + return string; + }; + + /* globals BdApi:false */ + return class BlurMedia extends Plugin { + constructor(meta) { super(); + this.meta = meta; this.styleTemplate = ` {{blurOnFocus}} - img.blur:hover, - video.blur:hover { + .${WrapperClasses.wrapperPlaying.split(" ").join(".")} video, + .${WrapperClasses.wrapperControlsHidden.split(" ").join(".")} video, + .blur:hover img, + .blur:hover video, + a:hover + div > .blur { transition: {{time}}ms cubic-bezier(.2, .11, 0, 1) !important; filter: blur(0px) !important; } - img.blur, - video.blur { + .blur img, + .blur video { filter: blur({{size}}px) !important; transition: {{time}}ms cubic-bezier(.2, .11, 0, 1) !important; }`; + + this.channelChange = this.channelChange.bind(this); } onStart() { - const blurAccessory = (thisObject) => { + /** @type {Set} */ + this.blurredChannels = new Set(BdApi.loadData(this.meta.name, "blurred") ?? []); + + /** @type {Set} */ + this.seenChannels = new Set(BdApi.loadData(this.meta.name, "seen") ?? []); + + Patcher.after(this.meta.name, InlineMediaWrapper.prototype, "render", (thisObject, _, retVal) => { 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); + if (!this.hasBlur(channel)) return; + if (retVal.props.className) retVal.props.className = retVal.props.className + " blur"; + else retVal.props.className = "blur"; + }); + + Patcher.after(this.meta.name, InlineMediaWrapper.prototype, "componentDidMount", (thisObject) => { + if (thisObject.cancelBlurListener) return; + const listener = () => thisObject.forceUpdate(); + Dispatcher.on("blur", listener); + thisObject.cancelBlurListener = () => Dispatcher.off("blur", listener); + }); + + Patcher.after(this.meta.name, InlineMediaWrapper.prototype, "componentWillUnmount", (thisObject) => { + if (!thisObject.cancelBlurListener) return; + thisObject.cancelBlurListener(); + delete thisObject.cancelBlurListener; + }); this.addStyle(); + + SelectedChannelStore.addChangeListener(this.channelChange); + + this.promises = {state: {cancelled: false}, cancel() {this.state.cancelled = true;}}; + this.patchChannelContextMenu(); } onStop() { - Patcher.unpatchAll(); + BdApi.saveData(this.meta.name, "blurred", this.blurredChannels); + BdApi.saveData(this.meta.name, "seen", this.seenChannels); + this.contextMenuPatch?.(); this.removeStyle(); + SelectedChannelStore.removeChangeListener(this.channelChange); + } + + hasBlur(channel) { + return this.blurredChannels.has(channel.id); + } + + addBlur(channel) { + this.blurredChannels.add(channel.id); + Dispatcher.emit("blur"); + } + + removeBlur(channel) { + this.blurredChannels.delete(channel.id); + Dispatcher.emit("blur"); + } + + channelChange() { + Dispatcher?.removeAllListeners(); + const channel = ChannelStore.getChannel(SelectedChannelStore.getChannelId()); + if (this.seenChannels.has(channel.id)) return; + + this.seenChannels.add(channel.id); + if (this.settings.blurNSFW && channel.nsfw) this.addBlur(channel); + } + + patchChannelContextMenu() { + this.contextMenuPatch = ContextMenu.patch("channel-context", (retVal, props) => { + const newItem = ContextMenu.buildItem({ + type: "toggle", + label: "Blur Media", + active: this.hasBlur(props.channel), + action: () => { + if (this.hasBlur(props.channel)) this.removeBlur(props.channel); + else this.addBlur(props.channel); + } + }); + + retVal.props.children.splice(1, 0, newItem); + }); } addStyle() { - const styleString = Utilities.formatString(this.styleTemplate, { + const styleString = formatString(this.styleTemplate, { size: Math.round(this.settings.blurSize), time: Math.round(this.settings.blurTime), - blurOnFocus: this.settings.blurOnFocus ? "" : ".layer-2KE1M9 img.blur," + blurOnFocus: this.settings.blurOnFocus ? "" : ".layer-1Ixpg3 .blur img," }); - PluginUtilities.addStyle(this.getName(), styleString); + DOM.addStyle(this.meta.name, styleString); } removeStyle() { - PluginUtilities.removeStyle(this.getName()); + DOM.removeStyle(this.meta.name); } getSettingsPanel() { @@ -138,7 +280,6 @@ module.exports = (() => { }; }; - return plugin(Plugin, Api); - })(global.ZeresPluginLibrary.buildPlugin(config)); -})(); + return plugin(Plugin, Api); +})(global.ZeresPluginLibrary.buildPlugin(config)); /*@end@*/ \ No newline at end of file diff --git a/.config/BetterDiscord/plugins/CreationDate.plugin.js b/.config/BetterDiscord/plugins/CreationDate.plugin.js index 5c1f5d0..fa238ae 100755 --- a/.config/BetterDiscord/plugins/CreationDate.plugin.js +++ b/.config/BetterDiscord/plugins/CreationDate.plugin.js @@ -2,44 +2,19 @@ * @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 + * @version 9.9.9 + * @description PLUGIN WAS DISCONTINUED */ 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" - } - } - }; + const changeLog = {}; - 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}`;} + return !window.BDFDB_Global || (!window.BDFDB_Global.loaded && !window.BDFDB_Global.started) ? class { + constructor (meta) {for (let key in meta) this[key] = meta[key];} + getName () {return this.name;} + getAuthor () {return this.author;} + getVersion () {return this.version;} + getDescription () {return `The Library Plugin needed for ${this.name} is missing. Open the Plugin Settings to download it. \n\n${this.description}`;} downloadLibrary () { require("request").get("https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js", (e, r, b) => { @@ -52,7 +27,7 @@ module.exports = (_ => { 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.`, { + BdApi.showConfirmationModal("Library Missing", `The Library Plugin needed for ${this.name} is missing. Please click "Download Now" to install it.`, { confirmText: "Download Now", cancelText: "Cancel", onCancel: _ => {delete window.BDFDB_Global.downloadModal;}, @@ -62,248 +37,40 @@ module.exports = (_ => { } }); } - if (!window.BDFDB_Global.pluginQueue.includes(config.info.name)) window.BDFDB_Global.pluginQueue.push(config.info.name); + if (!window.BDFDB_Global.pluginQueue.includes(this.name)) window.BDFDB_Global.pluginQueue.push(this.name); } start () {this.load();} stop () {} getSettingsPanel () { let template = document.createElement("template"); - template.innerHTML = `
The Library Plugin needed for ${config.info.name} is missing.\nPlease click Download Now to install it.
`; + template.innerHTML = `
The Library Plugin needed for ${this.name} is missing.\nPlease click Download Now to install it.
`; template.content.firstElementChild.querySelector("a").addEventListener("click", this.downloadLibrary); return template.content.firstElementChild; } - } : (([Plugin, BDFDB]) => { + } : (([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" - } - }; - - } + onLoad () {} 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); - } + BDFDB.ModalUtils.open(this, { + header: "PLUGIN WAS DISCONTINUED", + children: [ + BDFDB.ReactUtils.createElement("span", {children: "DISCORD ADDED THIS FEATURE BY THEMSELVES, MAKING THIS PLUGIN USELESS "}), + BDFDB.ReactUtils.createElement("strong", {children: "DELETE"}), + BDFDB.ReactUtils.createElement("span", {children: " TO REMOVE THIS EMPTY PLUGIN FILE."}) + BDFDB.ReactUtils.createElement("strong", {children: "DELETE"}), + BDFDB.ReactUtils.createElement("span", {children: " TO REMOVE THIS EMPTY PLUGIN FILE."}) + ], + buttons: [ + {contents: "DELETE", close: true, color: "RED", onClick: _ => { + BDFDB.LibraryRequires.fs.unlink(BDFDB.LibraryRequires.path.join(BDFDB.BDUtils.getPluginsFolder(), "CreationDate.plugin.js"), error => {}); + BDFDB.LibraryRequires.fs.unlink(BDFDB.LibraryRequires.path.join(BDFDB.BDUtils.getPluginsFolder(), "CreationDate.config.json"), error => {}); + }} + ] }); } - - 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}}" - }; - } - } + onStop () {} }; - })(window.BDFDB_Global.PluginUtils.buildPlugin(config)); -})(); \ No newline at end of file + })(window.BDFDB_Global.PluginUtils.buildPlugin(changeLog)); +})(); diff --git a/.config/BetterDiscord/plugins/EditRoles.plugin.js b/.config/BetterDiscord/plugins/EditRoles.plugin.js index 640c1b7..be03333 100755 --- a/.config/BetterDiscord/plugins/EditRoles.plugin.js +++ b/.config/BetterDiscord/plugins/EditRoles.plugin.js @@ -2,7 +2,7 @@ * @name EditRoles * @author DevilBro * @authorId 278543574059057154 - * @version 1.0.9 + * @version 1.1.2 * @description Allows you to locally edit Roles * @invite Jx3TjNS * @donate https://www.paypal.me/MircoWittrien @@ -13,25 +13,16 @@ */ 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" - } - } + const changeLog = { + }; 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}`;} + constructor (meta) {for (let key in meta) this[key] = meta[key];} + getName () {return this.name;} + getAuthor () {return this.author;} + getVersion () {return this.version;} + getDescription () {return `The Library Plugin needed for ${this.name} is missing. Open the Plugin Settings to download it. \n\n${this.description}`;} downloadLibrary () { require("request").get("https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js", (e, r, b) => { @@ -44,7 +35,7 @@ module.exports = (_ => { 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.`, { + BdApi.showConfirmationModal("Library Missing", `The Library Plugin needed for ${this.name} is missing. Please click "Download Now" to install it.`, { confirmText: "Download Now", cancelText: "Cancel", onCancel: _ => {delete window.BDFDB_Global.downloadModal;}, @@ -54,13 +45,13 @@ module.exports = (_ => { } }); } - if (!window.BDFDB_Global.pluginQueue.includes(config.info.name)) window.BDFDB_Global.pluginQueue.push(config.info.name); + if (!window.BDFDB_Global.pluginQueue.includes(this.name)) window.BDFDB_Global.pluginQueue.push(this.name); } start () {this.load();} stop () {} getSettingsPanel () { let template = document.createElement("template"); - template.innerHTML = `
The Library Plugin needed for ${config.info.name} is missing.\nPlease click Download Now to install it.
`; + template.innerHTML = `
The Library Plugin needed for ${this.name} is missing.\nPlease click Download Now to install it.
`; template.content.firstElementChild.querySelector("a").addEventListener("click", this.downloadLibrary); return template.content.firstElementChild; } @@ -71,18 +62,21 @@ module.exports = (_ => { onLoad () { this.patchedModules = { before: { + RoleMention: "default", + AutocompleteRoleResult: "render", MessageHeader: "default", ChannelMembers: "render", MemberListItem: "render", + UserPopoutBodySection: "default", UserPopoutBody: "default" + }, + after: { + RichRoleMention: "RoleMention" } }; } 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]; @@ -168,14 +162,15 @@ module.exports = (_ => { 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") { + if (child && child.props && typeof child.props.label == "function" && changedRoles[child.props.id]) { + let data = changedRoles[child.props.id]; let renderLabel = child.props.label; - child.props.label = (...args) => { + child.props.label = BDFDB.TimeUtils.suppress((...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}))); + if (data.color && label.props.children[0] && label.props.children[0].props) label.props.children[0].props.color = BDFDB.ColorUtils.convert(data.color, "hex"); + if (data.name && label.props.children[1] && label.props.children[1].props && label.props.children[1].props.children) label.props.children[1].props.children = data.name; return label; - }; + }, "Error in renderLabel of UserRolesItems", this); } } } @@ -223,6 +218,30 @@ module.exports = (_ => { ].flat(10).filter(n => n); } + processRichRoleMention (e) { + if (e.instance.props.id && changedRoles[e.instance.props.id]) { + e.returnvalue.props.color = changedRoles[e.instance.props.id].color ? BDFDB.ColorUtils.convert(changedRoles[e.instance.props.id].color, "int") : e.returnvalue.props.color; + e.returnvalue.props.children[1] = changedRoles[e.instance.props.id].name || e.returnvalue.props.children[1]; + } + } + + processRoleMention (e) { + if (e.instance.props.roleId && changedRoles[e.instance.props.roleId]) { + e.instance.props.roleColor = changedRoles[e.instance.props.roleId].color ? BDFDB.ColorUtils.convert(changedRoles[e.instance.props.roleId].color, "int") : e.instance.props.roleColor; + e.instance.props.children = [`@${changedRoles[e.instance.props.roleId].name || e.instance.props.children[1]}`]; + if (e.instance.props.content && e.instance.props.content[0]) e.instance.props.content[0].content = `@${changedRoles[e.instance.props.roleId].name || e.instance.props.children[1]}`; + } + } + + processAutocompleteRoleResult (e) { + if (e.instance.props.role && changedRoles[e.instance.props.role.id]) { + e.instance.props.role = Object.assign({}, e.instance.props.role); + e.instance.props.role.color = changedRoles[e.instance.props.role.id].color ? BDFDB.ColorUtils.convert(changedRoles[e.instance.props.role.id].color, "int") : e.instance.props.role.color; + e.instance.props.role.colorString = changedRoles[e.instance.props.role.id].color ? BDFDB.ColorUtils.convert(changedRoles[e.instance.props.role.id].color, "hex") : e.instance.props.role.colorString; + e.instance.props.role.name = changedRoles[e.instance.props.role.id].name || e.instance.props.role.name; + } + } + 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") { @@ -243,6 +262,10 @@ module.exports = (_ => { } } + processUserPopoutBodySection (e) { + if (e.instance.props.guild) e.instance.props.guild = this.changeRolesInGuild(e.instance.props.guild); + } + processUserPopoutBody (e) { if (e.instance.props.guild) e.instance.props.guild = this.changeRolesInGuild(e.instance.props.guild); } @@ -677,5 +700,5 @@ module.exports = (_ => { } } }; - })(window.BDFDB_Global.PluginUtils.buildPlugin(config)); + })(window.BDFDB_Global.PluginUtils.buildPlugin(changeLog)); })(); \ No newline at end of file diff --git a/.config/BetterDiscord/plugins/Freemoji.plugin.js b/.config/BetterDiscord/plugins/Freemoji.plugin.js deleted file mode 100755 index 330b2ab..0000000 --- a/.config/BetterDiscord/plugins/Freemoji.plugin.js +++ /dev/null @@ -1,374 +0,0 @@ -/** -* @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@*/ diff --git a/.config/BetterDiscord/plugins/ImageUtilities.config.json b/.config/BetterDiscord/plugins/ImageUtilities.config.json index 1581d7a..c5aad78 100755 --- a/.config/BetterDiscord/plugins/ImageUtilities.config.json +++ b/.config/BetterDiscord/plugins/ImageUtilities.config.json @@ -48,7 +48,8 @@ "galleryMode": true, "details": true, "copyImage": true, - "saveImage": true + "saveImage": true, + "jumpTo": true }, "zoomSettings": { "lensSize": 1459, diff --git a/.config/BetterDiscord/plugins/ImageUtilities.plugin.js b/.config/BetterDiscord/plugins/ImageUtilities.plugin.js index 2d69237..6ebae79 100755 --- a/.config/BetterDiscord/plugins/ImageUtilities.plugin.js +++ b/.config/BetterDiscord/plugins/ImageUtilities.plugin.js @@ -2,7 +2,7 @@ * @name ImageUtilities * @author DevilBro * @authorId 278543574059057154 - * @version 4.8.2 + * @version 4.9.5 * @description Adds several Utilities for Images/Videos (Gallery, Download, Reverse Search, Zoom, Copy, etc.) * @invite Jx3TjNS * @donate https://www.paypal.me/MircoWittrien @@ -13,20 +13,16 @@ */ module.exports = (_ => { - const config = { - "info": { - "name": "ImageUtilities", - "author": "DevilBro", - "version": "4.8.2", - "description": "Adds several Utilities for Images/Videos (Gallery, Download, Reverse Search, Zoom, Copy, etc.)" - } + const changeLog = { + }; 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}`;} + constructor (meta) {for (let key in meta) this[key] = meta[key];} + getName () {return this.name;} + getAuthor () {return this.author;} + getVersion () {return this.version;} + getDescription () {return `The Library Plugin needed for ${this.name} is missing. Open the Plugin Settings to download it. \n\n${this.description}`;} downloadLibrary () { require("request").get("https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js", (e, r, b) => { @@ -39,7 +35,7 @@ module.exports = (_ => { 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.`, { + BdApi.showConfirmationModal("Library Missing", `The Library Plugin needed for ${this.name} is missing. Please click "Download Now" to install it.`, { confirmText: "Download Now", cancelText: "Cancel", onCancel: _ => {delete window.BDFDB_Global.downloadModal;}, @@ -49,13 +45,13 @@ module.exports = (_ => { } }); } - if (!window.BDFDB_Global.pluginQueue.includes(config.info.name)) window.BDFDB_Global.pluginQueue.push(config.info.name); + if (!window.BDFDB_Global.pluginQueue.includes(this.name)) window.BDFDB_Global.pluginQueue.push(this.name); } start () {this.load();} stop () {} getSettingsPanel () { let template = document.createElement("template"); - template.innerHTML = `
The Library Plugin needed for ${config.info.name} is missing.\nPlease click Download Now to install it.
`; + template.innerHTML = `
The Library Plugin needed for ${this.name} is missing.\nPlease click Download Now to install it.
`; template.content.firstElementChild.querySelector("a").addEventListener("click", this.downloadLibrary); return template.content.firstElementChild; } @@ -128,8 +124,8 @@ module.exports = (_ => { _this.switchImages(this.props.modalInstance, this.props.offset); }, children: [ - this.props.loadedImage || BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Spinner, { - type: BDFDB.LibraryComponents.Spinner.Type.SPINNING_CIRCLE + this.props.loadedImage || BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SpinnerComponents.Spinner, { + type: BDFDB.LibraryComponents.SpinnerComponents.Types.SPINNING_CIRCLE }), BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.SvgIcon, { className: BDFDB.disCNS._imageutilitiesswitchicon + BDFDB.disCN.svgicon, @@ -209,17 +205,18 @@ module.exports = (_ => { this.defaults = { general: { - nsfwMode: {value: false, description: "Blur Media that is posted in NSFW Channels"} + nsfwMode: {value: false, description: "Blurs Media that is posted in NSFW Channels"} }, viewerSettings: { - zoomMode: {value: true, description: "Enable Zoom Mode to zoom into Images while holding down your Mouse"}, - galleryMode: {value: true, description: "Enable Gallery Mode to quick-switch between Images"}, - details: {value: true, description: "Add Image Details (Name, Size, Amount)"}, - copyImage: {value: true, description: "Add a 'Copy Image' Option"}, - saveImage: {value: true, description: "Add a 'Save Image as' Option"} + zoomMode: {value: true, description: "Enables Zoom Mode to zoom into Images while holding down your Mouse"}, + galleryMode: {value: true, description: "Enables Gallery Mode to quick-switch between Images"}, + details: {value: true, description: "Adds Image Details (Name, Size, Amount)"}, + copyImage: {value: true, description: "Adds a 'Copy Image' Option"}, + saveImage: {value: true, description: "Adds a 'Save Image as' Option"}, + jumpTo: {value: true, description: "Adds a 'Jump to Message' Option in Gallery Mode"} }, zoomSettings: { - pixelMode: {value: false, label: "Use Pixel Lens instead of a Blur Lens"}, + pixelMode: {value: false, label: "Uses Pixel Lens instead of a Blur Lens"}, zoomLevel: {value: 2, digits: 1, minValue: 1, maxValue: 20, unit: "x", label: "ACCESSIBILITY_ZOOM_LEVEL_LABEL"}, lensSize: {value: 200, digits: 0, minValue: 50, maxValue: 5000, unit: "px", label: "context_lenssize"} }, @@ -254,25 +251,40 @@ module.exports = (_ => { } }; - this.patchedModules = { - before: { - LazyImage: "render", - Spoiler: "render", - SimpleMessageAccessories: "default" - }, - after: { - ImageModal: ["render", "componentDidMount", "componentWillUnmount"], - ModalCarousel: "render", - LazyImage: ["componentDidMount", "componentDidUpdate"], - LazyImageZoomable: "render", - Spoiler: "render", - UserBanner: "default" - } + this.modulePatches = { + before: [ + "MessageAccessories", + "Spoiler" + ], + after: [ + "ImageModal", + "LazyImage", + "LazyImageZoomable", + "ModalCarousel", + "Spoiler", + "UserBanner", + "UserThemedBanner" + ], + componentDidMount: [ + "ImageModal", + "LazyImage" + ], + componentDidUpdate: [ + "LazyImage" + ], + componentWillUnmount: [ + "ImageModal" + ] }; this.css = ` ${BDFDB.dotCN._imageutilitiesimagedetails} { display: inline-flex; + font-weight: 500; + color: var(--text-muted); + font-size: 12px; + margin: .25rem 0 .75rem; + line-height: 16px; } ${BDFDB.dotCNS.spoilerhidden + BDFDB.dotCN._imageutilitiesimagedetails} { visibility: hidden; @@ -312,6 +324,13 @@ module.exports = (_ => { object-fit: contain; width: unset; } + ${BDFDB.dotCN.imagemodalnavbutton} { + background: rgba(0, 0, 0, 0.3); + border-radius: 100%; + } + ${BDFDB.dotCN.imagemodalnavbutton}:hover { + background: rgba(0, 0, 0, 0.5); + } ${BDFDB.dotCN._imageutilitiessibling} { display: flex; align-items: center; @@ -393,37 +412,6 @@ module.exports = (_ => { onStart () { BDFDB.ListenerUtils.add(this, document.body, "click", BDFDB.dotCNS.message + BDFDB.dotCNS.imagewrapper + BDFDB.dotCNC.imageoriginallink + BDFDB.dotCNS.message + BDFDB.dotCNS.imagewrapper + "img", e => this.cacheClickedImage(e.target)); - - BDFDB.PatchUtils.patch(this, BDFDB.LibraryModules.MediaComponentUtils, "renderImageComponent", { - after: e => { - if (this.settings.detailsSettings.footnote && e.methodArguments[0].original && e.methodArguments[0].src.indexOf("https://media.discordapp.net/attachments") == 0 && (e.methodArguments[0].className || "").indexOf(BDFDB.disCN.embedmedia) == -1 && (e.methodArguments[0].className || "").indexOf(BDFDB.disCN.embedthumbnail) == -1 && BDFDB.ReactUtils.findChild(e.returnValue, {name: ["ConnectedLazyImageZoomable", "LazyImageZoomable", "LazyImage"]})) { - const altText = e.returnValue.props.children[1] && e.returnValue.props.children[1].props.children; - const details = BDFDB.ReactUtils.createElement(ImageDetailsComponent, { - original: e.methodArguments[0].original, - attachment: { - height: 0, - width: 0, - filename: "unknown.png" - } - }); - e.returnValue.props.children[1] = BDFDB.ReactUtils.createElement("span", { - className: BDFDB.disCN.imagealttext, - children: [ - altText && altText.length >= 50 && BDFDB.ReactUtils.createElement("div", { - children: details - }), - altText && BDFDB.ReactUtils.createElement("span", { - children: altText - }), - (!altText || altText.length < 50) && details - ] - }); - e.returnValue.props.children = BDFDB.ReactUtils.createElement("div", { - children: e.returnValue.props.children - }); - } - } - }); this.forceUpdateAll(); } @@ -674,55 +662,24 @@ module.exports = (_ => { let banner = BDFDB.GuildUtils.getBanner(e.instance.props.guild.id); if (banner) this.injectItem(e, [banner.replace(/\.webp|\.gif/, ".png"), e.instance.props.guild.banner && BDFDB.LibraryModules.IconUtils.isAnimatedIconHash(e.instance.props.guild.banner), banner], BDFDB.LanguageUtils.LibraryStrings.guildbanner); } - else if (e.type != "GuildChannelListContextMenu") this.injectItem(e, [(e.instance.props.guild.getIconURL(4096) || "").replace(/\.webp|\.gif/, ".png"), e.instance.props.guild.icon && BDFDB.LibraryModules.IconUtils.isAnimatedIconHash(e.instance.props.guild.icon) && e.instance.props.guild.getIconURL(4096, true)], BDFDB.LanguageUtils.LibraryStrings.guildicon); + else if (!BDFDB.DOMUtils.getParent(BDFDB.dotCN.channels, e.instance.props.target)) this.injectItem(e, [(e.instance.props.guild.getIconURL(4096) || "").replace(/\.webp|\.gif/, ".png"), e.instance.props.guild.icon && BDFDB.LibraryModules.IconUtils.isAnimatedIconHash(e.instance.props.guild.icon) && e.instance.props.guild.getIconURL(4096, true)], BDFDB.LanguageUtils.LibraryStrings.guildicon); } } onUserContextMenu (e) { - if (e.instance.props.user && this.settings.places.userAvatars && e.subType == "useBlockUserItem") { - const guildId = BDFDB.LibraryModules.LastGuildStore.getGuildId(); - const member = BDFDB.LibraryModules.MemberStore.getMember(guildId, e.instance.props.user.id); - let validUrls = this.filterUrls((e.instance.props.user.getAvatarURL(null, 4096) || "").replace(/\.webp|\.gif/, ".png"), BDFDB.LibraryModules.IconUtils.isAnimatedIconHash(e.instance.props.user.avatar) && e.instance.props.user.getAvatarURL(null, 4096, true), (e.instance.props.user.getAvatarURL(guildId, 4096) || "").replace(/\.webp|\.gif/, ".png"), member && member.avatar && BDFDB.LibraryModules.IconUtils.isAnimatedIconHash(member.avatar) && e.instance.props.user.getAvatarURL(guildId, 4096, true)); - if (!validUrls.length) return; - - if (e.returnvalue.length) e.returnvalue.push(BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuSeparator, {})); - e.returnvalue.push(BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { - label: this.isValid(validUrls[0].file, "video") ? BDFDB.LanguageUtils.LanguageStrings.VIDEO : BDFDB.LanguageUtils.LanguageStrings.IMAGE + " " + BDFDB.LanguageUtils.LanguageStrings.ACTIONS, - id: BDFDB.ContextMenuUtils.createItemId(this.name, "main-subitem"), - children: this.createSubMenus({ - instance: e.instance, - urls: validUrls, - prefix: BDFDB.LanguageUtils.LanguageStrings.USER_SETTINGS_AVATAR - }) - })); + if (e.instance.props.user && this.settings.places.userAvatars) { + const guildId = BDFDB.LibraryStores.SelectedGuildStore.getGuildId(); + const member = BDFDB.LibraryStores.GuildMemberStore.getMember(guildId, e.instance.props.user.id); + this.injectItem(e, [(e.instance.props.user.getAvatarURL(null, 4096) || "").replace(/\.webp|\.gif/, ".png"), BDFDB.LibraryModules.IconUtils.isAnimatedIconHash(e.instance.props.user.avatar) && e.instance.props.user.getAvatarURL(null, 4096, true), (e.instance.props.user.getAvatarURL(guildId, 4096) || "").replace(/\.webp|\.gif/, ".png"), member && member.avatar && BDFDB.LibraryModules.IconUtils.isAnimatedIconHash(member.avatar) && e.instance.props.user.getAvatarURL(guildId, 4096, true)]); } } onGroupDMContextMenu (e) { - if (e.instance.props.channel && e.instance.props.channel.isGroupDM() && this.settings.places.groupIcons) this.injectItem(e, ); + if (e.instance.props.channel && e.instance.props.channel.isGroupDM() && this.settings.places.groupIcons) this.injectItem(e, [(BDFDB.DMUtils.getIcon(e.instance.props.channel.id) || "").replace(/\.webp|\.gif/, ".png")]); } - onChannelContextMenu (e) { - if (e.instance.props.channel && e.instance.props.channel.isGroupDM() && this.settings.places.groupIcons && e.subType == "useChannelLeaveItem") { - let validUrls = this.filterUrls((BDFDB.DMUtils.getIcon(e.instance.props.channel.id) || "").replace(/\.webp|\.gif/, ".png")); - if (!validUrls.length) return; - - if (e.returnvalue.length) e.returnvalue.unshift(BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuSeparator, {})); - e.returnvalue.unshift(BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { - label: this.isValid(validUrls[0].file, "video") ? BDFDB.LanguageUtils.LanguageStrings.VIDEO : BDFDB.LanguageUtils.LanguageStrings.IMAGE + " " + BDFDB.LanguageUtils.LanguageStrings.ACTIONS, - id: BDFDB.ContextMenuUtils.createItemId(this.name, "main-subitem"), - children: this.createSubMenus({ - instance: e.instance, - urls: validUrls, - prefix: BDFDB.LanguageUtils.LanguageStrings.USER_SETTINGS_AVATAR - }) - })); - } - } - - - onNativeContextMenu (e) { - if (e.type == "NativeImageContextMenu" && (e.instance.props.href || e.instance.props.src)) this.injectItem(e, [e.instance.props.href || e.instance.props.src]); + onImageContextMenu (e) { + if (e.instance.props.href || e.instance.props.src) this.injectItem(e, [e.instance.props.href || e.instance.props.src]); } onMessageContextMenu (e) { @@ -760,16 +717,18 @@ module.exports = (_ => { injectItem (e, urls, prefix) { let validUrls = this.filterUrls(...urls); if (!validUrls.length) return; - let [removeParent, removeIndex] = BDFDB.ContextMenuUtils.findItem(e.returnvalue, {id: "copy-native-link", group: true}); - if (removeIndex > -1) { - removeParent.splice(removeIndex, 1); - removeIndex -= 1; + let isNative = false; + let [nativeParent, nativeIndex] = BDFDB.ContextMenuUtils.findItem(e.returnvalue, {id: "copy-native-link", group: true}); + if (nativeIndex > -1) { + if (validUrls.length == 1) isNative = true; + nativeParent.splice(nativeIndex, 1); + nativeIndex -= 1; + } + for (let id of ["open-native-link", "copy-image", "save-image"]) { + let [removeParent, removeIndex] = BDFDB.ContextMenuUtils.findItem(e.returnvalue, {id: id, group: true}); + if (removeIndex > -1) removeParent.splice(removeIndex, 1); } - let [removeParent2, removeIndex2] = BDFDB.ContextMenuUtils.findItem(e.returnvalue, {id: "copy-image", group: true}); - if (removeIndex2 > -1) removeParent2.splice(removeIndex2, 1); - let type = this.isValid(validUrls[0].file, "video") ? BDFDB.LanguageUtils.LanguageStrings.VIDEO : BDFDB.LanguageUtils.LanguageStrings.IMAGE; - let isNative = validUrls.length == 1 && removeIndex > -1; let subMenu = this.createSubMenus({ instance: e.instance, urls: validUrls, @@ -777,10 +736,10 @@ module.exports = (_ => { target: e.instance.props.target }); - let [children, index] = isNative ? [removeParent, removeIndex] : BDFDB.ContextMenuUtils.findItem(e.returnvalue, {id: "devmode-copy-id", group: true}); + let [children, index] = isNative ? [nativeParent, nativeIndex] : BDFDB.ContextMenuUtils.findItem(e.returnvalue, {id: "devmode-copy-id", group: true}); children.splice(index > -1 ? index : children.length, 0, isNative ? subMenu : BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuGroup, { children: BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { - label: type + " " + BDFDB.LanguageUtils.LanguageStrings.ACTIONS, + label: this.isValid(validUrls[0].file, "video") ? this.labels.context_videoactions : this.labels.context_imageactions, id: BDFDB.ContextMenuUtils.createItemId(this.name, "main-subitem"), children: subMenu }) @@ -832,7 +791,7 @@ module.exports = (_ => { label: BDFDB.LanguageUtils.LanguageStrings.COPY_LINK, id: BDFDB.ContextMenuUtils.createItemId(this.name, "copy-link"), action: _ => { - BDFDB.LibraryRequires.electron.clipboard.write({text: urlData.original}); + BDFDB.LibraryModules.WindowUtils.copy(urlData.original.split("?size")[0]); BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LanguageStrings.LINK_COPIED, {type: "success"}); } }), @@ -840,7 +799,7 @@ module.exports = (_ => { label: BDFDB.LanguageUtils.LanguageStrings.COPY_MEDIA_LINK, id: BDFDB.ContextMenuUtils.createItemId(this.name, "copy-media-link"), action: _ => { - BDFDB.LibraryRequires.electron.clipboard.write({text: urlData.file}); + BDFDB.LibraryModules.WindowUtils.copy(urlData.file.split("?size")[0]); BDFDB.NotificationUtils.toast(BDFDB.LanguageUtils.LanguageStrings.LINK_COPIED, {type: "success"}); } }), @@ -923,7 +882,7 @@ module.exports = (_ => { }) : Object.keys(enabledEngines).map(key => BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { label: this.defaults.engines[key].name, id: BDFDB.ContextMenuUtils.createItemId(this.name, "search", key), - color: key == "_all" ? BDFDB.LibraryComponents.MenuItems.Colors.DANGER : BDFDB.LibraryComponents.MenuItems.Colors.DEFAULT, + color: key == "_all" ? BDFDB.DiscordConstants.MenuItemColors.DANGER : BDFDB.DiscordConstants.MenuItemColors.DEFAULT, persisting: true, action: event => { const open = (url, k) => BDFDB.DiscordUtils.openLink(this.defaults.engines[k].url.replace(imgUrlReplaceString, this.defaults.engines[k].raw ? url : encodeURIComponent(url)), {minimized: event.shiftKey}); @@ -946,7 +905,7 @@ module.exports = (_ => { let modal = BDFDB.DOMUtils.getParent(BDFDB.dotCN.modal, e.node); if (modal) { modal.className = BDFDB.DOMUtils.formatClassName(modal.className, this.settings.viewerSettings.galleryMode && BDFDB.disCN._imageutilitiesgallery, this.settings.viewerSettings.details && BDFDB.disCN._imageutilitiesdetailsadded); - if (this.settings.viewerSettings.zoomMode) { + if (this.settings.viewerSettings.galleryMode) { BDFDB.DOMUtils.addClass(modal, BDFDB.disCN.imagemodal); BDFDB.DOMUtils.removeClass(modal, BDFDB.disCN.modalcarouselmodal, BDFDB.disCN.modalcarouselmodalzoomed); } @@ -1050,6 +1009,24 @@ module.exports = (_ => { } }) ], + this.settings.viewerSettings.galleryMode && viewedImage && this.settings.viewerSettings.jumpTo && [ + BDFDB.ReactUtils.createElement("span", { + className: BDFDB.disCN.downloadlink, + children: "|", + style: {margin: "0 5px"} + }), + BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Anchor, { + className: BDFDB.disCN.downloadlink, + children: BDFDB.LanguageUtils.LanguageStrings.JUMP, + onClick: event => { + let layerContainer = !event.shiftKey && BDFDB.DOMUtils.getParent(BDFDB.dotCN.itemlayercontainer, event.currentTarget) + let backdrop = layerContainer && layerContainer.querySelector(BDFDB.dotCN.backdrop); + if (backdrop) backdrop.click(); + let channel = BDFDB.LibraryStores.ChannelStore.getChannel(viewedImage.channelId); + if (channel) BDFDB.LibraryModules.HistoryUtils.transitionTo(BDFDB.DiscordConstants.Routes.CHANNEL(channel.guild_id, channel.id, viewedImage.messageId)); + } + }) + ], this.settings.viewerSettings.zoomMode && !isVideo && [ BDFDB.ReactUtils.createElement("span", { className: BDFDB.disCN.downloadlink, @@ -1091,16 +1068,17 @@ module.exports = (_ => { if (this.settings.viewerSettings.galleryMode && viewedImage) { if (!cachedImages || cachedImages.channelId != viewedImage.channelId || cachedImages.amount && this.getImageIndex(cachedImages.all, viewedImage) == -1) { BDFDB.TimeUtils.clear(viewedImageTimeout); - let channel = BDFDB.LibraryModules.ChannelStore.getChannel(viewedImage.channelId); + let channel = BDFDB.LibraryStores.ChannelStore.getChannel(viewedImage.channelId); BDFDB.LibraryModules.APIUtils.get({ - url: channel && channel.guild_id ? BDFDB.DiscordConstants.Endpoints.SEARCH_GUILD(channel && channel.guild_id) : BDFDB.DiscordConstants.Endpoints.SEARCH_CHANNEL(channel.id), + url: BDFDB.DiscordConstants.Endpoints.MESSAGES(channel.id), query: BDFDB.LibraryModules.APIEncodeUtils.stringify({ channel_id: channel && channel.guild_id ? (BDFDB.ChannelUtils.isThread(channel) && channel.parent_id || channel.id) : null, has: "image", include_nsfw: true, + limit: 100, around: viewedImage.messageId }) - }).catch(_ => { + }).catch(err => { cachedImages = { channelId: viewedImage.channelId, firstReached: null, @@ -1116,7 +1094,7 @@ module.exports = (_ => { if (!viewedImage) return; let messages = [], index = -1; if (result) { - messages = result.body.messages.flat(10).reverse(); + messages = result.body.flat(10).reverse(); cachedImages = {all: this.filterMessagesForImages(messages, viewedImage)}; index = this.getImageIndex(cachedImages.all, viewedImage); } @@ -1173,7 +1151,7 @@ module.exports = (_ => { } processModalCarousel (e) { - if (this.settings.viewerSettings.zoomMode) { + if (this.settings.viewerSettings.galleryMode) { let [children, index] = BDFDB.ReactUtils.findParent(e.returnvalue, {name: "ImageModal"}); if (index > -1) return children[index]; } @@ -1182,10 +1160,19 @@ module.exports = (_ => { processLazyImage (e) { if (e.node) { if (e.instance.props.resized) { - let embed = BDFDB.DOMUtils.getParent(BDFDB.dotCN.embedfull, e.node); - if (embed) embed.style.setProperty("max-width", "unset", "important"); - if (e.instance.state.readyState != BDFDB.LibraryComponents.Image.ImageReadyStates.READY) { - e.instance.state.readyState = BDFDB.LibraryComponents.Image.ImageReadyStates.READY; + for (let selector of ["embedfull", "embedinlinemedia", "embedgridcontainer"]) { + let parent = BDFDB.DOMUtils.getParent(BDFDB.dotCN[selector], e.node); + if (parent) parent.style.setProperty("max-width", "unset", "important"); + } + for (let ele of [e.node.style.getPropertyValue("width") && e.node, ...e.node.querySelectorAll("[style*='width:']")].filter(n => n)) { + ele.style.setProperty("width", e.instance.props.width + "px"); + ele.style.setProperty("max-width", e.instance.props.width + "px"); + ele.style.setProperty("height", e.instance.props.height + "px"); + ele.style.setProperty("max-height", e.instance.props.height + "px"); + } + for (let ele of [e.node.src && e.node, ...e.node.querySelectorAll("[src]")].filter(n => n)) ele.src = ele.src.split("?width")[0].split("?height")[0].split("?size")[0]; + if (e.instance.state.readyState != BDFDB.LibraryComponents.ImageComponents.ImageReadyStates.READY) { + e.instance.state.readyState = BDFDB.LibraryComponents.ImageComponents.ImageReadyStates.READY; BDFDB.ReactUtils.forceUpdate(e.instance); } } @@ -1305,7 +1292,7 @@ module.exports = (_ => { e.instance.props.resized = true; } } - if (this.settings.rescaleSettings.messages != "NONE" && (!e.instance.props.className || e.instance.props.className.indexOf(BDFDB.disCN.embedthumbnail) == -1) && BDFDB.ReactUtils.findOwner(reactInstance, {name: "LazyImageZoomable", up: true})) { + if (this.settings.rescaleSettings.messages != "NONE" && (!e.instance.props.className || e.instance.props.className.indexOf(BDFDB.disCN.embedthumbnail) == -1) && (!e.instance.props.containerClassName || e.instance.props.containerClassName.indexOf(BDFDB.disCN.embedthumbnail) == -1) && BDFDB.ReactUtils.findOwner(reactInstance, {name: "LazyImageZoomable", up: true})) { let aRects = BDFDB.DOMUtils.getRects(document.querySelector(BDFDB.dotCN.appmount)); let mRects = BDFDB.DOMUtils.getRects(document.querySelector(BDFDB.dotCNC.messageaccessory + BDFDB.dotCN.messagecontents)); let mwRects = BDFDB.DOMUtils.getRects(document.querySelector(BDFDB.dotCN.messagewrapper)); @@ -1334,7 +1321,8 @@ module.exports = (_ => { } processLazyImageZoomable (e) { - if (this.settings.detailsSettings.tooltip && e.instance.props.original && e.instance.props.src.indexOf("https://media.discordapp.net/attachments") == 0) { + if (!e.instance.props.original || e.instance.props.src.indexOf("https://media.discordapp.net/attachments") != 0) return; + if (this.settings.detailsSettings.tooltip) { const attachment = BDFDB.ReactUtils.findValue(e.instance, "attachment", {up: true}); if (attachment) { const onMouseEnter = e.returnvalue.props.onMouseEnter; @@ -1351,9 +1339,24 @@ module.exports = (_ => { }, "Error in onMouseEnter of LazyImageZoomable!"); } } + if (this.settings.detailsSettings.footnote && (e.instance.props.className || "").indexOf(BDFDB.disCN.embedmedia) == -1 && (e.instance.props.className || "").indexOf(BDFDB.disCN.embedthumbnail) == -1) { + e.returnvalue = BDFDB.ReactUtils.createElement("div", { + children: [ + e.returnvalue, + BDFDB.ReactUtils.createElement(ImageDetailsComponent, { + original: e.instance.props.original, + attachment: { + height: 0, + width: 0, + filename: "unknown.png" + } + }) + ] + }); + } } - processSimpleMessageAccessories (e) { + processMessageAccessories (e) { if (this.settings.general.nsfwMode && e.instance.props.channel.nsfw) { e.instance.props.message = new BDFDB.DiscordObjects.Message(e.instance.props.message); e.instance.props.message.attachments = [].concat(e.instance.props.message.attachments); @@ -1365,29 +1368,31 @@ module.exports = (_ => { processSpoiler (e) { if (!e.returnvalue) { - if (this.settings.rescaleSettings.messages != "NONE" && !e.instance.props.inline && e.instance.props.type == "attachment") delete e.instance.props.containerStyles.maxWidth; + if (this.settings.rescaleSettings.messages != "NONE" && !e.instance.props.inline && e.instance.props.type == "attachment" && e.instance.props.containerStyles) e.instance.props.containerStyles.maxWidth = "100%"; } else { - if (this.settings.general.nsfwMode) { + if (this.settings.general.nsfwMode && typeof e.returnvalue.props.children == "function") { let childrenRender = e.returnvalue.props.children; e.returnvalue.props.children = BDFDB.TimeUtils.suppress((...args) => { - let children = childrenRender(...args); - let attachment = BDFDB.ReactUtils.findValue(children, "attachment"); + let returnedChildren = childrenRender(...args); + let attachment = BDFDB.ReactUtils.findValue(returnedChildren, "attachment"); if (attachment && attachment.nsfw) { - let [children2, index] = BDFDB.ReactUtils.findParent(children, {name: "SpoilerWarning"}); - if (index > -1) children2[index] = BDFDB.ReactUtils.createElement("div", { + let [children, index] = BDFDB.ReactUtils.findParent(returnedChildren, {name: "SpoilerWarning"}); + if (index > -1) children[index] = BDFDB.ReactUtils.createElement("div", { className: BDFDB.disCN.spoilerwarning, children: "NSFW" }); } - return children; + return returnedChildren; }, "Error in Children Render of Spoiler!"); } } } - processUserBanner (e) { - if (this.settings.places.userAvatars && e.instance.props.displayProfile && e.instance.props.displayProfile.banner) e.returnvalue.props.onContextMenu = event => { + processUserThemedBanner (e) { + if (!this.settings.places.userAvatars || !e.instance.props.displayProfile || !e.instance.props.displayProfile.banner) return; + let div = BDFDB.ReactUtils.findChild(e.returnvalue, {type: "div"}); + if (div) div.props.onContextMenu = event => { let validUrls = this.filterUrls(BDFDB.UserUtils.getBanner(e.instance.props.user.id, null, false), BDFDB.LibraryModules.IconUtils.isAnimatedIconHash(e.instance.props.displayProfile._userProfile.banner) && BDFDB.UserUtils.getBanner(e.instance.props.user.id, null, true), e.instance.props.displayProfile._guildMemberProfile.banner && BDFDB.UserUtils.getBanner(e.instance.props.user.id, e.instance.props.guildId, false), e.instance.props.displayProfile._guildMemberProfile.banner && BDFDB.LibraryModules.IconUtils.isAnimatedIconHash(e.instance.props.displayProfile._guildMemberProfile.banner) && BDFDB.UserUtils.getBanner(e.instance.props.user.id, e.instance.props.guildId, true)); if (validUrls.length) BDFDB.ContextMenuUtils.open(this, event, BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuGroup, { children: validUrls.length == 1 ? this.createSubMenus({ @@ -1395,7 +1400,7 @@ module.exports = (_ => { urls: validUrls, prefix: BDFDB.LanguageUtils.LanguageStrings.USER_SETTINGS_PROFILE_BANNER }) : BDFDB.ContextMenuUtils.createItem(BDFDB.LibraryComponents.MenuItems.MenuItem, { - label: BDFDB.LanguageUtils.LanguageStrings.IMAGE + " " + BDFDB.LanguageUtils.LanguageStrings.ACTIONS, + label: this.labels.context_imageactions, id: BDFDB.ContextMenuUtils.createItemId(this.name, "main-subitem"), children: this.createSubMenus({ instance: {}, @@ -1407,6 +1412,10 @@ module.exports = (_ => { }; } + processUserBanner (e) { + this.processUserThemedBanner(e); + } + cacheClickedImage (target) { if (!target) return; const image = (BDFDB.DOMUtils.getParent(BDFDB.dotCN.imagewrapper, target) || target).querySelector("img") || target; @@ -1424,14 +1433,14 @@ module.exports = (_ => { downloadFile (url, path, fallbackUrl, alternativeName) { url = url.startsWith("/assets") ? (window.location.origin + url) : url; - BDFDB.LibraryRequires.request(url, {agentOptions: {rejectUnauthorized: false}, encoding: null}, (error, response, body) => { + BDFDB.LibraryRequires.request(url, {agentOptions: {rejectUnauthorized: false}, headers: {"Content-Type": "application/json"}}, (error, response, body) => { let type = this.isValid(url, "video") ? BDFDB.LanguageUtils.LanguageStrings.VIDEO : BDFDB.LanguageUtils.LanguageStrings.IMAGE; - if (error || response.statusCode != 200 || response.headers["content-type"] == "text/html") { + if (error || response.statusCode != 200 || response.headers["content-type"].indexOf("text/html") > -1) { if (fallbackUrl) this.downloadFile(fallbackUrl, path, null, alternativeName); else BDFDB.NotificationUtils.toast(this.labels.toast_save_failed.replace("{{var0}}", type).replace("{{var1}}", ""), {type: "danger"}); } else { - BDFDB.LibraryRequires.fs.writeFile(this.getFileName(path, (alternativeName || url.split("/").pop().split(".").slice(0, -1).join(".") || "unknown").slice(0, 35), this.getFileExtenstion(response.headers["content-type"].split("/").pop().split("+")[0]), 0), body, error => { + BDFDB.LibraryRequires.fs.writeFile(this.getFileName(path, (alternativeName || url.split("/").pop().split(".").slice(0, -1).join(".") || "unknown").slice(0, 35), this.getFileExtenstion(response.headers["content-type"].split("/").pop().split("+")[0]), 0), Buffer.from(body), error => { if (error) BDFDB.NotificationUtils.toast(this.labels.toast_save_failed.replace("{{var0}}", type).replace("{{var1}}", path), {type: "danger"}); else BDFDB.NotificationUtils.toast(this.labels.toast_save_success.replace("{{var0}}", type).replace("{{var1}}", path), {type: "success"}); }); @@ -1441,40 +1450,13 @@ module.exports = (_ => { downloadFileAs (url, fallbackUrl, alternativeName) { url = url.startsWith("/assets") ? (window.location.origin + url) : url; - BDFDB.LibraryRequires.request(url, {agentOptions: {rejectUnauthorized: false}, encoding: null}, (error, response, body) => { - let type = this.isValid(url, "video") ? BDFDB.LanguageUtils.LanguageStrings.VIDEO : BDFDB.LanguageUtils.LanguageStrings.IMAGE; - if (error || response.statusCode != 200 || response.headers["content-type"] == "text/html") { - if (fallbackUrl) this.downloadFileAs(fallbackUrl, null, alternativeName); - else BDFDB.NotificationUtils.toast(this.labels.toast_save_failed.replace("{{var0}}", type).replace("{{var1}}", ""), {type: "danger"}); - } - else { - let hrefURL = window.URL.createObjectURL(new Blob([body])); - let tempLink = document.createElement("a"); - tempLink.href = hrefURL; - tempLink.download = `${(alternativeName || url.split("/").pop().split(".").slice(0, -1).join(".") || "unknown").slice(0, 35)}.${this.getFileExtenstion(response.headers["content-type"].split("/").pop().split("+")[0])}`; - tempLink.click(); - window.URL.revokeObjectURL(hrefURL); - } - }); + BDFDB.LibraryModules.WindowUtils.saveImage(url.startsWith("/assets") ? (window.location.origin + url) : url); } copyFile (url) { - BDFDB.LibraryRequires.request(url, {agentOptions: {rejectUnauthorized: false}, encoding: null}, (error, response, body) => { - let type = this.isValid(url, "video") ? BDFDB.LanguageUtils.LanguageStrings.VIDEO : BDFDB.LanguageUtils.LanguageStrings.IMAGE; - if (error) BDFDB.NotificationUtils.toast(this.labels.toast_copy_failed.replace("{{var0}}", type), {type: "danger"}); - else if (body) { - if (BDFDB.LibraryRequires.process.platform === "win32" || BDFDB.LibraryRequires.process.platform === "darwin") { - BDFDB.LibraryRequires.electron.clipboard.write({image: BDFDB.LibraryRequires.electron.nativeImage.createFromBuffer(body)}); - } - else { - let file = BDFDB.LibraryRequires.path.join(BDFDB.LibraryRequires.process.env.USERPROFILE || BDFDB.LibraryRequires.process.env.HOMEPATH || BDFDB.LibraryRequires.process.env.HOME, "imageutilstempimg.png"); - BDFDB.LibraryRequires.fs.writeFileSync(file, body, {encoding: null}); - BDFDB.LibraryRequires.electron.clipboard.write({image: file}); - BDFDB.LibraryRequires.fs.unlinkSync(file); - } - BDFDB.NotificationUtils.toast(this.labels.toast_copy_success.replace("{{var0}}", type), {type: "success"}); - } - }); + let type = this.isValid(url, "video") ? BDFDB.LanguageUtils.LanguageStrings.VIDEO : BDFDB.LanguageUtils.LanguageStrings.IMAGE; + BDFDB.LibraryModules.WindowUtils.copyImage(url); + BDFDB.NotificationUtils.toast(this.labels.toast_copy_success.replace("{{var0}}", type), {type: "success"}); } getDownloadLocation () { @@ -1503,7 +1485,7 @@ module.exports = (_ => { getImageSrc (img) { if (!img) return null; - return (typeof img == "string" ? img : (img.proxy_url || img.src || (img.querySelector("canvas") ? img.querySelector("canvas").src : ""))).split("?width=")[0]; + return (typeof img == "string" ? img : (img.proxy_url || img.src || (typeof img.querySelector == "function" && img.querySelector("canvas") ? img.querySelector("canvas").src : ""))).split("?width=")[0]; } getImageIndex (messages, img) { @@ -1511,7 +1493,7 @@ module.exports = (_ => { } filterMessagesForImages (messages, img) { - return messages.filter(m => m && m.hit && m.channel_id == img.channelId && (m.id == firstViewedImage.messageId || m.id == img.messageId || m.embeds.length || m.attachments.filter(a => !a.filename.startsWith("SPOILER_")).length)).map(m => [m.attachments, m.embeds].flat(10).filter(n => n).map(i => Object.assign({messageId: m.id, channelId: img.channelId}, i, i.image, i.thumbnail, i.video))).flat(10); + return messages.filter(m => m && m.channel_id == img.channelId && !BDFDB.LibraryStores.RelationshipStore.isBlocked(m.author.id) && (m.id == firstViewedImage.messageId || m.id == img.messageId || m.embeds.filter(e => e.image || e.thumbnail || e.video).length || m.attachments.filter(a => !a.filename.startsWith("SPOILER_")).length)).map(m => [m.attachments, m.embeds].flat(10).filter(n => n).map(i => Object.assign({m, messageId: m.id, channelId: img.channelId}, i, i.image, i.thumbnail, i.video))).flat(10); } switchImages (modalInstance, offset) { @@ -1523,61 +1505,55 @@ module.exports = (_ => { viewedImage = cachedImages.all[cachedImages.index]; if (offset > 0 && !cachedImages.lastReached && cachedImages.index == (cachedImages.amount - 1)) { - let channel = BDFDB.LibraryModules.ChannelStore.getChannel(viewedImage.channelId); + let channel = BDFDB.LibraryStores.ChannelStore.getChannel(viewedImage.channelId); BDFDB.LibraryModules.APIUtils.get({ - url: channel && channel.guild_id ? BDFDB.DiscordConstants.Endpoints.SEARCH_GUILD(channel && channel.guild_id) : BDFDB.DiscordConstants.Endpoints.SEARCH_CHANNEL(channel.id), + url: BDFDB.DiscordConstants.Endpoints.MESSAGES(channel.id), query: BDFDB.LibraryModules.APIEncodeUtils.stringify({ channel_id: channel && channel.guild_id ? (BDFDB.ChannelUtils.isThread(channel) && channel.parent_id || channel.id) : null, has: "image", include_nsfw: true, - min_id: (BigInt(cachedImages.newestId) - BigInt(1)).toString() + limit: 100, + after: (BigInt(cachedImages.newestId) - BigInt(1)).toString() }) }).then(result => { if (result && viewedImage) { - const messages = result.body.messages.flat(10).reverse(); - const newCachedImages = this.filterMessagesForImages(messages, viewedImage); - const lastOldIndex = this.getImageIndex(newCachedImages, cachedImages.all[cachedImages.all.length-1]); - if (lastOldIndex > -1) { - cachedImages = Object.assign(cachedImages, {all: [].concat(cachedImages.all, newCachedImages.slice(lastOldIndex + 1))}); - const index = this.getImageIndex(cachedImages.all, viewedImage); - cachedImages = Object.assign(cachedImages, { - channelId: viewedImage.channelId, - index: index, - amount: cachedImages.all.length, - newestId: messages[messages.length-1] ? messages[messages.length-1].id : null, - lastReached: index == (cachedImages.all.length - 1) - }); - } + const messages = result.body.flat(10).reverse(); + Object.assign(cachedImages, {all: BDFDB.ArrayUtils.removeCopies([].concat(cachedImages.all, this.filterMessagesForImages(messages, viewedImage)))}); + const index = this.getImageIndex(cachedImages.all, viewedImage); + cachedImages = Object.assign(cachedImages, { + channelId: viewedImage.channelId, + index: index, + amount: cachedImages.all.length, + newestId: messages[messages.length-1] ? messages[messages.length-1].id : null, + lastReached: index == (cachedImages.all.length - 1) + }); BDFDB.ReactUtils.forceUpdate(modalInstance); } }); } if (offset < 0 && !cachedImages.firstReached && cachedImages.index == 0) { - let channel = BDFDB.LibraryModules.ChannelStore.getChannel(viewedImage.channelId); + let channel = BDFDB.LibraryStores.ChannelStore.getChannel(viewedImage.channelId); BDFDB.LibraryModules.APIUtils.get({ - url: channel && channel.guild_id ? BDFDB.DiscordConstants.Endpoints.SEARCH_GUILD(channel && channel.guild_id) : BDFDB.DiscordConstants.Endpoints.SEARCH_CHANNEL(channel.id), + url: BDFDB.DiscordConstants.Endpoints.MESSAGES(channel.id), query: BDFDB.LibraryModules.APIEncodeUtils.stringify({ channel_id: channel && channel.guild_id ? (BDFDB.ChannelUtils.isThread(channel) && channel.parent_id || channel.id) : null, has: "image", include_nsfw: true, - max_id: (BigInt(cachedImages.oldestId) + BigInt(1)).toString() + limit: 100, + before: (BigInt(cachedImages.oldestId) + BigInt(1)).toString() }) }).then(result => { if (result && viewedImage) { - const messages = result.body.messages.flat(10).reverse(); - const newCachedImages = this.filterMessagesForImages(messages, viewedImage); - const firstOldIndex = this.getImageIndex(newCachedImages, cachedImages.all[0]); - if (firstOldIndex > -1) { - cachedImages = Object.assign(cachedImages, {all: [].concat(newCachedImages.slice(0, firstOldIndex), cachedImages.all)}); - const index = this.getImageIndex(cachedImages.all, viewedImage); - cachedImages = Object.assign(cachedImages, { - channelId: viewedImage.channelId, - firstReached: index == 0, - oldestId: messages[0] ? messages[0].id : null, - index: index, - amount: cachedImages.all.length - }); - } + const messages = result.body.flat(10).reverse(); + Object.assign(cachedImages, {all: BDFDB.ArrayUtils.removeCopies([].concat(this.filterMessagesForImages(messages, viewedImage), cachedImages.all))}); + const index = this.getImageIndex(cachedImages.all, viewedImage); + cachedImages = Object.assign(cachedImages, { + channelId: viewedImage.channelId, + firstReached: index == 0, + oldestId: messages[0] ? messages[0].id : null, + index: index, + amount: cachedImages.all.length + }); BDFDB.ReactUtils.forceUpdate(modalInstance); } }); @@ -1596,7 +1572,7 @@ module.exports = (_ => { naturalWidth: viewedImage.width, naturalHeight: viewedImage.height, play: true, - playOnHover: !!BDFDB.LibraryModules.LocalSettingsStore.useReducedMotion + playOnHover: !!BDFDB.LibraryStores.AccessibilityStore.useReducedMotion })); BDFDB.ReactUtils.forceUpdate(modalInstance); } @@ -1624,9 +1600,11 @@ module.exports = (_ => { case "bg": // Bulgarian return { context_copy: "Копирайте {{var0}}", + context_imageactions: "Действия с изображения", context_lenssize: "Размер на обектива", context_saveas: "Запазете {{var0}} като ...", context_searchwith: "Търсете {{var0}} с ...", + context_videoactions: "Видео действия", context_view: "Преглед {{var0}}", submenu_disabled: "Всички инвалиди", toast_copy_failed: "{{var0}} не можа да бъде копиран в клипборда", @@ -1637,9 +1615,11 @@ module.exports = (_ => { case "cs": // Czech return { context_copy: "Zkopírovat {{var0}}", + context_imageactions: "Akce s obrázky", context_lenssize: "Velikost lupy", context_saveas: "Uložit {{var0}} jako...", context_searchwith: "Hledat {{var0}} pomocí...", + context_videoactions: "Video akce", context_view: "Zobrazit {{var0}}", submenu_disabled: "Vše zakázáno", toast_copy_failed: "{{var0}} nemohl být zkopírován do schránky", @@ -1650,9 +1630,11 @@ module.exports = (_ => { case "da": // Danish return { context_copy: "Kopiér {{var0}}", + context_imageactions: "Billedhandlinger", context_lenssize: "Objektivstørrelse", context_saveas: "Gem {{var0}} som ...", context_searchwith: "Søg i {{var0}} med ...", + context_videoactions: "Videohandlinger", context_view: "Se {{var0}}", submenu_disabled: "Alle handicappede", toast_copy_failed: "{{var0}} kunne ikke kopieres til udklipsholderen", @@ -1663,9 +1645,11 @@ module.exports = (_ => { case "de": // German return { context_copy: "{{var0}} kopieren", + context_imageactions: "Bildaktionen", context_lenssize: "Linsengröße", context_saveas: "{{var0}} speichern als ...", context_searchwith: "{{var0}} suchen mit ...", + context_videoactions: "Videoaktionen", context_view: "{{var0}} ansehen", submenu_disabled: "Alle deaktiviert", toast_copy_failed: "{{var0}} konnte nicht in die Zwischenablage kopiert werden", @@ -1676,9 +1660,11 @@ module.exports = (_ => { case "el": // Greek return { context_copy: "Αντιγραφή {{var0}}", + context_imageactions: "Ενέργειες εικόνας", context_lenssize: "Μέγεθος φακού", context_saveas: "Αποθήκευση {{var0}} ως ...", context_searchwith: "Αναζήτηση {{var0}} με ...", + context_videoactions: "Ενέργειες βίντεο", context_view: "Προβολή {{var0}}", submenu_disabled: "Όλα τα άτομα με ειδικές ανάγκες", toast_copy_failed: "Δεν ήταν δυνατή η αντιγραφή του {{var0}} στο πρόχειρο", @@ -1689,9 +1675,11 @@ module.exports = (_ => { case "es": // Spanish return { context_copy: "Copiar {{var0}}", + context_imageactions: "Acciones de imagen", context_lenssize: "Tamaño de la lente", context_saveas: "Guardar {{var0}} como ...", context_searchwith: "Buscar {{var0}} con ...", + context_videoactions: "Acciones de vídeo", context_view: "Ver {{var0}}", submenu_disabled: "Todos discapacitados", toast_copy_failed: "{{var0}} no se pudo copiar al portapapeles", @@ -1702,9 +1690,11 @@ module.exports = (_ => { case "fi": // Finnish return { context_copy: "Kopioi {{var0}}", + context_imageactions: "Kuvatoiminnot", context_lenssize: "Linssin koko", context_saveas: "Tallenna {{var0}} nimellä ...", context_searchwith: "Tee haku {{var0}} ...", + context_videoactions: "Videotoiminnot", context_view: "Näytä {{var0}}", submenu_disabled: "Kaikki vammaiset", toast_copy_failed: "Kohdetta {{var0}} ei voitu kopioida leikepöydälle", @@ -1715,9 +1705,11 @@ module.exports = (_ => { case "fr": // French return { context_copy: "Copier {{var0}}", + context_imageactions: "Actions sur les images", context_lenssize: "Taille de l'objectif", context_saveas: "Enregistrer {{var0}} sous ...", context_searchwith: "Rechercher {{var0}} avec ...", + context_videoactions: "Actions vidéo", context_view: "Afficher {{var0}}", submenu_disabled: "Tout désactivé", toast_copy_failed: "{{var0}} n'a pas pu être copié dans le presse-papiers", @@ -1728,9 +1720,11 @@ module.exports = (_ => { case "hi": // Hindi return { context_copy: "कॉपी {{var0}}", + context_imageactions: "छवि क्रियाएँ", context_lenssize: "लेंस का आकार", context_saveas: "{{var0}} को इस रूप में सेव करें...", context_searchwith: "इसके साथ {{var0}} खोजें ...", + context_videoactions: "वीडियो क्रिया", context_view: "देखें {{var0}}", submenu_disabled: "सभी अक्षम", toast_copy_failed: "{{var0}} को क्लिपबोर्ड पर कॉपी नहीं किया जा सका", @@ -1741,9 +1735,11 @@ module.exports = (_ => { case "hr": // Croatian return { context_copy: "Kopiraj {{var0}}", + context_imageactions: "Radnje slike", context_lenssize: "Veličina leće", context_saveas: "Spremi {{var0}} kao ...", context_searchwith: "Traži {{var0}} sa ...", + context_videoactions: "Video radnje", context_view: "Pogledajte {{var0}}", submenu_disabled: "Svi invalidi", toast_copy_failed: "{{var0}} nije moguće kopirati u međuspremnik", @@ -1754,9 +1750,11 @@ module.exports = (_ => { case "hu": // Hungarian return { context_copy: "{{var0}} másolása", + context_imageactions: "Képműveletek", context_lenssize: "Lencse mérete", context_saveas: "{{var0}} mentése másként ...", context_searchwith: "Keresés a következőben: {{var0}} a következővel:", + context_videoactions: "Videóműveletek", context_view: "Megtekintés: {{var0}}", submenu_disabled: "Minden fogyatékkal él", toast_copy_failed: "A {{var0}} fájl nem másolható a vágólapra", @@ -1767,9 +1765,11 @@ module.exports = (_ => { case "it": // Italian return { context_copy: "Copia {{var0}}", + context_imageactions: "Azioni immagine", context_lenssize: "Dimensione della lente", context_saveas: "Salva {{var0}} come ...", context_searchwith: "Cerca {{var0}} con ...", + context_videoactions: "Azioni video", context_view: "Visualizza {{var0}}", submenu_disabled: "Tutti disabilitati", toast_copy_failed: "{{var0}} non può essere copiato negli appunti", @@ -1780,9 +1780,11 @@ module.exports = (_ => { case "ja": // Japanese return { context_copy: "{{var0}} をコピーします", + context_imageactions: "画像アクション", context_lenssize: "レンズサイズ", context_saveas: "{{var0}} を...として保存します", context_searchwith: "{{var0}} を...で検索", + context_videoactions: "ビデオ アクション", context_view: "{{var0}} を表示", submenu_disabled: "すべて無効", toast_copy_failed: "{{var0}} をクリップボードにコピーできませんでした", @@ -1793,9 +1795,11 @@ module.exports = (_ => { case "ko": // Korean return { context_copy: "{{var0}} 복사", + context_imageactions: "이미지 작업", context_lenssize: "렌즈 크기", context_saveas: "{{var0}} 을 다른 이름으로 저장 ...", context_searchwith: "{{var0}} 검색 ...", + context_videoactions: "비디오 작업", context_view: "{{var0}} 보기", submenu_disabled: "모두 비활성화 됨", toast_copy_failed: "{{var0}} 을 클립 보드에 복사 할 수 없습니다.", @@ -1806,9 +1810,11 @@ module.exports = (_ => { case "lt": // Lithuanian return { context_copy: "Kopijuoti {{var0}}", + context_imageactions: "Vaizdo veiksmai", context_lenssize: "Objektyvo dydis", context_saveas: "Išsaugoti '{{var0}}' kaip ...", context_searchwith: "Ieškoti {{var0}} naudojant ...", + context_videoactions: "Vaizdo įrašų veiksmai", context_view: "Žiūrėti {{var0}}", submenu_disabled: "Visi neįgalūs", toast_copy_failed: "{{var0}} nepavyko nukopijuoti į mainų sritį", @@ -1819,9 +1825,11 @@ module.exports = (_ => { case "nl": // Dutch return { context_copy: "Kopieer {{var0}}", + context_imageactions: "Afbeeldingsacties", context_lenssize: "Lens Maat", context_saveas: "Bewaar {{var0}} als ...", context_searchwith: "Zoek {{var0}} met ...", + context_videoactions: "Video-acties", context_view: "Bekijk {{var0}}", submenu_disabled: "Allemaal uitgeschakeld", toast_copy_failed: "{{var0}} kan niet naar het klembord worden gekopieerd", @@ -1832,9 +1840,11 @@ module.exports = (_ => { case "no": // Norwegian return { context_copy: "Kopier {{var0}}", + context_imageactions: "Bildehandlinger", context_lenssize: "Linsestørrelse", context_saveas: "Lagre {{var0}} som ...", context_searchwith: "Søk på {{var0}} med ...", + context_videoactions: "Videohandlinger", context_view: "Vis {{var0}}", submenu_disabled: "Alle funksjonshemmede", toast_copy_failed: "{{var0}} kunne ikke kopieres til utklippstavlen", @@ -1845,9 +1855,11 @@ module.exports = (_ => { case "pl": // Polish return { context_copy: "Kopiuj {{var0}}", + context_imageactions: "Działania związane z obrazem", context_lenssize: "Rozmiar soczewki", context_saveas: "Zapisz {{var0}} jako ...", context_searchwith: "Wyszukaj {{var0}} za pomocą ...", + context_videoactions: "Akcje wideo", context_view: "Wyświetl {{var0}}", submenu_disabled: "Wszystkie wyłączone", toast_copy_failed: "Nie można skopiować {{var0}} do schowka", @@ -1858,9 +1870,11 @@ module.exports = (_ => { case "pt-BR": // Portuguese (Brazil) return { context_copy: "Copiar {{var0}}", + context_imageactions: "Ações de imagem", context_lenssize: "Tamanho da lente", context_saveas: "Salvar {{var0}} como ...", context_searchwith: "Pesquisar {{var0}} com ...", + context_videoactions: "Ações de vídeo", context_view: "Visualizar {{var0}}", submenu_disabled: "Todos desativados", toast_copy_failed: "{{var0}} não pôde ser copiado para a área de transferência", @@ -1871,9 +1885,11 @@ module.exports = (_ => { case "ro": // Romanian return { context_copy: "Copiați {{var0}}", + context_imageactions: "Acțiuni de imagine", context_lenssize: "Dimensiunea obiectivului", context_saveas: "Salvați {{var0}} ca ...", context_searchwith: "Căutați {{var0}} cu ...", + context_videoactions: "Acțiuni video", context_view: "Vizualizați {{var0}}", submenu_disabled: "Toate sunt dezactivate", toast_copy_failed: "{{var0}} nu a putut fi copiat în clipboard", @@ -1884,9 +1900,11 @@ module.exports = (_ => { case "ru": // Russian return { context_copy: "Скопируйте {{var0}}", + context_imageactions: "Действия с изображением", context_lenssize: "Размер линзы", context_saveas: "Сохранить {{var0}} как ...", context_searchwith: "Искать {{var0}} с помощью ...", + context_videoactions: "Действия с видео", context_view: "Посмотреть {{var0}}", submenu_disabled: "Все отключены", toast_copy_failed: "{{var0}} не удалось скопировать в буфер обмена", @@ -1897,9 +1915,11 @@ module.exports = (_ => { case "sv": // Swedish return { context_copy: "Kopiera {{var0}}", + context_imageactions: "Bildåtgärder", context_lenssize: "Linsstorlek", context_saveas: "Spara {{var0}} som ...", context_searchwith: "Sök {{var0}} med ...", + context_videoactions: "Videoåtgärder", context_view: "Visa {{var0}}", submenu_disabled: "Alla funktionshindrade", toast_copy_failed: "{{var0}} kunde inte kopieras till Urklipp", @@ -1910,9 +1930,11 @@ module.exports = (_ => { case "th": // Thai return { context_copy: "คัดลอก{{var0}}", + context_imageactions: "การทำงานของรูปภาพ", context_lenssize: "ขนาดเลนส์", context_saveas: "บันทึก{{var0}}เป็น ...", context_searchwith: "ค้นหา{{var0}} ้วย ...", + context_videoactions: "การกระทำของวิดีโอ", context_view: "ดู{{var0}}", submenu_disabled: "ปิดใช้งานทั้งหมด", toast_copy_failed: "ไม่สามารถคัดลอก{{var0}}ไปยังคลิปบอร์ดได้", @@ -1923,9 +1945,11 @@ module.exports = (_ => { case "tr": // Turkish return { context_copy: "{{var0}} kopyala", + context_imageactions: "Görüntü Eylemleri", context_lenssize: "Lens Boyutu", context_saveas: "{{var0}} farklı kaydet ...", context_searchwith: "{{var0}} şununla ara ...", + context_videoactions: "Video Eylemleri", context_view: "{{var0}} görüntüle", submenu_disabled: "Hepsi devre dışı", toast_copy_failed: "{{var0}} panoya kopyalanamadı", @@ -1936,9 +1960,11 @@ module.exports = (_ => { case "uk": // Ukrainian return { context_copy: "Копіювати {{var0}}", + context_imageactions: "Дії із зображеннями", context_lenssize: "Розмір лінзи", context_saveas: "Збережіть {{var0}} як ...", context_searchwith: "Шукати {{var0}} за допомогою ...", + context_videoactions: "Відео дії", context_view: "Переглянути {{var0}}", submenu_disabled: "Всі інваліди", toast_copy_failed: "Не вдалося скопіювати {{var0}} у буфер обміну", @@ -1949,9 +1975,11 @@ module.exports = (_ => { case "vi": // Vietnamese return { context_copy: "Sao chép {{var0}}", + context_imageactions: "Hành động hình ảnh", context_lenssize: "Kích thước ống kính", context_saveas: "Lưu {{var0}} dưới dạng ...", context_searchwith: "Tìm kiếm {{var0}} bằng ...", + context_videoactions: "Hành động video", context_view: "Xem {{var0}}", submenu_disabled: "Tất cả đã bị vô hiệu hóa", toast_copy_failed: "Không thể sao chép {{var0}} vào khay nhớ tạm", @@ -1962,9 +1990,11 @@ module.exports = (_ => { case "zh-CN": // Chinese (China) return { context_copy: "复制 {{var0}}", + context_imageactions: "图像动作", context_lenssize: "缩放尺寸", context_saveas: "将 {{var0}} 另存到...", context_searchwith: "搜索 {{var0}} 使用...", + context_videoactions: "视频动作", context_view: "查看 {{var0}}", submenu_disabled: "全部禁用", toast_copy_failed: "{{var0}} 无法复制到剪贴板", @@ -1975,9 +2005,11 @@ module.exports = (_ => { case "zh-TW": // Chinese (Taiwan) return { context_copy: "複製 {{var0}}", + context_imageactions: "圖像動作", context_lenssize: "縮放尺寸", context_saveas: "將 {{var0}} 另存到...", context_searchwith: "搜尋 {{var0}} 使用...", + context_videoactions: "視頻動作", context_view: "預覽 {{var0}}", submenu_disabled: "全部關閉", toast_copy_failed: "{{var0}} 無法複製到剪貼簿", @@ -1988,9 +2020,11 @@ module.exports = (_ => { default: // English return { context_copy: "Copy {{var0}}", + context_imageactions: "Image Actions", context_lenssize: "Lens Size", context_saveas: "Save {{var0}} as ...", context_searchwith: "Search {{var0}} with ...", + context_videoactions: "Video Actions", context_view: "View {{var0}}", submenu_disabled: "All disabled", toast_copy_failed: "{{var0}} could not be copied to the Clipboard", @@ -2001,5 +2035,5 @@ module.exports = (_ => { } } }; - })(window.BDFDB_Global.PluginUtils.buildPlugin(config)); + })(window.BDFDB_Global.PluginUtils.buildPlugin(changeLog)); })(); diff --git a/.config/BetterDiscord/plugins/InvisibleTyping.config.json b/.config/BetterDiscord/plugins/InvisibleTyping.config.json index 700600f..866c9f2 100755 --- a/.config/BetterDiscord/plugins/InvisibleTyping.config.json +++ b/.config/BetterDiscord/plugins/InvisibleTyping.config.json @@ -4,7 +4,10 @@ "hasShownChangelog": true }, "settings": { - "exclude": [], - "autoEnable": false + "exclude": [ + "709081938622939166" + ], + "autoEnable": false, + "latestUsedVersion": "1.3.3" } } \ No newline at end of file diff --git a/.config/BetterDiscord/plugins/InvisibleTyping.plugin.js b/.config/BetterDiscord/plugins/InvisibleTyping.plugin.js index 591592b..c10c2fc 100755 --- a/.config/BetterDiscord/plugins/InvisibleTyping.plugin.js +++ b/.config/BetterDiscord/plugins/InvisibleTyping.plugin.js @@ -1,690 +1,534 @@ /** * @name InvisibleTyping + * @version 1.3.3 + * @description Makes your typing invisible to other people. * @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 + * @invite gvA2ree + * @changelog [fixed] Fixed cleanup of observer. + * @changelogDate 2022-10-22T22:00:00.000Z + * @changelogImage https://cdn.discordapp.com/attachments/939319506428391495/1032360180303790163/Untitled-1.jpg */ -/*@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." - ] - }] + +var meta; + +const {React, DOM, Patcher, UI, Data, Utils, ReactUtils, ContextMenu, Webpack: _Webpack} = new BdApi("InvisibleTyping"); + +const Webpack = { + ..._Webpack, + getByProps(...props) {return this.getModule(this.Filters.byProps(...props));}, + getStore(name) {return this.getModule(m => m?._dispatchToken && m?.getName() === name);}, + getBulk(...queries) {return _Webpack.getBulk(...queries.map(q => typeof q === "function" ? {filter: q} : q));} }; -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; + +Utilities: { + var removeItem = function (array, item) { + while (array.includes(item)) { + array.splice(array.indexOf(item), 1); + } + + return array; + }; + + var onceAdded = (selector, callback, signal) => { + let directMatch; + if (directMatch = document.querySelector(selector)) { + callback(directMatch); + return () => null; + } + + const cancel = () => observer.disconnect(); + + const observer = new MutationObserver(changes => { + for (const change of changes) { + if (!change.addedNodes.length) continue; + + for (const node of change.addedNodes) { + const match = (node.matches(selector) && node) || node.querySelector(selector); + + if (!match) continue; + + cancel(); + signal.removeEventListener("abort", cancel); + + callback(match); + } + } + }); + + observer.observe(document.body, {childList: true, subtree: true}); + + signal.addEventListener("abort", cancel); + }; + + var Fluxify = (component, stores, getter) => { + Object.assign(component.prototype, { + componentDidMount() { + this._handleStoreChange = this._handleStoreChange.bind(this); + this._handleStoreChange(); + + for (const store of stores) store.addChangeListener(this._handleStoreChange); + }, + _handleStoreChange() { + if (this._gone) return; + this.setState(getter(this.props)); + }, + componentWillUnmount() { + this._gone = true; + for (const store of stores) store.removeChangeListener(this._handleStoreChange); + } + }); + }; + + var Settings = { + _listeners: new Set, + settings: Data.load("settings") ?? {}, + getSetting(id, defValue) {return this.settings[id] ?? defValue;}, + updateSetting(id, value) {return this.settings[id] = value, this.saveSettings();}, + saveSettings() {Data.save("settings", this.settings), this.emitChange();}, + + emitChange() {this._listeners.forEach(callback => callback());}, + addChangeListener(listener) {this._listeners.add(listener);}, + removeChangeListener(listener) {this._listeners.delete(listener);} + }; +}; + +Components: { + var InvisibleTypingButton = class InvisibleTypingButton extends React.Component { + state = {enabled: false}; + static DMChannels = new Set([1, 3]); + static canViewChannel(channel) { + if (!channel) return false; + if (this.DMChannels.has(channel.type)) return true; + + try { + return this.defaultProps.PermissionUtils.can({ + context: channel, + user: this.defaultProps.UserStore.getCurrentUser(), + permission: /*SEND_MESSAGES*/ 2048n + }); + } catch (error) { + console.error("Failed to request permissions:", error); + return true; + } + } + + static shouldShow(children, props) { + if (!Array.isArray(children)) return false; + if (props.type?.analyticsName === "profile_bio_input") return false; + if (children.some(child => child && child.type === InvisibleTypingButton)) return false; + if (!this.canViewChannel(props.channel)) return false; + + return true; + } + + static getState(channelId) { + const isGlobal = Settings.getSetting("autoEnable", true); + const isExcluded = Settings.getSetting("exclude", []).includes(channelId); + + if (isExcluded) return isGlobal; + return !isGlobal; + } + + handleClick = () => { + const {channel, isEmpty, TypingModule} = this.props; + const excludeList = Settings.getSetting("exclude", []).concat(); + + 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.updateSetting("exclude", excludeList); + } + + renderContextMenu() { + const globalState = Settings.getSetting("autoEnable", false); + + return ContextMenu.buildMenu([ + { + id: "globally-disable-or-enable-typing", + label: !globalState ? "Disable Globally" : "Enable Globally", + onClick: () => {Settings.updateSetting("autoEnable", !globalState);} + }, + { + id: "reset-config", + color: "colorDanger", + disabled: !Settings.getSetting("exclude", []).length, + label: "Reset Config", + onClick() { + Settings.updateSetting("exclude", []); + UI.showToast("Successfully reset config for all channels.", {type: "success"}); + } + } + ]); + } + + renderButton = props => { + return React.createElement("button", { + ...props, + ref: e => e && (e.unmount = () => { + this.render = () => null; + this.forceUpdate(); + }), + onClick: this.handleClick, + onContextMenu: e => ContextMenu.open(e, this.renderContextMenu()), + className: Utils.className("invisible-typing-button", {enabled: this.state.enabled, disabled: !this.state.disabled}), + children: React.createElement("svg", { + width: "25", + height: "25", + viewBox: "0 0 576 512" + }, React.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" + }), !this.state.enabled ? React.createElement("rect", { + className: "disabled-stroke-through", + x: "10", + y: "10", + width: "600pt", + height: "70px", + fill: "#f04747" + }) : null) + }); + } + + render() { + const {Tooltip} = this.props; + + return React.createElement(Tooltip, { + text: this.state.enabled ? "Disable Typing" : "Enable Typing", + children: this.renderButton + }); + } + } + + Fluxify(InvisibleTypingButton, [Settings], (props) => ({enabled: InvisibleTypingButton.getState(props.channel.id)})); + + Settings: { + var SimpleSwitch = ({state = false, name = "", note = "", onChange}) => { + const [currState, toggle] = React.useReducer(n => !n, state); + + const handleChange = () => (onChange(!currState), toggle()); + + return React.createElement("div", {className: "it-switch-wrapper"}, + React.createElement("div", {className: "it-switch-header"}, + React.createElement("h5", {className: "it-switch-name"}, name), + React.createElement("div", { + className: Utils.className("it-switch-item", currState && "it-switch-checked"), + onClick: handleChange, + }, React.createElement("div", {className: "it-switch-dot"})) + ), + React.createElement("span", {className: "it-switch-note"}, note) + ); + } + } } -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@*/ \ No newline at end of file + +module.exports = class InvisibleTyping { + constructor(metaObject) {meta = this.meta = metaObject;} + + cleanup = new Set([ + () => Patcher.unpatchAll(), + () => DOM.removeStyle(), + () => new Set(document.getElementsByClassName("invisible-typing-button")).forEach(el => el.unmount?.()) + ]); + + start() { + DOM.addStyle(` + .it-title-wrap { + font-size: 18px; + } + + .it-title-wrap span { + font-size: 12px; + color: var(--text-muted); + font-family: var(--font-primary); + } + + .invisible-typing-button svg { + color: var(--interactive-normal); + overflow: visible; + } + + .invisible-typing-button .disabled-stroke-through { + position: absolute; + transform: translateX(-15px) translateY(530px) rotate(-45deg); + } + + .invisible-typing-button { + margin-top: 3px; + background: transparent; + } + + .invisible-typing-button:hover:not(.disabled) svg { + color: var(--interactive-hover); + } + + .it-switch-wrapper { + color: #fff; + margin-bottom: 10px; + } + + .it-switch-header { + margin-bottom: 15px; + display: flex; + justify-content: space-between; + align-items: center; + } + + .it-switch-name { + font-size: 18px; + font-weight: 500; + } + + .it-switch-note { + font-size: 14px; + color: var(--text-muted); + } + + .it-switch-item.it-switch-checked { + background: var(--brand-experiment); + } + + .it-switch-item { + width: 40px; + height: 24px; + background: rgb(114, 118, 125); + border-radius: 100px; + cursor: pointer; + } + + .it-switch-dot { + width: 18px; + height: 18px; + background: #fff; + border-radius: 100px; + top: 3px; + left: 3px; + position: relative; + transition: transform .3s ease-in-out; + } + + .it-switch-checked .it-switch-dot { + transform: translateX(16px); + } + + .it-switch-wrapper { + color: #fff; + margin-bottom: 10px; + } + + .it-switch-header { + margin-bottom: 15px; + display: flex; + justify-content: space-between; + align-items: center; + } + + .it-switch-name { + font-size: 18px; + font-weight: 500; + } + + .it-switch-note { + font-size: 14px; + color: var(--text-muted); + } + + .it-switch-item.it-switch-checked { + background: var(--brand-experiment); + } + + .it-switch-item { + width: 40px; + height: 24px; + background: rgb(114, 118, 125); + border-radius: 100px; + cursor: pointer; + } + + .it-switch-dot { + width: 18px; + height: 18px; + background: #fff; + border-radius: 100px; + top: 3px; + left: 3px; + position: relative; + transition: transform .3s ease-in-out; + } + + .it-switch-checked .it-switch-dot { + transform: translateX(16px); + } + + .it-changelog-item { + color: #fff; + } + + .it-changelog-header { + text-transform: uppercase; + font-weight: 700; + display: flex; + align-items: center; + margin-bottom: 10px; + } + + .item-changelog-added .it-changelog-header { + color: #45BA6A; + } + + .item-changelog-fixed .it-changelog-header { + color: #EC4245; + } + + .item-changelog-improved .it-changelog-header { + color: #5865F2; + } + + .it-changelog-header::after { + content: ""; + flex-grow: 1; + height: 1px; + background: currentColor; + margin-left: 7px; + } + + .it-changelog-item span { + display: list-item; + margin-left: 5px; + list-style: inside; + } + + .it-changelog-item span::marker { + color: var(--background-accent); + } + + .it-changelog-banner { + width: 405px; + border-radius: 8px; + margin-bottom: 20px; + } + `); + + InvisibleTypingButton.defaultProps ??= {}; + + [ + InvisibleTypingButton.defaultProps.PermissionUtils, + InvisibleTypingButton.defaultProps.UserStore, + InvisibleTypingButton.defaultProps.Tooltip + ] = Webpack.getBulk( + {searchExports: true, filter: Webpack.Filters.byProps("can", "areChannelsLocked")}, + m => m?._dispatchToken && m.getName() === "UserStore", + {searchExports: true, filter: Webpack.Filters.byPrototypeFields("renderTooltip")} + ); + + this.patchTextAreaButtons().catch(() => {}); + this.patchStartTyping(); + this.maybeShowChangelog(); + } + + maybeShowChangelog() { + if (this.meta.version === Settings.getSetting("latestUsedVersion")) return; + + const items = Array.from(meta.changelog.matchAll(/\[(\w+)\]\s?([^\n]+)/g), ([, type, content]) => { + let className = "it-changelog-item"; + switch (type) { + case "fixed": + case "improved": + case "added": { + className += " item-changelog-" + type; + + break; + }; + } + + return React.createElement("div", { + className, + children: [ + React.createElement("h4", {className: "it-changelog-header"}, type), + React.createElement("span", null, content) + ] + }); + }); + + "changelogImage" in meta && items.unshift( + React.createElement("img", { + className: "it-changelog-banner", + src: meta.changelogImage + }) + ); + + Settings.updateSetting("latestUsedVersion", meta.version); + const formatter = new Intl.DateTimeFormat(document.documentElement.lang, {month: "long", day: "numeric", year: "numeric"}); + UI.alert(React.createElement("div", { + className: "it-title-wrap", + children: [ + React.createElement("h1", null, "What's New - InvisibleTyping"), + React.createElement("span", null, formatter.format(new Date(meta.changelogDate))) + ] + }), items); + } + + async patchTextAreaButtons() { + const buttonsClassName = Webpack.getByProps("profileBioInput", "buttons")?.buttons + + if (!buttonsClassName) return UI.showToast(`[${this.meta.name}] Could not add button to textarea.`, {type: "error"}); + + const controller = new AbortController(); + const instance = await new Promise((resolve, reject) => { + onceAdded("." + buttonsClassName, e => { + const vnode = ReactUtils.getInternalInstance(e); + + if (!vnode) return; + + for (let curr = vnode, max = 100; curr !== null && max--; curr = curr.return) { + const tree = curr?.pendingProps?.children; + let buttons; + if (Array.isArray(tree) && (buttons = tree.find(s => s?.props?.type && s.props.channel && s.type?.$$typeof))) { + resolve(buttons.type); + break; + } + } + }, controller.signal); + + const abort = controller.abort.bind(controller); + + controller.signal.addEventListener("abort", () => { + this.cleanup.delete(abort); + reject(); + }); + + this.cleanup.add(abort); + }); + + Patcher.after(instance, "type", (_, [props], res) => { + if (!InvisibleTypingButton.shouldShow(res?.props?.children, props)) return; + + res.props.children.unshift(React.createElement(InvisibleTypingButton, props)); + }); + } + + patchStartTyping() { + const TypingModule = InvisibleTypingButton.defaultProps.TypingModule = Webpack.getByProps("startTyping"); + + Patcher.instead(TypingModule, "startTyping", (_, [channelId], originalMethod) => { + if (InvisibleTypingButton.getState(channelId)) originalMethod(channelId); + }); + } + + stop() { + this.cleanup.forEach(clean => clean()); + } + + getSettingsPanel() { + return React.createElement(SimpleSwitch, { + get state() {return Settings.getSetting("autoEnable", false);}, + name: "Globally Toggle", + note: "Enable/Disable your typing information globally and use excluded channels as white-/blacklist.", + onChange: value => Settings.updateSetting("autoEnable", value) + }); + } +}; diff --git a/.config/BetterDiscord/plugins/NotificationSounds.config.json b/.config/BetterDiscord/plugins/NotificationSounds.config.json index 4a6bb3a..f641392 100755 --- a/.config/BetterDiscord/plugins/NotificationSounds.config.json +++ b/.config/BetterDiscord/plugins/NotificationSounds.config.json @@ -243,6 +243,13 @@ "mute": false, "sound": "---", "volume": 100 + }, + "call_ringing_halloween": { + "category": "---", + "focus": false, + "mute": null, + "sound": "---", + "volume": 100 } }, "volumes": { diff --git a/.config/BetterDiscord/plugins/NotificationSounds.plugin.js b/.config/BetterDiscord/plugins/NotificationSounds.plugin.js index 93ade71..9997935 100644 --- a/.config/BetterDiscord/plugins/NotificationSounds.plugin.js +++ b/.config/BetterDiscord/plugins/NotificationSounds.plugin.js @@ -2,7 +2,7 @@ * @name NotificationSounds * @author DevilBro * @authorId 278543574059057154 - * @version 3.7.2 + * @version 3.7.5 * @description Allows you to replace the native Sounds with custom Sounds * @invite Jx3TjNS * @donate https://www.paypal.me/MircoWittrien @@ -13,20 +13,16 @@ */ module.exports = (_ => { - const config = { - "info": { - "name": "NotificationSounds", - "author": "DevilBro", - "version": "3.7.2", - "description": "Allows you to replace the native Sounds with custom Sounds" - } + const changeLog = { + }; 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}`;} + constructor (meta) {for (let key in meta) this[key] = meta[key];} + getName () {return this.name;} + getAuthor () {return this.author;} + getVersion () {return this.version;} + getDescription () {return `The Library Plugin needed for ${this.name} is missing. Open the Plugin Settings to download it. \n\n${this.description}`;} downloadLibrary () { require("request").get("https://mwittrien.github.io/BetterDiscordAddons/Library/0BDFDB.plugin.js", (e, r, b) => { @@ -39,7 +35,7 @@ module.exports = (_ => { 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.`, { + BdApi.showConfirmationModal("Library Missing", `The Library Plugin needed for ${this.name} is missing. Please click "Download Now" to install it.`, { confirmText: "Download Now", cancelText: "Cancel", onCancel: _ => {delete window.BDFDB_Global.downloadModal;}, @@ -49,13 +45,13 @@ module.exports = (_ => { } }); } - if (!window.BDFDB_Global.pluginQueue.includes(config.info.name)) window.BDFDB_Global.pluginQueue.push(config.info.name); + if (!window.BDFDB_Global.pluginQueue.includes(this.name)) window.BDFDB_Global.pluginQueue.push(this.name); } start () {this.load();} stop () {} getSettingsPanel () { let template = document.createElement("template"); - template.innerHTML = `
The Library Plugin needed for ${config.info.name} is missing.\nPlease click Download Now to install it.
`; + template.innerHTML = `
The Library Plugin needed for ${this.name} is missing.\nPlease click Download Now to install it.
`; template.content.firstElementChild.querySelector("a").addEventListener("click", this.downloadLibrary); return template.content.firstElementChild; } @@ -66,7 +62,7 @@ module.exports = (_ => { const removeAllKey = "REMOVE_ALL_BDFDB_DEVILBRO_DO_NOT_COPY"; const defaultDevice = "default"; - var currentDevice = defaultDevice, createdAudios = {}, repatchIncoming; + var currentDevice = defaultDevice, createdAudios = {}; let types = {}; @@ -137,8 +133,8 @@ module.exports = (_ => { 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); + audio.volume = Math.min((BDFDB.LibraryStores.MediaEngineStore.getOutputVolume() / 100) * (this._volume / 100) * (volumes.globalVolume / 100), 1); + BDFDB.DiscordUtils.isPlaformEmbedded() && audio.setSinkId(currentDevice || defaultDevice); callback(audio); }; audio.onerror = _ => errorCallback(new Error("could not play audio")); @@ -165,12 +161,12 @@ module.exports = (_ => { 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 name = id == "reconnect" ? "Invited To Speak" : id.replace("ddr-", "HotKeys_").replace("ptt_", "Push2Talk_").split("_").map(BDFDB.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); + soundPackName = BDFDB.StringUtils.upperCaseFirstChar(soundPackName); if (!defaultAudios[soundPackName]) defaultAudios[soundPackName] = {}; defaultAudios[soundPackName][name.replace(new RegExp(`${soundPackName} `, "i"), "").replace(/bootup/i, "Discodo")] = src; } @@ -200,12 +196,12 @@ module.exports = (_ => { } onStart () { - if (BDFDB.LibraryModules.PlatformUtils.embedded) { + if (BDFDB.DiscordUtils.isPlaformEmbedded()) { 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 id = BDFDB.LibraryStores.MediaEngineStore.getOutputDeviceId(); + let allDevices = BDFDB.LibraryStores.MediaEngineStore.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]; @@ -217,7 +213,7 @@ module.exports = (_ => { }); } }; - BDFDB.StoreChangeUtils.add(this, BDFDB.LibraryModules.MediaDeviceUtils, change); + BDFDB.StoreChangeUtils.add(this, BDFDB.LibraryStores.MediaEngineStore, change); change(); } @@ -225,11 +221,11 @@ module.exports = (_ => { 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); + if (message.author.id != BDFDB.UserUtils.me.id && !BDFDB.LibraryStores.RelationshipStore.isBlocked(message.author.id)) { + const channel = BDFDB.LibraryStores.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; + const muted = BDFDB.ChannelUtils.isThread(channel) ? BDFDB.LibraryStores.JoinedThreadsStore.isMuted(channel.id) : BDFDB.LibraryStores.UserGuildSettingsStore.isGuildOrCategoryOrChannelMuted(guildId, channel.id); + const focused = document.hasFocus() && BDFDB.LibraryStores.SelectedChannelStore.getChannelId() == channel.id; if (!guildId && !muted && !(choices[isGroupDM ? "groupdm" : "dm"].focus && focused)) { this.fireEvent(isGroupDM ? "groupdm" : "dm"); this.playAudio(isGroupDM ? "groupdm" : "dm"); @@ -249,15 +245,15 @@ module.exports = (_ => { 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 (message.mention_roles.length && !BDFDB.LibraryStores.UserGuildSettingsStore.isSuppressRolesEnabled(guildId, channel.id) && (!muted || choices.role.force) && !(choices.role.focus && focused)) { + const member = BDFDB.LibraryStores.GuildMemberStore.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.mention_everyone && !BDFDB.LibraryStores.UserGuildSettingsStore.isSuppressEveryoneEnabled(guildId, channel.id)) { if (message.content.indexOf("@everyone") > -1 && (!muted || choices.everyone.force) && !(choices.everyone.focus && focused)) { this.fireEvent("everyone"); this.playAudio("everyone"); @@ -270,7 +266,7 @@ module.exports = (_ => { } } } - if (BDFDB.LibraryModules.MutedUtils.allowAllMessages(channel) && (!muted || choices.message1.force) && !(choices.message1.focus && focused)) { + if (BDFDB.LibraryStores.UserGuildSettingsStore.allowAllMessages(channel) && (!muted || choices.message1.force) && !(choices.message1.focus && focused)) { this.fireEvent("message1"); this.playAudio("message1"); return; @@ -303,7 +299,7 @@ module.exports = (_ => { } else e.callOriginalMethodAfterwards(); }}); - BDFDB.PatchUtils.patch(this, BDFDB.LibraryModules.SoundUtils, "createSound", {after: e => { + BDFDB.PatchUtils.patch(this, BDFDB.LibraryModules.SoundUtils, ["createSound", "createSoundpackSound"], {after: e => { let type = e.methodArguments[0]; if (type && choices[type]) { let audio = new WebAudioSound(type); @@ -316,18 +312,6 @@ module.exports = (_ => { 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(); } @@ -424,9 +408,9 @@ module.exports = (_ => { } 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) => { + else BDFDB.LibraryRequires.fs.readFile(source, "", (error, buffer) => { 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")}`}); + else return successSavedAudio({category, sound, source: `data:audio/mpeg;base64,${Buffer.from(buffer).toString("base64")}`}); }); }, children: BDFDB.LanguageUtils.LanguageStrings.SAVE @@ -493,10 +477,10 @@ module.exports = (_ => { mini: true, grow: 0, label: "Mute in", - labelChildren: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.Status, { + labelChildren: BDFDB.ReactUtils.createElement(BDFDB.LibraryComponents.StatusComponents.Status, { style: {marginLeft: 6}, size: 12, - status: BDFDB.DiscordConstants.StatusTypes.DND + status: BDFDB.LibraryComponents.StatusComponents.Types.DND }), value: choices[type].mute, onChange: value => { @@ -676,9 +660,8 @@ module.exports = (_ => { } forceUpdateAll () { - repatchIncoming = true; - createdAudios["call_calling"] = BDFDB.LibraryModules.SoundUtils.createSound("call_calling"); volumes = BDFDB.DataUtils.get(this, "volumes"); + if (BDFDB.LibraryStores.SoundpackStore) BDFDB.LibraryStores.SoundpackStore.emitChange(); BDFDB.PatchUtils.forceAllUpdates(this); BDFDB.DiscordUtils.rerenderAll(); } @@ -718,15 +701,15 @@ module.exports = (_ => { } playAudio (type) { - if (this.dontPlayAudio(type) || BDFDB.LibraryModules.StreamerModeStore.disableSounds) return; + if (this.dontPlayAudio(type) || BDFDB.LibraryStores.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); + let channelSettings = BDFDB.LibraryStores.UserGuildSettingsStore.getChannelMessageNotifications(guildId, channelId); + return channelSettings && (channelSettings == BDFDB.DiscordConstants.UserNotificationSettings.NO_MESSAGES || channelSettings == BDFDB.DiscordConstants.UserNotificationSettings.NULL && BDFDB.LibraryStores.UserGuildSettingsStore.getMessageNotifications(guildId) == BDFDB.DiscordConstants.UserNotificationSettings.NO_MESSAGES); } dontPlayAudio (type) { @@ -743,5 +726,5 @@ module.exports = (_ => { 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)); + })(window.BDFDB_Global.PluginUtils.buildPlugin(changeLog)); })(); diff --git a/.config/BetterDiscord/plugins/PermissionsViewer.config.json b/.config/BetterDiscord/plugins/PermissionsViewer.config.json index d66c35a..3678bcc 100755 --- a/.config/BetterDiscord/plugins/PermissionsViewer.config.json +++ b/.config/BetterDiscord/plugins/PermissionsViewer.config.json @@ -1,6 +1,6 @@ { "currentVersionInfo": { - "version": "0.2.2", + "version": "0.2.6", "hasShownChangelog": true } } \ No newline at end of file diff --git a/.config/BetterDiscord/plugins/PermissionsViewer.plugin.js b/.config/BetterDiscord/plugins/PermissionsViewer.plugin.js index e7350f1..2722b9e 100755 --- a/.config/BetterDiscord/plugins/PermissionsViewer.plugin.js +++ b/.config/BetterDiscord/plugins/PermissionsViewer.plugin.js @@ -1,10 +1,11 @@ /** * @name PermissionsViewer - * @version 0.2.2 - * @authorLink https://twitter.com/IAmZerebos + * @description Allows you to view a user's permissions. Thanks to Noodlebox for the idea! + * @version 0.2.6 + * @author Zerebos + * @authorId 249746236008169473 * @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) @@ -29,49 +30,212 @@ 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)); +const config = { + info: { + name: "PermissionsViewer", + authors: [ + { + name: "Zerebos", + discord_id: "249746236008169473", + github_username: "rauenzi", + twitter_username: "ZackRauen" + } + ], + version: "0.2.6", + 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: [ + "Popouts and context menus should all work once again!" + ] + } + ], + 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" +}; +class Dummy { + constructor() {this._config = config;} + start() {} + stop() {} +} + +if (!global.ZeresPluginLibrary) { + BdApi.showConfirmationModal("Library Missing", `The library plugin needed for ${config.name ?? config.info.name} is missing. Please click Download Now to install it.`, { + confirmText: "Download Now", + cancelText: "Cancel", + onConfirm: () => { + require("request").get("https://betterdiscord.app/gh-redirect?id=9", async (err, resp, body) => { + if (err) return require("electron").shell.openExternal("https://betterdiscord.app/Download?id=9"); + if (resp.statusCode === 302) { + require("request").get(resp.headers.location, async (error, response, content) => { + 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"), content, r)); }); } + else { + 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; + }); +} + +module.exports = !global.ZeresPluginLibrary ? Dummy : (([Plugin, Api]) => { + const plugin = (Plugin, Api) => { + const {ContextMenu, DOM, Utils} = window.BdApi; + const {DiscordModules, WebpackModules, Toasts, DiscordClasses, Utilities, DOMTools, ColorConverter, 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 DiscordPerms = Object.assign({}, DiscordModules.DiscordPermissions); 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; - }; + const ModalClasses = WebpackModules.getByProps("root", "header", "small"); + const Strings = WebpackModules.getModule(m => m.Messages && m.Messages.COPY_ID).Messages; + const UserPopoutClasses = Object.assign({}, WebpackModules.getByProps("userPopout"), WebpackModules.getByProps("rolesList"), WebpackModules.getByProps("eyebrow")); + const UserPopoutSelectors = {}; + for (const key in UserPopoutClasses) UserPopoutSelectors[key] = new Structs.Selector(UserPopoutClasses[key]); + const RoleClasses = Object.assign({}, DiscordClasses.PopoutRoles, WebpackModules.getByProps("rolesList"), WebpackModules.getByProps("roleName", "roleIcon")); if (DiscordPerms.STREAM) { DiscordPerms.VIDEO = DiscordPerms.STREAM; @@ -85,7 +249,15 @@ module.exports = (() => { return class PermissionsViewer extends Plugin { constructor() { super(); - this.css = `.member-perms-header { + this.css = `.perm-user-avatar { + border-radius: 50%; + width: 16px; + height: 16px; + margin-right: 3px; +} + +.member-perms-header { + color: var(--header-secondary); display: flex; justify-content: space-between; } @@ -212,7 +384,6 @@ module.exports = (() => { } #permissions-modal-wrapper #permissions-modal { - display: flex; contain: layout; flex-direction: column; pointer-events: auto; @@ -291,7 +462,7 @@ module.exports = (() => { } #permissions-modal-wrapper .perm-side { - width: 250px; + width: 273px; background-color: #36393f; flex: 0 0 auto; display: flex; @@ -396,6 +567,10 @@ module.exports = (() => { .theme-light #permissions-modal-wrapper .role-item, .theme-light #permissions-modal-wrapper .perm-name { color: #000; +} + +#permissions-modal-wrapper #permissions-modal { + width: auto; }`; this.jumbo = `#permissions-modal-wrapper #permissions-modal { height: 840px; @@ -415,7 +590,7 @@ module.exports = (() => { width: 50%; }`; this.listHTML = `
-
+
\${label}
@@ -425,6 +600,18 @@ module.exports = (() => {
    +
    `; + this.skinHTML = `
    +

    +
    \${label}
    + + + + + + +

    +
    `; this.itemHTML = `
  • @@ -432,8 +619,8 @@ module.exports = (() => {
  • `; this.modalHTML = `
    -