diff options
-rw-r--r-- | src/api/ContextMenu.ts | 9 | ||||
-rw-r--r-- | src/plugins/apiContextMenu.ts | 46 | ||||
-rw-r--r-- | src/plugins/devCompanion.dev.tsx | 33 | ||||
-rw-r--r-- | src/plugins/emoteCloner.tsx | 6 | ||||
-rw-r--r-- | src/plugins/invisibleChat/index.tsx | 4 | ||||
-rw-r--r-- | src/plugins/messageActions.ts | 10 | ||||
-rw-r--r-- | src/plugins/reverseImageSearch.tsx | 6 | ||||
-rw-r--r-- | src/plugins/showHiddenChannels/index.tsx | 4 | ||||
-rw-r--r-- | src/plugins/silentMessageToggle.tsx | 50 | ||||
-rw-r--r-- | src/plugins/silentTyping.tsx | 4 | ||||
-rw-r--r-- | src/plugins/volumeBooster.ts (renamed from src/plugins/volumeBooster.desktop.ts) | 4 |
11 files changed, 105 insertions, 71 deletions
diff --git a/src/api/ContextMenu.ts b/src/api/ContextMenu.ts index 9a8d7b6..3f73a41 100644 --- a/src/api/ContextMenu.ts +++ b/src/api/ContextMenu.ts @@ -23,13 +23,13 @@ import type { ReactElement } from "react"; * @param children The rendered context menu elements * @param args Any arguments passed into making the context menu, like the guild, channel, user or message for example */ -export type NavContextMenuPatchCallback = (children: Array<React.ReactElement>, args?: Array<any>) => void; +export type NavContextMenuPatchCallback = (children: Array<React.ReactElement>, ...args: Array<any>) => void; /** * @param The navId of the context menu being patched * @param children The rendered context menu elements * @param args Any arguments passed into making the context menu, like the guild, channel, user or message for example */ -export type GlobalContextMenuPatchCallback = (navId: string, children: Array<React.ReactElement>, args?: Array<any>) => void; +export type GlobalContextMenuPatchCallback = (navId: string, children: Array<React.ReactElement>, ...args: Array<any>) => void; const ContextMenuLogger = new Logger("ContextMenu"); @@ -119,12 +119,13 @@ interface ContextMenuProps { } export function _patchContextMenu(props: ContextMenuProps) { + props.contextMenuApiArguments ??= []; const contextMenuPatches = navPatches.get(props.navId); if (contextMenuPatches) { for (const patch of contextMenuPatches) { try { - patch(props.children, props.contextMenuApiArguments); + patch(props.children, ...props.contextMenuApiArguments); } catch (err) { ContextMenuLogger.error(`Patch for ${props.navId} errored,`, err); } @@ -133,7 +134,7 @@ export function _patchContextMenu(props: ContextMenuProps) { for (const patch of globalPatches) { try { - patch(props.navId, props.children, props.contextMenuApiArguments); + patch(props.navId, props.children, ...props.contextMenuApiArguments); } catch (err) { ContextMenuLogger.error("Global patch errored,", err); } diff --git a/src/plugins/apiContextMenu.ts b/src/plugins/apiContextMenu.ts index 1874f5f..88a1eb9 100644 --- a/src/plugins/apiContextMenu.ts +++ b/src/plugins/apiContextMenu.ts @@ -18,9 +18,28 @@ import { Settings } from "@api/settings"; import { Devs } from "@utils/constants"; -import definePlugin from "@utils/types"; +import definePlugin, { type PatchReplacement } from "@utils/types"; import { addListener, removeListener } from "@webpack"; +/** + * The last var name corresponding to the Context Menu API (Discord, not ours) module + */ +let lastVarName = ""; + +/** + * @param target The patch replacement object + * @param exportKey The key exporting the build Context Menu component function + */ +function makeReplacementProxy(target: PatchReplacement, exportKey: string) { + return new Proxy(target, { + get(_, p) { + if (p === "match") return RegExp(`${exportKey},{(?<=${lastVarName}\\.${exportKey},{)`, "g"); + // @ts-expect-error + return Reflect.get(...arguments); + } + }); +} + function listener(exports: any, id: number) { if (!Settings.plugins.ContextMenuAPI.enabled) return removeListener(listener); @@ -37,13 +56,24 @@ function listener(exports: any, id: number) { all: true, noWarn: true, find: "navId:", - replacement: [{ - match: RegExp(`${id}(?<=(\\i)=.+?).+$`), - replace: (code, varName) => { - const regex = RegExp(`${key},{(?<=${varName}\\.${key},{)`, "g"); - return code.replace(regex, "$&contextMenuApiArguments:arguments,"); - } - }] + replacement: [ + { + // Set the lastVarName for our proxy to use + match: RegExp(`${id}(?<=(\\i)=.+?)`), + replace: (id, varName) => { + lastVarName = varName; + return id; + } + }, + /** + * We are using a proxy here to utilize the whole code the patcher gives us, instead of matching the entire module (which is super slow) + * Our proxy returns the corresponding match for that module utilizing lastVarName, which is set by the patch before + */ + makeReplacementProxy({ + match: "", // Needed to canonicalizeDescriptor + replace: "$&contextMenuApiArguments:arguments,", + }, key) + ] }); removeListener(listener); diff --git a/src/plugins/devCompanion.dev.tsx b/src/plugins/devCompanion.dev.tsx index cea71e0..c3d4d6a 100644 --- a/src/plugins/devCompanion.dev.tsx +++ b/src/plugins/devCompanion.dev.tsx @@ -16,7 +16,7 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { addContextMenuPatch } from "@api/ContextMenu"; +import { addContextMenuPatch, NavContextMenuPatchCallback, removeContextMenuPatch } from "@api/ContextMenu"; import { showNotification } from "@api/Notifications"; import { Devs } from "@utils/constants"; import Logger from "@utils/Logger"; @@ -221,6 +221,21 @@ function initWs(isManual = false) { }); } +const contextMenuPatch: NavContextMenuPatchCallback = kids => { + if (kids.some(k => k?.props?.id === NAV_ID)) return; + + kids.unshift( + <Menu.MenuItem + id={NAV_ID} + label="Reconnect Dev Companion" + action={() => { + socket?.close(1000, "Reconnecting"); + initWs(true); + }} + /> + ); +}; + export default definePlugin({ name: "DevCompanion", description: "Dev Companion Plugin", @@ -229,24 +244,12 @@ export default definePlugin({ start() { initWs(); - addContextMenuPatch("user-settings-cog", kids => { - if (kids.some(k => k?.props?.id === NAV_ID)) return; - - kids.unshift( - <Menu.MenuItem - id={NAV_ID} - label="Reconnect Dev Companion" - action={() => { - socket?.close(1000, "Reconnecting"); - initWs(true); - }} - /> - ); - }); + addContextMenuPatch("user-settings-cog", contextMenuPatch); }, stop() { socket?.close(1000, "Plugin Stopped"); socket = void 0; + removeContextMenuPatch("user-settings-cog", contextMenuPatch); } }); diff --git a/src/plugins/emoteCloner.tsx b/src/plugins/emoteCloner.tsx index eba77c7..609ef08 100644 --- a/src/plugins/emoteCloner.tsx +++ b/src/plugins/emoteCloner.tsx @@ -176,9 +176,9 @@ function CloneModal({ id, name: emojiName, isAnimated }: { id: string; name: str ); } -const messageContextMenuPatch: NavContextMenuPatchCallback = (children, args) => { - if (!args?.[0]) return; - const { favoriteableId, emoteClonerDataAlt, itemHref, itemSrc, favoriteableType } = args[0]; +const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => { + if (!props) return; + const { favoriteableId, emoteClonerDataAlt, itemHref, itemSrc, favoriteableType } = props; if (!emoteClonerDataAlt || favoriteableType !== "emoji") return; diff --git a/src/plugins/invisibleChat/index.tsx b/src/plugins/invisibleChat/index.tsx index d3358be..d30bb7c 100644 --- a/src/plugins/invisibleChat/index.tsx +++ b/src/plugins/invisibleChat/index.tsx @@ -131,8 +131,8 @@ export default definePlugin({ { find: ".activeCommandOption", replacement: { - match: /(.)\.push.{1,50}\(\i,\{.{1,30}\},"gift"\)\)/, - replace: "$&;try{$1.push($self.chatBarIcon())}catch{}", + match: /(.)\.push.{1,30}disabled:(\i),.{1,20}\},"gift"\)\)/, + replace: "$&;try{$2||$1.push($self.chatBarIcon())}catch{}", } }, ], diff --git a/src/plugins/messageActions.ts b/src/plugins/messageActions.ts index b71a9f1..f244554 100644 --- a/src/plugins/messageActions.ts +++ b/src/plugins/messageActions.ts @@ -20,13 +20,15 @@ import { addClickListener, removeClickListener } from "@api/MessageEvents"; import { migratePluginSettings } from "@api/settings"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; -import { findByPropsLazy, findLazy } from "@webpack"; -import { UserStore } from "@webpack/common"; +import { findByPropsLazy } from "@webpack"; +import { PermissionStore, UserStore } from "@webpack/common"; let isDeletePressed = false; const keydown = (e: KeyboardEvent) => e.key === "Backspace" && (isDeletePressed = true); const keyup = (e: KeyboardEvent) => e.key === "Backspace" && (isDeletePressed = false); +const MANAGE_CHANNELS = 1n << 4n; + migratePluginSettings("MessageClickActions", "MessageQuickActions"); export default definePlugin({ @@ -50,8 +52,6 @@ export default definePlugin({ start() { const MessageActions = findByPropsLazy("deleteMessage", "startEditMessage"); - const PermissionStore = findByPropsLazy("can", "initialize"); - const Permissions = findLazy(m => typeof m.MANAGE_MESSAGES === "bigint"); const EditStore = findByPropsLazy("isEditing", "isEditingAny"); document.addEventListener("keydown", keydown); @@ -64,7 +64,7 @@ export default definePlugin({ MessageActions.startEditMessage(chan.id, msg.id, msg.content); event.preventDefault(); } - } else if (Vencord.Settings.plugins.MessageClickActions.enableDeleteOnClick && (isMe || PermissionStore.can(Permissions.MANAGE_MESSAGES, chan))) { + } else if (Vencord.Settings.plugins.MessageClickActions.enableDeleteOnClick && (isMe || PermissionStore.can(MANAGE_CHANNELS, chan))) { MessageActions.deleteMessage(chan.id, msg.id); event.preventDefault(); } diff --git a/src/plugins/reverseImageSearch.tsx b/src/plugins/reverseImageSearch.tsx index 47954ba..88c0b16 100644 --- a/src/plugins/reverseImageSearch.tsx +++ b/src/plugins/reverseImageSearch.tsx @@ -34,9 +34,9 @@ function search(src: string, engine: string) { open(engine + encodeURIComponent(src), "_blank"); } -const imageContextMenuPatch: NavContextMenuPatchCallback = (children, args) => { - if (!args?.[0]) return; - const { reverseImageSearchType, itemHref, itemSrc } = args[0]; +const imageContextMenuPatch: NavContextMenuPatchCallback = (children, props) => { + if (!props) return; + const { reverseImageSearchType, itemHref, itemSrc } = props; if (!reverseImageSearchType || reverseImageSearchType !== "img") return; diff --git a/src/plugins/showHiddenChannels/index.tsx b/src/plugins/showHiddenChannels/index.tsx index 70c5045..eb49468 100644 --- a/src/plugins/showHiddenChannels/index.tsx +++ b/src/plugins/showHiddenChannels/index.tsx @@ -321,9 +321,7 @@ export default definePlugin({ ], }, { - // The module wasn't being found, so lets just escape everything - // eslint-disable-next-line no-useless-escape - find: "\^https\:\/\/\(\?\:canary\.\|ptb\.\)\?discord.com\/channels\/\(\\\\\d\+\|", + find: "\"^/guild-stages/(\\\\d+)(?:/)?(\\\\d+)?\"", replacement: { // Make mentions of hidden channels work match: /\i\.\i\.can\(\i\.\i\.VIEW_CHANNEL,\i\)/, diff --git a/src/plugins/silentMessageToggle.tsx b/src/plugins/silentMessageToggle.tsx index 09fb4e7..8d33f81 100644 --- a/src/plugins/silentMessageToggle.tsx +++ b/src/plugins/silentMessageToggle.tsx @@ -40,28 +40,30 @@ function SilentMessageToggle() { return ( <Tooltip text="Toggle Silent Message"> {tooltipProps => ( - <Button - {...tooltipProps} - onClick={() => setEnabled(prev => !prev)} - size="" - look={ButtonLooks.BLANK} - innerClassName={ButtonWrapperClasses.button} - style={{ margin: "0px 8px" }} - > - <div className={ButtonWrapperClasses.buttonWrapper}> - <svg - width="24" - height="24" - viewBox="0 0 24 24" - > - <g fill="currentColor"> - <path d="M18 10.7101C15.1085 9.84957 13 7.17102 13 4C13 3.69264 13.0198 3.3899 13.0582 3.093C12.7147 3.03189 12.3611 3 12 3C8.686 3 6 5.686 6 9V14C6 15.657 4.656 17 3 17V18H21V17C19.344 17 18 15.657 18 14V10.7101ZM8.55493 19C9.24793 20.19 10.5239 21 11.9999 21C13.4759 21 14.7519 20.19 15.4449 19H8.55493Z" /> - <path d="M18.2624 5.50209L21 2.5V1H16.0349V2.49791H18.476L16 5.61088V7H21V5.50209H18.2624Z" /> - {!enabled && <line x1="22" y1="2" x2="2" y2="22" stroke="var(--red-500)" stroke-width="2.5" />} - </g> - </svg> - </div> - </Button> + <div style={{ display: "flex" }}> + <Button + {...tooltipProps} + onClick={() => setEnabled(prev => !prev)} + size="" + look={ButtonLooks.BLANK} + innerClassName={ButtonWrapperClasses.button} + style={{ margin: "0px 8px" }} + > + <div className={ButtonWrapperClasses.buttonWrapper}> + <svg + width="24" + height="24" + viewBox="0 0 24 24" + > + <g fill="currentColor"> + <path d="M18 10.7101C15.1085 9.84957 13 7.17102 13 4C13 3.69264 13.0198 3.3899 13.0582 3.093C12.7147 3.03189 12.3611 3 12 3C8.686 3 6 5.686 6 9V14C6 15.657 4.656 17 3 17V18H21V17C19.344 17 18 15.657 18 14V10.7101ZM8.55493 19C9.24793 20.19 10.5239 21 11.9999 21C13.4759 21 14.7519 20.19 15.4449 19H8.55493Z" /> + <path d="M18.2624 5.50209L21 2.5V1H16.0349V2.49791H18.476L16 5.61088V7H21V5.50209H18.2624Z" /> + {!enabled && <line x1="22" y1="2" x2="2" y2="22" stroke="var(--red-500)" stroke-width="2.5" />} + </g> + </svg> + </div> + </Button> + </div> )} </Tooltip> ); @@ -75,8 +77,8 @@ export default definePlugin({ { find: ".activeCommandOption", replacement: { - match: /"gift"\)\);(?<=(\i)\.push.+?)/, - replace: (m, array) => `${m}${array}.push($self.SilentMessageToggle());` + match: /"gift"\)\);(?<=(\i)\.push.+?disabled:(\i),.+?)/, + replace: (m, array, disabled) => `${m}${disabled}||${array}.push($self.SilentMessageToggle());` } } ], diff --git a/src/plugins/silentTyping.tsx b/src/plugins/silentTyping.tsx index 83f6415..d0edaac 100644 --- a/src/plugins/silentTyping.tsx +++ b/src/plugins/silentTyping.tsx @@ -82,8 +82,8 @@ export default definePlugin({ find: ".activeCommandOption", predicate: () => settings.store.showIcon, replacement: { - match: /(.)\.push.{1,50}\(\i,\{.{1,30}\},"gift"\)\)/, - replace: "$&;try{$1.push($self.chatBarIcon())}catch{}", + match: /(.)\.push.{1,30}disabled:(\i),.{1,20}\},"gift"\)\)/, + replace: "$&;try{$2||$1.push($self.chatBarIcon())}catch{}", } }, ], diff --git a/src/plugins/volumeBooster.desktop.ts b/src/plugins/volumeBooster.ts index 7d81449..3f692c7 100644 --- a/src/plugins/volumeBooster.desktop.ts +++ b/src/plugins/volumeBooster.ts @@ -56,8 +56,8 @@ export default definePlugin({ find: "AudioContextSettingsMigrated", replacement: [ { - match: /(?<=updateAsync\("audioContextSettings".{0,50})(?=return (\i)\.volume=(\i))/, - replace: (_, volumeOptions, newVolume) => `if(${newVolume}>200)return ${volumeOptions}.volume=200;` + match: /(?<=updateAsync\("audioContextSettings".{0,350}return \i\.volume=)\i(?=})/, + replace: "$&>200?200:$&" }, { match: /(?<=Object\.entries\(\i\.localMutes\).+?volume:).+?(?=,)/, |