diff --git a/src/api/ContextMenu.ts b/src/api/ContextMenu.ts index 9a8d7b66f..3f73a41ea 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, args?: Array) => void; +export type NavContextMenuPatchCallback = (children: Array, ...args: Array) => 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, args?: Array) => void; +export type GlobalContextMenuPatchCallback = (navId: string, children: Array, ...args: Array) => 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 1874f5f05..88a1eb9cc 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 cea71e03f..c3d4d6a2a 100644 --- a/src/plugins/devCompanion.dev.tsx +++ b/src/plugins/devCompanion.dev.tsx @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -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( + { + 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( - { - 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 eba77c752..609ef0831 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 d3358be43..d30bb7ccb 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 b71a9f162..f24455432 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 47954ba0f..88c0b1652 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 70c5045ba..eb494682f 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 09fb4e75c..8d33f81c7 100644 --- a/src/plugins/silentMessageToggle.tsx +++ b/src/plugins/silentMessageToggle.tsx @@ -40,28 +40,30 @@ function SilentMessageToggle() { return ( {tooltipProps => ( - +
+ +
)}
); @@ -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 83f64153f..d0edaac2a 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 similarity index 95% rename from src/plugins/volumeBooster.desktop.ts rename to src/plugins/volumeBooster.ts index 7d8144912..3f692c7f1 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:).+?(?=,)/,