From 3109ff102ee8deb9f796caadacf5ebf25f195e0d Mon Sep 17 00:00:00 2001 From: Vendicated Date: Fri, 8 May 2026 16:00:46 +0200 Subject: [PATCH 1/5] Fix Vencord context menu options missing Also merges MenuItemDemanglerAPI into ContextMenuAPI because these patch the same module anyway and depend on each other --- src/plugins/_api/contextMenu.ts | 75 +++++++++++++++++++++++---- src/plugins/_api/menuItemDemangler.ts | 71 ------------------------- 2 files changed, 66 insertions(+), 80 deletions(-) delete mode 100644 src/plugins/_api/menuItemDemangler.ts diff --git a/src/plugins/_api/contextMenu.ts b/src/plugins/_api/contextMenu.ts index debc55273..8fe49d650 100644 --- a/src/plugins/_api/contextMenu.ts +++ b/src/plugins/_api/contextMenu.ts @@ -17,7 +17,23 @@ */ import { Devs } from "@utils/constants"; +import { canonicalizeMatch } from "@utils/patches"; import definePlugin from "@utils/types"; +import { Menu } from "@webpack/common"; + +// duplicate values have multiple branches with different types. Just include all to be safe +const nameMap = { + radio: "MenuRadioItem", + separator: "MenuSeparator", + checkbox: "MenuCheckboxItem", + groupstart: "MenuGroup", + + control: "MenuControlItem", + compositecontrol: "MenuControlItem", + + item: "MenuItem", + customitem: "MenuItem", +}; export default definePlugin({ name: "ContextMenuAPI", @@ -26,13 +42,6 @@ export default definePlugin({ required: true, patches: [ - { - find: "♫ (つ。◕‿‿◕。)つ ♪", - replacement: { - match: /(?=let{navId:)(?<=function \i\((\i)\).+?)/, - replace: "$1=Vencord.Api.ContextMenu._usePatchContextMenu($1);" - } - }, { find: "navId:", all: true, @@ -50,6 +59,54 @@ export default definePlugin({ } } ] - } - ] + }, + + { + find: "Menu API only allows Items", + replacement: [ + // Patch the central context menu handler + { + match: /(?=let{navId:)(?<=function \i\((\i)\).+?)/, + replace: "$1=Vencord.Api.ContextMenu._usePatchContextMenu($1);" + }, + + // Demangle Discord's Menu Item module + { + match: /(?<=(\(\i\.type===(\i\.\i)\).{0,50}?navigable:.+Menu API).+?)}$/s, + replace: (_, m) => { + const registerCalls = [] as string[]; + + const typeCheckRe = canonicalizeMatch(/\(\i\.type===(\i\.\i)\)/g); // if (t.type === m.MenuItem) + const pushTypeRe = /type:"(\w+)"/g; // push({type:"item"}) + + let typeMatch: RegExpExecArray | null; + while ((typeMatch = typeCheckRe.exec(m)) !== null) { + const component = typeMatch[1]; + // Set the starting index of the second regex to that of the first to start + // matching from after the if + pushTypeRe.lastIndex = typeCheckRe.lastIndex; + + // extract the first type: "..." + const type = pushTypeRe.exec(m)?.[1]; + if (type && type in nameMap) { + const name = nameMap[type]; + registerCalls.push(`$self.registerMenuItem("${name}",${component})`); + } + } + + if (registerCalls.length < 6) { + console.warn("[MenuItemDemanglerAPI] Expected to remap 6 items, only remapped", registerCalls.length); + } + + return `${registerCalls.join(";")};}`; + }, + } + ], + }, + ], + + registerMenuItem(name: string, component: any) { + Object.defineProperty(component, "name", { value: name }); + Menu[name] = component; + } }); diff --git a/src/plugins/_api/menuItemDemangler.ts b/src/plugins/_api/menuItemDemangler.ts deleted file mode 100644 index 72b8fee6d..000000000 --- a/src/plugins/_api/menuItemDemangler.ts +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Vencord, a Discord client mod - * Copyright (c) 2025 Vendicated and contributors - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -import { Devs } from "@utils/constants"; -import { canonicalizeMatch } from "@utils/patches"; -import definePlugin from "@utils/types"; -import { Menu } from "@webpack/common"; - -// duplicate values have multiple branches with different types. Just include all to be safe -const nameMap = { - radio: "MenuRadioItem", - separator: "MenuSeparator", - checkbox: "MenuCheckboxItem", - groupstart: "MenuGroup", - - control: "MenuControlItem", - compositecontrol: "MenuControlItem", - - item: "MenuItem", - customitem: "MenuItem", -}; - -export default definePlugin({ - name: "MenuItemDemanglerAPI", - description: "Demangles Discord's Menu Item module", - authors: [Devs.Ven], - required: true, - patches: [ - { - find: "Menu API only allows Items", - replacement: { - match: /(?<=(\(\i\.type===(\i\.\i)\).{0,50}?navigable:.+Menu API).+?)}$/s, - replace: (_, m) => { - const registerCalls = [] as string[]; - - const typeCheckRe = canonicalizeMatch(/\(\i\.type===(\i\.\i)\)/g); // if (t.type === m.MenuItem) - const pushTypeRe = /type:"(\w+)"/g; // push({type:"item"}) - - let typeMatch: RegExpExecArray | null; - while ((typeMatch = typeCheckRe.exec(m)) !== null) { - const component = typeMatch[1]; - // Set the starting index of the second regex to that of the first to start - // matching from after the if - pushTypeRe.lastIndex = typeCheckRe.lastIndex; - - // extract the first type: "..." - const type = pushTypeRe.exec(m)?.[1]; - if (type && type in nameMap) { - const name = nameMap[type]; - registerCalls.push(`$self.registerMenuItem("${name}",${component})`); - } - } - - if (registerCalls.length < 6) { - console.warn("[MenuItemDemanglerAPI] Expected to remap 6 items, only remapped", registerCalls.length); - } - - return `${registerCalls.join(";")};}`; - }, - }, - }, - ], - - registerMenuItem(name: string, component: any) { - Object.defineProperty(component, "name", { value: name }); - Menu[name] = component; - } -}); From 7a75cd64d0909af3069460ec55dd8f5b8066a515 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Fri, 8 May 2026 16:07:31 +0200 Subject: [PATCH 2/5] fix RoleColorEverywhere --- src/plugins/roleColorEverywhere/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/roleColorEverywhere/index.tsx b/src/plugins/roleColorEverywhere/index.tsx index 2b4b3e0c7..d50596398 100644 --- a/src/plugins/roleColorEverywhere/index.tsx +++ b/src/plugins/roleColorEverywhere/index.tsx @@ -107,8 +107,8 @@ export default definePlugin({ find: 'tutorialId:"whos-online', replacement: [ { - match: /(#{intl::CHANNEL_MEMBERS_A11Y_LABEL}.+}\):null,).{0,100}?— ",\i\]\}\)\]/, - replace: (_, rest) => `${rest}$self.RoleGroupColor(arguments[0])]` + match: /(#{intl::CHANNEL_MEMBERS_A11Y_LABEL}.+}\):null,).{0,100}?(?:—|\\u2014) ",\i\]\}\)\]/, + replace: "$1$self.RoleGroupColor(arguments[0])]" }, ], predicate: () => settings.store.memberList @@ -117,7 +117,7 @@ export default definePlugin({ find: "#{intl::THREAD_BROWSER_PRIVATE}", replacement: [ { - match: /children:\[\i," — ",\i\]/, + match: /children:\[\i," (?:—|\\u2014) ",\i\]/, replace: "children:[$self.RoleGroupColor(arguments[0])]" }, ], From 697715e9c85175f9cbdadcebbf15b4063f2b1a3e Mon Sep 17 00:00:00 2001 From: AutumnVN Date: Fri, 8 May 2026 21:52:28 +0700 Subject: [PATCH 3/5] fix NoMosaic (#4183) Co-authored-by: V --- src/plugins/noMosaic/index.ts | 53 +++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 src/plugins/noMosaic/index.ts diff --git a/src/plugins/noMosaic/index.ts b/src/plugins/noMosaic/index.ts new file mode 100644 index 000000000..b5fffba00 --- /dev/null +++ b/src/plugins/noMosaic/index.ts @@ -0,0 +1,53 @@ +/* + * Vencord, a Discord client mod + * Copyright (c) 2023 Vendicated and contributors + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +import { definePluginSettings } from "@api/Settings"; +import { Devs } from "@utils/constants"; +import definePlugin, { OptionType } from "@utils/types"; + +const settings = definePluginSettings({ + inlineVideo: { + description: "Play videos without carousel modal", + type: OptionType.BOOLEAN, + default: true, + restartNeeded: true + } +}); + +export default definePlugin({ + name: "NoMosaic", + authors: [Devs.AutumnVN], + description: "Removes Discord image mosaic", + tags: ["Media", "Appearance", "Chat"], + searchTerms: ["image", "mosaic", "media"], + + settings, + + patches: [ + { + find: '"PLAINTEXT_PREVIEW":"OTHER"', + replacement: { + match: /"IMAGE"===\i\|\|"VIDEO"===\i\|\|"CLIP"===\i/, + replace: "false" + } + }, + { + find: "return{visualMediaItems:", + replacement: { + match: /return{visualMediaItems:.+?props:(\i)(?=.{0,20}?\1\.item\.uniqueId)/, + replace: '$&,useFullWidth:["IMAGE","VIDEO","CLIP"].includes($1.item?.type)?false:undefined' + } + }, + { + find: "renderAttachments(", + predicate: () => settings.store.inlineVideo, + replacement: { + match: /url:(\i)\.url\}\);return /, + replace: "$&$1.content_type?.startsWith('image/')&&" + } + }, + ] +}); From 38340bbc2dc933cc81e52c2b38531e686940b261 Mon Sep 17 00:00:00 2001 From: AutumnVN Date: Fri, 8 May 2026 22:14:30 +0700 Subject: [PATCH 4/5] BetterFolders: fix using wrong folder icon (#4197) --- src/plugins/betterFolders/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/betterFolders/index.tsx b/src/plugins/betterFolders/index.tsx index 97677251f..acffff289 100644 --- a/src/plugins/betterFolders/index.tsx +++ b/src/plugins/betterFolders/index.tsx @@ -197,7 +197,7 @@ export default definePlugin({ { // Modify the expanded prop to use the boolean if the above patch fails, or check if the folder is expanded from the list if it succeeds // Also export the list of expanded folders to the child folder component if the patch above succeeds, else export undefined - match: /(?<=\(0,\i\.jsxs?\)\(\i,\{folderNode:(\i),expanded:)\i(?=,)/, + match: /(?<=\.\.\.\i,folderNode:(\i),expanded:)\i(?=,)/, replace: (isExpandedOrExpandedIds, folderNote) => "" + `typeof ${isExpandedOrExpandedIds}==="boolean"?${isExpandedOrExpandedIds}:${isExpandedOrExpandedIds}.has(${folderNote}.id),` + `betterFoldersExpandedIds:${isExpandedOrExpandedIds} instanceof Set?${isExpandedOrExpandedIds}:void 0` From 909df8b8c22e377aacbab6587db10e952bf1a461 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Fri, 8 May 2026 17:50:39 +0200 Subject: [PATCH 5/5] 1.14.13 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 73b79db6b..39dc4c4bb 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vencord", "private": "true", - "version": "1.14.12", + "version": "1.14.13", "description": "The cutest Discord client mod", "homepage": "https://github.com/Vendicated/Vencord#readme", "bugs": {