/** * @name FakeDeafen * @author Ahlawat * @authorId 1025214794766221384 * @version 1.4.4 * @invite SgKSKyh9gY * @description Fake your audio status, to make it look like you are muted or deafened when you're not. * @website https://tharki-god.github.io/ * @source https://github.com/Tharki-God/BetterDiscordPlugins * @updateUrl https://tharki-god.github.io/BetterDiscordPlugins/FakeDeafen.plugin.js */ /*@cc_on @if (@_jscript) var shell = WScript.CreateObject("WScript.Shell"); var fs = new ActiveXObject("Scripting.FileSystemObject"); var pathPlugins = shell.ExpandEnvironmentStrings("%APPDATA%\\BetterDiscord\\plugins"); var pathSelf = WScript.ScriptFullName; 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 move myself to BetterDiscord's plugins folder for you?", 0, "Do you need some help?", 0x34) === 6) { fs.MoveFile(pathSelf, fs.BuildPath(pathPlugins, fs.GetFileName(pathSelf))); shell.Exec("explorer " + pathPlugins); shell.Popup("I'm installed!", 0, "Successfully installed", 0x40); } WScript.Quit(); @else@*/ module.exports = (() => { const config = { info: { name: "FakeDeafen", authors: [ { name: "Ahlawat", discord_id: "1025214794766221384", github_username: "Tharki-God", }, ], version: "1.4.4", description: "Fake your audio status, to make it look like you are muted or deafened when you're not.", github: "https://github.com/Tharki-God/BetterDiscordPlugins", github_raw: "https://tharki-god.github.io/BetterDiscordPlugins/FakeDeafen.plugin.js", }, changelog: [ { title: "v0.2.3", items: ["Easier To use Now"], }, { title: "v0.2.4", items: ["Reindented file"], }, { title: "v0.2.6", items: ["Fixed some bugs, and made the code better looking."], }, { title: "v0.3.7", items: ["Updater Library, Meta Update url having bugs."], }, { title: "v0.3.8", items: ["Wifey.exe executed, lol ヾ(•ω•`)o."], }, { title: "v0.3.9", items: ["Refractor"], }, { title: "v0.4.0", items: ["Library Handler"], }, { title: "Initial Release v1.0.0", items: [ "This is the initial release of the plugin :)", "Fool them all (●'◡'●)", ], }, { title: "v1.0.2", items: ["Added Fake Video", "Removed Useless code"], }, { title: "v1.0.6", items: ["Option to toogle without disabling plugin itself."], }, { title: "v1.0.9", items: ["Keybind to toogle, by default: CTRL+D."], }, { title: "v1.3.2", items: ["Corrected text."], }, ], main: "FakeDeafen.plugin.js", }; const RequiredLibs = [{ window: "ZeresPluginLibrary", filename: "0PluginLibrary.plugin.js", external: "https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js", downloadUrl: "https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js" }, { window: "BunnyLib", filename: "1BunnyLib.plugin.js", external: "https://github.com/Tharki-God/BetterDiscordPlugins", downloadUrl: "https://tharki-god.github.io/BetterDiscordPlugins/1BunnyLib.plugin.js" }, ]; class handleMissingLibrarys { load() { for (const Lib of RequiredLibs.filter(lib => !window.hasOwnProperty(lib.window))) BdApi.showConfirmationModal( "Library Missing", `The library plugin (${Lib.window}) needed for ${config.info.name} is missing. Please click Download Now to install it.`, { confirmText: "Download Now", cancelText: "Cancel", onConfirm: () => this.downloadLib(Lib), } ); } async downloadLib(Lib) { const fs = require("fs"); const path = require("path"); const { Plugins } = BdApi; const LibFetch = await fetch( Lib.downloadUrl ); if (!LibFetch.ok) return this.errorDownloadLib(Lib); const LibContent = await LibFetch.text(); try { await fs.writeFile( path.join(Plugins.folder, Lib.filename), LibContent, (err) => { if (err) return this.errorDownloadLib(Lib); } ); } catch (err) { return this.errorDownloadLib(Lib); } } errorDownloadZLib(Lib) { const { shell } = require("electron"); BdApi.showConfirmationModal( "Error Downloading", [ `${Lib.window} download failed. Manually install plugin library from the link below.`, ], { confirmText: "Download", cancelText: "Cancel", onConfirm: () => { shell.openExternal( Lib.external ); }, } ); } start() { } stop() { } } return RequiredLibs.some(m => !window.hasOwnProperty(m.window)) ? handleMissingLibrarys : (([Plugin, ZLibrary]) => { const { WebpackModules, Toasts, Utilities, PluginUpdater, Logger, DOMTools, Settings: { SettingPanel, SettingGroup, Switch }, DiscordModules: { React, LocaleManager }, } = ZLibrary; const { Patcher, ContextMenu } = BdApi; const { LibraryUtils, ReactUtils, LibraryIcons, Settings: { Keybind }, LibraryModules: { WindowInfoStore, KeybindUtils, AccountDetails, PanelButton, Menu, StatusPicker, SoundModule, NotificationStore, AudioUtils, GatewayConnectionStore } } = BunnyLib.build(config); const NotificationVars = () => NotificationStore.__getLocalVars(); const CSS = `.withTagAsButton-OsgQ9L { min-width:0; } `; const Sounds = { Enable: "reconnect", Disable: "stream_ended", }; const defaultSettings = { toFake: { mute: true, deaf: true, video: false, }, statusPicker: true, userPanel: false, playAudio: false, showToast: true, keybind: KeybindUtils.Kd("ctrl+d"), }; return class FakeDeafen extends Plugin { constructor() { super(); this.currentlyPressed = {}; this.keybindListener = this.keybindListener.bind(this); this.cleanCallback = this.cleanCallback.bind(this); this.settings = Utilities.loadData( config.info.name, "settings", defaultSettings ); this.enabled = Utilities.loadData( config.info.name, "enabled", true ); } checkForUpdates() { try { PluginUpdater.checkForUpdate( config.info.name, config.info.version, config.info.github_raw ); } catch (err) { Logger.err("Plugin Updater could not be reached.", err); } } onStart() { this.checkForUpdates(); this.init(); this.addListeners(); } addListeners() { window.addEventListener("keydown", this.keybindListener); window.addEventListener("keyup", this.keybindListener); WindowInfoStore.addChangeListener(this.cleanCallback); } async init() { if (this.enabled) await this.fakeIt(); if (this.settings["statusPicker"]) this.patchStatusPicker(); if (this.settings["userPanel"]) this.patchPanelButton(); } patchStatusPicker() { Patcher.before(config.info.name, Menu, "ZP", (_, args) => { if (args[0]?.navId != "account") return args; const [ { children } ] = args; const Icon = ReactUtils.addStyle(LibraryIcons.Sound("16", "16"), { marginLeft: "-2px", }); const DisabledIcon = ReactUtils.addChilds(Icon, React.createElement("polygon", { style: { fill: "#a61616", }, points: "22.6,2.7 22.6,2.8 19.3,6.1 16,9.3 16,9.4 15,10.4 15,10.4 10.3,15 2.8,22.5 1.4,21.1 21.2,1.3 ", })); const switchAccount = children.find( (c) => c?.props?.children?.key == "switch-account" ); if (!children.find((c) => c?.props?.className == "tharki")) children.splice( children.indexOf(switchAccount), 0, React.createElement(Menu.kS, { className: "tharki", children: [], }) ); const section = children.find( (c) => c?.props?.className == "tharki" ); if ( !section.props.children.find((m) => m?.props?.id == "fake-deafen") ) section.props.children.push( React.createElement(Menu.sN, { id: "fake-deafen", keepItemStyles: true, action: () => { return this.toggle(); }, render: () => React.createElement( "div", { onContextMenu: (event) => this.renderContextMenu(event), className: StatusPicker.statusItem, "aria-label": `${this.enabled ? "Unfake" : "Fake" } audio status`, }, this.enabled ? Icon : DisabledIcon, React.createElement( "div", { className: StatusPicker.status, }, `${this.enabled ? "Unfake" : "Fake"} audio status` ), React.createElement( "div", { className: StatusPicker.description, }, `Whether to ${this.enabled ? "unfake" : "fake" } deafen/mute/video status for others.` ) ), }) ); }); } patchPanelButton() { DOMTools.addStyle(config.info.name, CSS); Patcher.before(config.info.name, AccountDetails, "Z", (_, args) => { const [{ children }] = args; if ( !children?.some?.( (m) => m?.props?.tooltipText == LocaleManager.Messages["MUTE"] || m?.props?.tooltipText == LocaleManager.Messages["UNMUTE"] ) ) return; const Icon = LibraryIcons.Sound("20", "20"); const DisabledIcon = ReactUtils.addChilds(Icon, React.createElement("polygon", { style: { fill: "#a61616", }, points: "22.6,2.7 22.6,2.8 19.3,6.1 16,9.3 16,9.4 15,10.4 15,10.4 10.3,15 2.8,22.5 1.4,21.1 21.2,1.3 ", })); children.unshift( React.createElement(PanelButton, { onContextMenu: (event) => this.renderContextMenu(event), icon: () => this.enabled ? Icon : DisabledIcon, tooltipText: `${this.enabled ? "Unfake" : "Fake" } audio status`, onClick: () => { this.toggle(); }, }) ); }); } renderContextMenu(event) { ContextMenu.open( event, ContextMenu.buildMenu([ { label: "What to fake?", type: "text", }, { type: "separator", }, { type: "toggle", label: "Mute", checked: this.settings["toFake"]["mute"], action: () => { this.settings["toFake"]["mute"] = !this.settings["toFake"]["mute"]; this.saveSettings(); }, }, { type: "toggle", label: "Deafen", checked: this.settings["toFake"]["deaf"], action: () => { this.settings["toFake"]["deaf"] = !this.settings["toFake"]["deaf"]; this.saveSettings(); }, }, { type: "toggle", label: "Video", checked: this.settings["toFake"]["video"], action: () => { this.settings["toFake"]["video"] = !this.settings["toFake"]["video"]; this.saveSettings(); }, }, ]) ); } onStop() { Patcher.unpatchAll("fake-deafen"); Patcher.unpatchAll(config.info.name); this.removeListeners(); DOMTools.removeStyle(config.info.name); } removeListeners() { window.removeEventListener("keydown", this.keybindListener); window.removeEventListener("keyup", this.keybindListener); WindowInfoStore.removeChangeListener(this.cleanCallback); } cleanCallback() { if (WindowInfoStore.isFocused()) this.currentlyPressed = {}; } keybindListener(e) { const keybindEvent = KeybindUtils.d2(this.settings["keybind"]); if ( e.type == "keyup" && keybindEvent.length && keybindEvent.every( (ev) => Object.keys(ev) .filter((k) => k !== "keyCode") .every((k) => ev[k] == e[k]) && this.currentlyPressed[ev["keyCode"]] ) ) { if (this.settings["showToast"]) Toasts.show( `${this.enabled ? "Unfaked" : "Faked"} audio status`, { icon: "https://tharki-god.github.io/files-random-host/sound%20fake%20deaf.png", timeout: 1000, type: "success", } ); this.toggle(); } this.currentlyPressed[e.keyCode] = e.type == "keydown"; } toggle() { if (this.settings["playAudio"]) SoundModule.GN( this.enabled ? Sounds.Disable : Sounds.Enable, 0.5 ); this.enabled ? this.unfakeIt() : this.fakeIt(); } unfakeIt() { Patcher.unpatchAll("fake-deafen"); this.enabled = false; Utilities.saveData(config.info.name, "enabled", this.enabled); this.update(); } async fakeIt() { const voiceSocket = GatewayConnectionStore.getSocket(); Patcher.instead( "fake-deafen", voiceSocket, "voiceStateUpdate", (instance, args) => { instance.send(4, { guild_id: args[0].guildId, channel_id: args[0].channelId, preferredRegion: args[0].preferredRegion, self_mute: this.settings["toFake"]["mute"] || args[0].selfMute, self_deaf: this.settings["toFake"]["deaf"] || args[0].selfDeaf, self_video: this.settings["toFake"]["video"] || args[0].selfVideo, }); } ); this.enabled = true; Utilities.saveData(config.info.name, "enabled", this.enabled); this.update(); } async update() { const toCheck = ["mute", "unmute"]; const toToggle = toCheck.filter( (sound) => !NotificationVars().state.disabledSounds.includes(sound) ); if (toToggle.length > 0) Object.defineProperty(NotificationVars().state, "disabledSounds", { value: [...toToggle, ...NotificationVars().state.disabledSounds], writable: true, }); await AudioUtils.toggleSelfMute(); await LibraryUtils.Sleep(100); AudioUtils.toggleSelfMute(); if (toToggle.length > 0) Object.defineProperty(NotificationVars().state, "disabledSounds", { value: NotificationVars().state.disabledSounds.filter( (sound) => !toToggle.includes(sound) ), writable: true, }); } getSettingsPanel() { return SettingPanel.build( this.saveSettings.bind(this), new SettingGroup("What to fake?", { collapsible: true, shown: false, }).append( new Switch( "Mute", "Whether you want to fake mute or not.", this.settings["toFake"]["mute"], (e) => { this.settings["toFake"]["mute"] = e; } ), new Switch( "Deafen", "Whether you want to fake deafen or not.", this.settings["toFake"]["deaf"], (e) => { this.settings["toFake"]["deaf"] = e; } ), new Switch( "Video", "Whether you want to fake video or not.", this.settings["toFake"]["video"], (e) => { this.settings["toFake"]["video"] = e; } ) ), new SettingGroup("Toggle options", { collapsible: true, shown: false, }).append( new Keybind( "Toggle by keybind:", "Keybind to toggle faking.", this.settings["keybind"], (e) => { this.settings["keybind"] = e; } ), new Switch( "Show toasts", "Whether to show toasts on using keybinds.", this.settings["showToast"], (e) => { this.settings["showToast"] = e; } ), new Switch( "Status picker", "Add an option in the status picker to toggle faking.", this.settings["statusPicker"], (e) => { this.settings["statusPicker"] = e; } ), new Switch( "User panel", "Add a button in the user panel to toggle faking.", this.settings["userPanel"], (e) => { this.settings["userPanel"] = e; } ), new Switch( "Play audio", "Play a sound upon using the keybind or clicking the button in the status picker or user panel.", this.settings["playAudio"], (e) => { this.settings["playAudio"] = e; } ) ) ); } saveSettings() { Utilities.saveData(config.info.name, "settings", this.settings); Patcher.unpatchAll("fake-deafen"); Patcher.unpatchAll(config.info.name); this.init(); } }; })(ZLibrary.buildPlugin(config)); })(); /*@end@*/