diff --git a/docs/1_INSTALLING.md b/docs/1_INSTALLING.md index d57e64e58..edeed4eb5 100644 --- a/docs/1_INSTALLING.md +++ b/docs/1_INSTALLING.md @@ -1,6 +1,6 @@ -> [!WARNING] -> These instructions are only for advanced users. If you're not a Developer, you should use our [graphical installer](https://github.com/Vendicated/VencordInstaller#usage) instead. -> No support will be provided for installing in this fashion. If you cannot figure it out, you should just stick to a regular install. +> [!WARNING] +> These instructions are only for advanced users. If you're not a Developer, you should use our [graphical installer](https://github.com/Vendicated/VencordInstaller#usage) instead. +> No support will be provided for installing in this fashion. If you cannot figure it out, you should just stick to a regular install. # Installation Guide @@ -95,5 +95,3 @@ Simply run: ```shell pnpm uninject ``` - -If you need more help, ask in the support channel in our [Discord Server](https://discord.gg/D9uwnFnqmd). diff --git a/scripts/generateReport.ts b/scripts/generateReport.ts index 33b099ef8..41e384295 100644 --- a/scripts/generateReport.ts +++ b/scripts/generateReport.ts @@ -67,7 +67,8 @@ const IGNORED_DISCORD_ERRORS = [ "Unable to process domain list delta: Client revision number is null", "Downloading the full bad domains file", /\[GatewaySocket\].{0,110}Cannot access '/, - "search for 'name' in undefined" + "search for 'name' in undefined", + "Attempting to set fast connect zstd when unsupported" ] as Array; function toCodeBlock(s: string) { diff --git a/src/plugins/_api/chatButtons.ts b/src/plugins/_api/chatButtons.ts index ca85964c0..1ec2fa25e 100644 --- a/src/plugins/_api/chatButtons.ts +++ b/src/plugins/_api/chatButtons.ts @@ -13,10 +13,10 @@ export default definePlugin({ authors: [Devs.Ven], patches: [{ - find: 'location:"ChannelTextAreaButtons"', + find: '"sticker")', replacement: { - match: /if\(!\i\.isMobile\)\{(?=.+?&&(\i)\.push\(.{0,50}"gift")/, - replace: "$&Vencord.Api.ChatButtons._injectButtons($1,arguments[0]);" + match: /!\i\.isMobile(?=.+?(\i)\.push\(.{0,50}"gift")/, + replace: "$& &&(Vencord.Api.ChatButtons._injectButtons($1,arguments[0]),true)" } }] }); diff --git a/src/plugins/_api/memberListDecorators.ts b/src/plugins/_api/memberListDecorators.ts index 1251c3578..5e3e5ed18 100644 --- a/src/plugins/_api/memberListDecorators.ts +++ b/src/plugins/_api/memberListDecorators.ts @@ -31,7 +31,7 @@ export default definePlugin({ match: /let\{[^}]*lostPermissionTooltipText:\i[^}]*\}=(\i),/, replace: "$&vencordProps=$1," }, { - match: /decorators:.{0,100}?children:\[/, + match: /\.Messages\.GUILD_OWNER(?=.+?decorators:(\i)\(\)).+?\1=?\(\)=>.+?children:\[/, replace: "$&...(typeof vencordProps=='undefined'?[]:Vencord.Api.MemberListDecorators.__getDecorators(vencordProps))," } ] diff --git a/src/plugins/betterNotes/index.tsx b/src/plugins/betterNotes/index.tsx index da41b9732..2183d98e2 100644 --- a/src/plugins/betterNotes/index.tsx +++ b/src/plugins/betterNotes/index.tsx @@ -18,6 +18,7 @@ import { Settings } from "@api/Settings"; import { Devs } from "@utils/constants"; +import { canonicalizeMatch } from "@utils/patches"; import definePlugin, { OptionType } from "@utils/types"; import { findByPropsLazy } from "@webpack"; @@ -39,8 +40,12 @@ export default definePlugin({ match: /hideNote:.+?(?=([,}].*?\)))/g, replace: (m, rest) => { const destructuringMatch = rest.match(/}=.+/); - if (destructuringMatch == null) return "hideNote:!0"; - return m; + if (destructuringMatch) { + const defaultValueMatch = m.match(canonicalizeMatch(/hideNote:(\i)=!?\d/)); + return defaultValueMatch ? `hideNote:${defaultValueMatch[1]}=!0` : m; + } + + return "hideNote:!0"; } } }, @@ -52,10 +57,10 @@ export default definePlugin({ } }, { - find: ".Messages.NOTE}", + find: ".popularApplicationCommandIds,", replacement: { - match: /(?<=return \i\?)null(?=:\(0,\i\.jsxs)/, - replace: "$self.patchPadding(arguments[0])" + match: /lastSection:(!?\i)}\),/, + replace: "$&$self.patchPadding($1)," } } ], @@ -75,8 +80,8 @@ export default definePlugin({ } }, - patchPadding(e: any) { - if (!e.lastSection) return; + patchPadding(lastSection: any) { + if (!lastSection) return; return (
); diff --git a/src/plugins/messageLogger/index.tsx b/src/plugins/messageLogger/index.tsx index 26409b89d..8a1e23912 100644 --- a/src/plugins/messageLogger/index.tsx +++ b/src/plugins/messageLogger/index.tsx @@ -225,7 +225,7 @@ export default definePlugin({ { // MessageStore // Module 171447 - find: "displayName=\"MessageStore\"", + find: '"MessageStore"', replacement: [ { // Add deleted=true to all target messages in the MESSAGE_DELETE event @@ -380,7 +380,7 @@ export default definePlugin({ { // ReferencedMessageStore // Module 778667 - find: "displayName=\"ReferencedMessageStore\"", + find: '"ReferencedMessageStore"', replacement: [ { match: /MESSAGE_DELETE:function\((\i)\).+?},/, diff --git a/src/plugins/pinDms/components/CreateCategoryModal.tsx b/src/plugins/pinDms/components/CreateCategoryModal.tsx index f38cc88c0..309ca69ff 100644 --- a/src/plugins/pinDms/components/CreateCategoryModal.tsx +++ b/src/plugins/pinDms/components/CreateCategoryModal.tsx @@ -31,9 +31,9 @@ interface ColorPickerWithSwatchesProps { } const ColorPicker = findComponentByCodeLazy(".Messages.USER_SETTINGS_PROFILE_COLOR_SELECT_COLOR", ".BACKGROUND_PRIMARY)"); -const ColorPickerWithSwatches = findComponentByCodeLazy(".presets,", "customColor:"); +const ColorPickerWithSwatches = findComponentByCodeLazy("presets,", "customColor:"); -export const requireSettingsMenu = extractAndLoadChunksLazy(['name:"UserSettings"'], /createPromise:.{0,20}el\("(.+?)"\).{0,50}"UserSettings"/); +export const requireSettingsMenu = extractAndLoadChunksLazy(['name:"UserSettings"'], /createPromise:.{0,20}Promise\.all\((\[\i\.\i\(".+?"\).+?\])\).then\(\i\.bind\(\i,"(.+?)"\)\).{0,50}"UserSettings"/); const cl = classNameFactory("vc-pindms-modal-"); diff --git a/src/plugins/pinDms/index.tsx b/src/plugins/pinDms/index.tsx index ee726bfab..8951f0949 100644 --- a/src/plugins/pinDms/index.tsx +++ b/src/plugins/pinDms/index.tsx @@ -79,11 +79,11 @@ export default definePlugin({ // Rendering { - match: /this\.renderDM=\(.+?(\i\.default),{channel.+?this.renderRow=(\i)=>{/, - replace: "$&if($self.isChannelIndex($2.section, $2.row))return $self.renderChannel($2.section,$2.row,$1);" + match: /"renderRow",(\i)=>{(?<="renderDM",.+?(\i\.default),\{channel:.+?)/, + replace: "$&if($self.isChannelIndex($1.section, $1.row))return $self.renderChannel($1.section,$1.row,$2);" }, { - match: /this\.renderSection=(\i)=>{/, + match: /"renderSection",(\i)=>{/, replace: "$&if($self.isCategoryIndex($1.section))return $self.renderCategory($1);" }, { @@ -93,11 +93,11 @@ export default definePlugin({ // Fix Row Height { - match: /(?<=this\.getRowHeight=.{1,100}return 1===)\i/, + match: /(?<="getRowHeight",.{1,100}return 1===)\i/, replace: "($&-$self.categoryLen())" }, { - match: /this.getRowHeight=\((\i),(\i)\)=>{/, + match: /"getRowHeight",\((\i),(\i)\)=>{/, replace: "$&if($self.isChannelHidden($1,$2))return 0;" }, diff --git a/src/plugins/readAllNotificationsButton/index.tsx b/src/plugins/readAllNotificationsButton/index.tsx index 0e08edb6d..ae66e11a4 100644 --- a/src/plugins/readAllNotificationsButton/index.tsx +++ b/src/plugins/readAllNotificationsButton/index.tsx @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +import "./style.css"; + import { addServerListElement, removeServerListElement, ServerListRenderPosition } from "@api/ServerList"; import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; @@ -49,9 +51,11 @@ const ReadAllButton = () => ( + color={Button.Colors.CUSTOM} + className="vc-ranb-button" + > + Read All + ); export default definePlugin({ diff --git a/src/plugins/readAllNotificationsButton/style.css b/src/plugins/readAllNotificationsButton/style.css new file mode 100644 index 000000000..3d10b2bd5 --- /dev/null +++ b/src/plugins/readAllNotificationsButton/style.css @@ -0,0 +1,11 @@ +.vc-ranb-button { + color: var(--interactive-normal); + padding: 0 0.5em; + margin-bottom: 0.5em; + width: 100%; + box-sizing: border-box; +} + +.vc-ranb-button:hover { + color: var(--interactive-active); +} diff --git a/src/plugins/userVoiceShow/index.tsx b/src/plugins/userVoiceShow/index.tsx index 935ff1c5d..200cfe895 100644 --- a/src/plugins/userVoiceShow/index.tsx +++ b/src/plugins/userVoiceShow/index.tsx @@ -98,8 +98,8 @@ export default definePlugin({ { find: ".popularApplicationCommandIds,", replacement: { - match: /\(0,\i\.jsx\)\(\i\.\i,{user:\i,setNote/, - replace: "$self.patchPopout(arguments[0]),$&", + match: /applicationId:\i\.id}\),(?=.{0,50}setNote:\i)/, + replace: "$&$self.patchPopout(arguments[0]),", } }, // below username diff --git a/src/plugins/webContextMenus.web/index.ts b/src/plugins/webContextMenus.web/index.ts index faa240783..ac4689036 100644 --- a/src/plugins/webContextMenus.web/index.ts +++ b/src/plugins/webContextMenus.web/index.ts @@ -195,7 +195,7 @@ export default definePlugin({ // Add back "Show My Camera" context menu { - find: '.default("MediaEngineWebRTC");', + find: '"MediaEngineWebRTC");', replacement: { match: /supports\(\i\)\{switch\(\i\)\{case (\i).Features/, replace: "$&.DISABLE_VIDEO:return true;case $1.Features" diff --git a/src/plugins/whoReacted/index.tsx b/src/plugins/whoReacted/index.tsx index b60366900..b3728c215 100644 --- a/src/plugins/whoReacted/index.tsx +++ b/src/plugins/whoReacted/index.tsx @@ -93,28 +93,30 @@ export default definePlugin({ description: "Renders the avatars of users who reacted to a message", authors: [Devs.Ven, Devs.KannaDev, Devs.newwares], - patches: [{ - find: ",reactionRef:", - replacement: { - match: /(\i)\?null:\(0,\i\.jsx\)\(\i\.\i,{className:\i\.reactionCount,.*?}\),/, - replace: "$&$1?null:$self.renderUsers(this.props)," - } - }, { - find: '.displayName="MessageReactionsStore";', - replacement: { - match: /(?<=CONNECTION_OPEN:function\(\){)(\i)={}/, - replace: "$&;$self.reactions=$1" - } - }, - { + patches: [ + { + find: ",reactionRef:", + replacement: { + match: /(\i)\?null:\(0,\i\.jsx\)\(\i\.\i,{className:\i\.reactionCount,.*?}\),/, + replace: "$&$1?null:$self.renderUsers(this.props)," + } + }, { + find: '"MessageReactionsStore"', + replacement: { + match: /(?<=CONNECTION_OPEN:function\(\){)(\i)={}/, + replace: "$&;$self.reactions=$1" + } + }, + { - find: "cleanAutomaticAnchor(){", - replacement: { - match: /this\.automaticAnchor=null,this\.messageFetchAnchor=null,/, - replace: "$&$self.setScrollObj(this)," + find: "cleanAutomaticAnchor(){", + replacement: { + match: /constructor\(\i\)\{(?=.{0,100}automaticAnchor)/, + replace: "$&$self.setScrollObj(this);" + } } - } ], + setScrollObj(scroll: any) { Scroll = scroll; }, diff --git a/src/webpack/common/stores.ts b/src/webpack/common/stores.ts index f3a18d7bc..2f9786bc5 100644 --- a/src/webpack/common/stores.ts +++ b/src/webpack/common/stores.ts @@ -44,7 +44,6 @@ export let PermissionStore: GenericStore; export let GuildChannelStore: GenericStore; export let ReadStateStore: GenericStore; export let PresenceStore: GenericStore; -export let PoggerModeSettingsStore: GenericStore; export let GuildStore: t.GuildStore; export let UserStore: Stores.UserStore & t.FluxStore; diff --git a/src/webpack/webpack.ts b/src/webpack/webpack.ts index 992bf38f3..0790e8bf1 100644 --- a/src/webpack/webpack.ts +++ b/src/webpack/webpack.ts @@ -110,13 +110,13 @@ export const find = traceFunction("find", function find(filter: FilterFn, { isIn for (const key in cache) { const mod = cache[key]; - if (!mod?.exports) continue; + if (!mod?.exports || mod.exports === window) continue; if (filter(mod.exports)) { return isWaitFor ? [mod.exports, key] : mod.exports; } - if (mod.exports.default && filter(mod.exports.default)) { + if (mod.exports.default && mod.exports.default !== window && filter(mod.exports.default)) { const found = mod.exports.default; return isWaitFor ? [found, key] : found; } @@ -408,10 +408,11 @@ export function findExportedComponentLazy(...props: stri /** * Extract and load chunks using their entry point - * @param code An array of all the code the module factory containing the entry point (as of using it to load chunks) must include - * @param matcher A RegExp that returns the entry point id as the first capture group. Defaults to a matcher that captures the first entry point found in the module factory + * @param code An array of all the code the module factory containing the lazy chunk loading must include + * @param matcher A RegExp that returns the chunk ids array as the first capture group and the entry point id as the second. Defaults to a matcher that captures the lazy chunk loading found in the module factory + * @returns A promise that resolves when the chunks were loaded */ -export async function extractAndLoadChunks(code: string[], matcher: RegExp = /\.el\("(.+?)"\)(?<=(\i)\.el.+?)\.then\(\2\.bind\(\2,"\1"\)\)/) { +export async function extractAndLoadChunks(code: string[], matcher: RegExp = /Promise\.all\((\[\i\.\i\(".+?"\).+?\])\).then\(\i\.bind\(\i,"(.+?)"\)\)/) { const module = findModuleFactory(...code); if (!module) { const err = new Error("extractAndLoadChunks: Couldn't find module factory"); @@ -432,9 +433,9 @@ export async function extractAndLoadChunks(code: string[], matcher: RegExp = /\. return; } - const [, id] = match; - if (!id || !Number(id)) { - const err = new Error("extractAndLoadChunks: Matcher didn't return a capturing group with the entry point, or the entry point returned wasn't a number"); + const [, rawChunkIds, entryPointId] = match; + if (!rawChunkIds || Number.isNaN(entryPointId)) { + const err = new Error("extractAndLoadChunks: Matcher didn't return a capturing group with the chunk ids array, or the entry point id returned as the second group wasn't a number"); logger.warn(err, "Code:", code, "Matcher:", matcher); // Strict behaviour in DevBuilds to fail early and make sure the issue is found @@ -444,19 +445,21 @@ export async function extractAndLoadChunks(code: string[], matcher: RegExp = /\. return; } - await (wreq as any).el(id); - return wreq(id as any); + const chunkIds = Array.from(rawChunkIds.matchAll(/\("(.+?)"\)/g)).map((m: any) => m[1]); + + await Promise.all(chunkIds.map(id => wreq.e(id))); + wreq(entryPointId); } /** * This is just a wrapper around {@link extractAndLoadChunks} to make our reporter test for your webpack finds. * * Extract and load chunks using their entry point - * @param code An array of all the code the module factory containing the entry point (as of using it to load chunks) must include - * @param matcher A RegExp that returns the entry point id as the first capture group. Defaults to a matcher that captures the first entry point found in the module factory - * @returns A function that loads the chunks on first call + * @param code An array of all the code the module factory containing the lazy chunk loading must include + * @param matcher A RegExp that returns the chunk ids array as the first capture group and the entry point id as the second. Defaults to a matcher that captures the lazy chunk loading found in the module factory + * @returns A function that returns a promise that resolves when the chunks were loaded, on first call */ -export function extractAndLoadChunksLazy(code: string[], matcher: RegExp = /\.el\("(.+?)"\)(?<=(\i)\.el.+?)\.then\(\2\.bind\(\2,"\1"\)\)/) { +export function extractAndLoadChunksLazy(code: string[], matcher: RegExp = /Promise\.all\((\[\i\.\i\(".+?"\).+?\])\).then\(\i\.bind\(\i,"(.+?)"\)\)/) { if (IS_DEV) lazyWebpackSearchHistory.push(["extractAndLoadChunks", [code, matcher]]); return () => extractAndLoadChunks(code, matcher);