From 5c7fa5578ce97b8f5c59e38a963d0e240eec833e Mon Sep 17 00:00:00 2001 From: nyan <24845294+nyakowint@users.noreply.github.com> Date: Sun, 12 May 2024 18:54:08 -0400 Subject: [PATCH 01/12] XSOverlay: Adjust message length timeout (#2445) --- src/plugins/xsOverlay.desktop/index.ts | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/plugins/xsOverlay.desktop/index.ts b/src/plugins/xsOverlay.desktop/index.ts index b666d116..5251959f 100644 --- a/src/plugins/xsOverlay.desktop/index.ts +++ b/src/plugins/xsOverlay.desktop/index.ts @@ -68,7 +68,6 @@ interface Call { ringing: string[]; } -const MuteStore = findByPropsLazy("isSuppressEveryoneEnabled"); const Notifs = findByPropsLazy("makeTextChatNotification"); const XSLog = new Logger("XSOverlay"); @@ -115,13 +114,13 @@ const settings = definePluginSettings({ }, timeout: { type: OptionType.NUMBER, - description: "Notif duration (secs)", - default: 1.0, + description: "Notification duration (secs)", + default: 3, }, - timeoutPerCharacter: { - type: OptionType.NUMBER, - description: "Duration multiplier per character", - default: 0.5 + lengthBasedTimeout: { + type: OptionType.BOOLEAN, + description: "Extend duration with message length", + default: true }, opacity: { type: OptionType.SLIDER, @@ -262,12 +261,11 @@ function shouldIgnoreForChannelType(channel: Channel) { } function sendMsgNotif(titleString: string, content: string, message: Message) { - const timeout = Math.max(settings.store.timeout, content.length * settings.store.timeoutPerCharacter); fetch(`https://cdn.discordapp.com/avatars/${message.author.id}/${message.author.avatar}.png?size=128`).then(response => response.arrayBuffer()).then(result => { const msgData = { messageType: 1, index: 0, - timeout, + timeout: settings.store.lengthBasedTimeout ? calculateTimeout(content) : settings.store.timeout, height: calculateHeight(content), opacity: settings.store.opacity, volume: settings.store.volume, @@ -286,7 +284,7 @@ function sendOtherNotif(content: string, titleString: string) { const msgData = { messageType: 1, index: 0, - timeout: settings.store.timeout, + timeout: settings.store.lengthBasedTimeout ? calculateTimeout(content) : settings.store.timeout, height: calculateHeight(content), opacity: settings.store.opacity, volume: settings.store.volume, @@ -313,3 +311,10 @@ function calculateHeight(content: string) { if (content.length <= 300) return 200; return 250; } + +function calculateTimeout(content: string) { + if (content.length <= 100) return 3; + if (content.length <= 200) return 4; + if (content.length <= 300) return 5; + return 6; +} From fd7dafb15327efa95eedc313998e6900715f67f4 Mon Sep 17 00:00:00 2001 From: dolfies Date: Sun, 12 May 2024 19:07:12 -0400 Subject: [PATCH 02/12] fix(MessageLatency): Adjust for Discord kotlin clients (#2443) --- src/plugins/messageLatency/index.tsx | 47 +++++++++++++++++++++------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/src/plugins/messageLatency/index.tsx b/src/plugins/messageLatency/index.tsx index 48b57863..301e605f 100644 --- a/src/plugins/messageLatency/index.tsx +++ b/src/plugins/messageLatency/index.tsx @@ -24,19 +24,27 @@ interface Diff { seconds: number; } +const DISCORD_KT_DELAY = 1471228.928; const HiddenVisually = findExportedComponentLazy("HiddenVisually"); export default definePlugin({ name: "MessageLatency", description: "Displays an indicator for messages that took ≥n seconds to send", authors: [Devs.arHSM], + settings: definePluginSettings({ latency: { type: OptionType.NUMBER, description: "Threshold in seconds for latency indicator", default: 2 + }, + detectDiscordKotlin: { + type: OptionType.BOOLEAN, + description: "Detect old Discord Android clients", + default: true } }), + patches: [ { find: "showCommunicationDisabledStyles", @@ -46,6 +54,7 @@ export default definePlugin({ } } ], + stringDelta(delta: number) { const diff: Diff = { days: Math.round(delta / (60 * 60 * 24)), @@ -71,15 +80,25 @@ export default definePlugin({ ); }, ""); - return [ts || "0 seconds", diff.days === 17 && diff.hours === 1] as const; + return ts || "0 seconds"; }, + latencyTooltipData(message: Message) { + const { latency, detectDiscordKotlin } = this.settings.store; const { id, nonce } = message; // Message wasn't received through gateway if (!isNonNullish(nonce)) return null; - const delta = Math.round((SnowflakeUtils.extractTimestamp(id) - SnowflakeUtils.extractTimestamp(nonce)) / 1000); + let isDiscordKotlin = false; + let delta = Math.round((SnowflakeUtils.extractTimestamp(id) - SnowflakeUtils.extractTimestamp(nonce)) / 1000); + + // Old Discord Android clients have a delay of around 17 days + // This is a workaround for that + if (-delta >= DISCORD_KT_DELAY - 86400) { // One day of padding for good measure + isDiscordKotlin = detectDiscordKotlin; + delta += DISCORD_KT_DELAY; + } // Thanks dziurwa (I hate you) // This is when the user's clock is ahead @@ -87,15 +106,13 @@ export default definePlugin({ const abs = Math.abs(delta); const ahead = abs !== delta; - const [stringDelta, isSuspectedKotlinDiscord] = this.stringDelta(abs); - const isKotlinDiscord = ahead && isSuspectedKotlinDiscord; + const stringDelta = abs >= latency ? this.stringDelta(abs) : null; // Also thanks dziurwa // 2 minutes const TROLL_LIMIT = 2 * 60; - const { latency } = this.settings.store; - const fill: Fill = isKotlinDiscord + const fill: Fill = isDiscordKotlin ? ["status-positive", "status-positive", "text-muted"] : delta >= TROLL_LIMIT || ahead ? ["text-muted", "text-muted", "text-muted"] @@ -103,17 +120,24 @@ export default definePlugin({ ? ["status-danger", "text-muted", "text-muted"] : ["status-warning", "status-warning", "text-muted"]; - return abs >= latency ? { delta: stringDelta, ahead, fill, isKotlinDiscord } : null; + return (abs >= latency || isDiscordKotlin) ? { delta: stringDelta, ahead, fill, isDiscordKotlin } : null; }, + Tooltip() { return ErrorBoundary.wrap(({ message }: { message: Message; }) => { - const d = this.latencyTooltipData(message); if (!isNonNullish(d)) return null; + let text: string; + if (!d.delta) { + text = "User is suspected to be on an old Discord Android client"; + } else { + text = (d.ahead ? `This user's clock is ${d.delta} ahead.` : `This message was sent with a delay of ${d.delta}.`) + (d.isDiscordKotlin ? " User is suspected to be on an old Discord Android client." : ""); + } + return { @@ -126,8 +150,9 @@ export default definePlugin({ ; }); }, + Icon({ delta, fill, props }: { - delta: string; + delta: string | null; fill: Fill, props: { onClick(): void; @@ -147,7 +172,7 @@ export default definePlugin({ role="img" fill="none" style={{ marginRight: "8px", verticalAlign: -1 }} - aria-label={delta} + aria-label={delta ?? "Old Discord Android client"} aria-hidden="false" {...props} > From 902b6bcdf20c6e9b3170ace70c124834e6e4f8cd Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Sun, 12 May 2024 20:58:26 -0300 Subject: [PATCH 03/12] PinDMs: ErrorBoundary renderChannel --- src/plugins/pinDms/index.tsx | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/plugins/pinDms/index.tsx b/src/plugins/pinDms/index.tsx index 010b5506..79503b9a 100644 --- a/src/plugins/pinDms/index.tsx +++ b/src/plugins/pinDms/index.tsx @@ -320,25 +320,26 @@ export default definePlugin({ ); - }), + }, { noop: true }), renderChannel(sectionIndex: number, index: number, ChannelComponent: React.ComponentType) { - const { channel, category } = this.getChannel(sectionIndex, index, this.instance.props.channels); + return ErrorBoundary.wrap(() => { + const { channel, category } = this.getChannel(sectionIndex, index, this.instance.props.channels); - if (!channel || !category) return null; - if (this.isChannelHidden(sectionIndex, index)) return null; + if (!channel || !category) return null; + if (this.isChannelHidden(sectionIndex, index)) return null; - return ( - - {channel.id} - - ); + return ( + + {channel.id} + + ); + }, { noop: true }); }, - getChannel(sectionIndex: number, index: number, channels: Record) { const category = categories[sectionIndex - 1]; if (!category) return { channel: null, category: null }; From 1f1c80c5f3bf897cec82d08302a2d3f396436ed0 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Mon, 13 May 2024 03:30:10 +0200 Subject: [PATCH 04/12] ValidUser: fix crashing when viewing a valid-userd staff's profile --- src/plugins/validUser/index.tsx | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/plugins/validUser/index.tsx b/src/plugins/validUser/index.tsx index 7a21ac86..fd88ca9c 100644 --- a/src/plugins/validUser/index.tsx +++ b/src/plugins/validUser/index.tsx @@ -18,6 +18,7 @@ import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; +import { isNonNullish } from "@utils/guards"; import { sleep } from "@utils/misc"; import { Queue } from "@utils/Queue"; import definePlugin from "@utils/types"; @@ -27,19 +28,20 @@ import type { ComponentType, ReactNode } from "react"; // LYING to the type checker here const UserFlags = Constants.UserFlags as Record; const badges: Record = { - "active_developer": { id: "active_developer", description: "Active Developer", icon: "6bdc42827a38498929a4920da12695d9", link: "https://support-dev.discord.com/hc/en-us/articles/10113997751447" }, - "bug_hunter_level_1": { id: "bug_hunter_level_1", description: "Discord Bug Hunter", icon: "2717692c7dca7289b35297368a940dd0", link: "https://support.discord.com/hc/en-us/articles/360046057772-Discord-Bugs" }, - "bug_hunter_level_2": { id: "bug_hunter_level_2", description: "Discord Bug Hunter", icon: "848f79194d4be5ff5f81505cbd0ce1e6", link: "https://support.discord.com/hc/en-us/articles/360046057772-Discord-Bugs" }, - "certified_moderator": { id: "certified_moderator", description: "Moderator Programs Alumni", icon: "fee1624003e2fee35cb398e125dc479b", link: "https://discord.com/safety" }, - "discord_employee": { id: "staff", description: "Discord Staff", icon: "5e74e9b61934fc1f67c65515d1f7e60d", link: "https://discord.com/company" }, - "hypesquad": { id: "hypesquad", description: "HypeSquad Events", icon: "bf01d1073931f921909045f3a39fd264", link: "https://discord.com/hypesquad" }, - "hypesquad_online_house_1": { id: "hypesquad_house_1", description: "HypeSquad Bravery", icon: "8a88d63823d8a71cd5e390baa45efa02", link: "https://discord.com/settings/hypesquad-online" }, - "hypesquad_online_house_2": { id: "hypesquad_house_2", description: "HypeSquad Brilliance", icon: "011940fd013da3f7fb926e4a1cd2e618", link: "https://discord.com/settings/hypesquad-online" }, - "hypesquad_online_house_3": { id: "hypesquad_house_3", description: "HypeSquad Balance", icon: "3aa41de486fa12454c3761e8e223442e", link: "https://discord.com/settings/hypesquad-online" }, - "partner": { id: "partner", description: "Partnered Server Owner", icon: "3f9748e53446a137a052f3454e2de41e", link: "https://discord.com/partners" }, - "premium": { id: "premium", description: "Subscriber", icon: "2ba85e8026a8614b640c2837bcdfe21b", link: "https://discord.com/settings/premium" }, - "premium_early_supporter": { id: "early_supporter", description: "Early Supporter", icon: "7060786766c9c840eb3019e725d2b358", link: "https://discord.com/settings/premium" }, - "verified_developer": { id: "verified_developer", description: "Early Verified Bot Developer", icon: "6df5892e0f35b051f8b61eace34f4967" }, + active_developer: { id: "active_developer", description: "Active Developer", icon: "6bdc42827a38498929a4920da12695d9", link: "https://support-dev.discord.com/hc/en-us/articles/10113997751447" }, + bug_hunter_level_1: { id: "bug_hunter_level_1", description: "Discord Bug Hunter", icon: "2717692c7dca7289b35297368a940dd0", link: "https://support.discord.com/hc/en-us/articles/360046057772-Discord-Bugs" }, + bug_hunter_level_2: { id: "bug_hunter_level_2", description: "Discord Bug Hunter", icon: "848f79194d4be5ff5f81505cbd0ce1e6", link: "https://support.discord.com/hc/en-us/articles/360046057772-Discord-Bugs" }, + certified_moderator: { id: "certified_moderator", description: "Moderator Programs Alumni", icon: "fee1624003e2fee35cb398e125dc479b", link: "https://discord.com/safety" }, + discord_employee: { id: "staff", description: "Discord Staff", icon: "5e74e9b61934fc1f67c65515d1f7e60d", link: "https://discord.com/company" }, + get staff() { return this.discord_employee; }, + hypesquad: { id: "hypesquad", description: "HypeSquad Events", icon: "bf01d1073931f921909045f3a39fd264", link: "https://discord.com/hypesquad" }, + hypesquad_online_house_1: { id: "hypesquad_house_1", description: "HypeSquad Bravery", icon: "8a88d63823d8a71cd5e390baa45efa02", link: "https://discord.com/settings/hypesquad-online" }, + hypesquad_online_house_2: { id: "hypesquad_house_2", description: "HypeSquad Brilliance", icon: "011940fd013da3f7fb926e4a1cd2e618", link: "https://discord.com/settings/hypesquad-online" }, + hypesquad_online_house_3: { id: "hypesquad_house_3", description: "HypeSquad Balance", icon: "3aa41de486fa12454c3761e8e223442e", link: "https://discord.com/settings/hypesquad-online" }, + partner: { id: "partner", description: "Partnered Server Owner", icon: "3f9748e53446a137a052f3454e2de41e", link: "https://discord.com/partners" }, + premium: { id: "premium", description: "Subscriber", icon: "2ba85e8026a8614b640c2837bcdfe21b", link: "https://discord.com/settings/premium" }, + premium_early_supporter: { id: "early_supporter", description: "Early Supporter", icon: "7060786766c9c840eb3019e725d2b358", link: "https://discord.com/settings/premium" }, + verified_developer: { id: "verified_developer", description: "Early Verified Bot Developer", icon: "6df5892e0f35b051f8b61eace34f4967" }, }; const fetching = new Set(); @@ -93,7 +95,8 @@ async function getUser(id: string) { userObj = UserStore.getUser(id); const fakeBadges: ProfileBadge[] = Object.entries(UserFlags) .filter(([_, flag]) => !isNaN(flag) && userObj.hasFlag(flag)) - .map(([key]) => badges[key.toLowerCase()]); + .map(([key]) => badges[key.toLowerCase()]) + .filter(isNonNullish); if (user.premium_type || !user.bot && (user.banner || user.avatar?.startsWith?.("a_"))) fakeBadges.push(badges.premium); From f6765818d2248292b4dacf74c3ae3e2eae5856d4 Mon Sep 17 00:00:00 2001 From: Vendicated Date: Mon, 13 May 2024 03:34:01 +0200 Subject: [PATCH 05/12] ValidUser: fix rendering old mentions when message is edited Fixes https://github.com/Vendicated/Vencord/issues/2451 --- src/plugins/pinDms/index.tsx | 2 +- src/plugins/validUser/index.tsx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/pinDms/index.tsx b/src/plugins/pinDms/index.tsx index 79503b9a..60484561 100644 --- a/src/plugins/pinDms/index.tsx +++ b/src/plugins/pinDms/index.tsx @@ -83,7 +83,7 @@ export default definePlugin({ // Rendering { match: /"renderRow",(\i)=>{(?<="renderDM",.+?(\i\.default),\{channel:.+?)/, - replace: "$&if($self.isChannelIndex($1.section, $1.row))return $self.renderChannel($1.section,$1.row,$2);" + replace: "$&if($self.isChannelIndex($1.section, $1.row))return $self.renderChannel($1.section,$1.row,$2)();" }, { match: /"renderSection",(\i)=>{/, diff --git a/src/plugins/validUser/index.tsx b/src/plugins/validUser/index.tsx index fd88ca9c..64b734f5 100644 --- a/src/plugins/validUser/index.tsx +++ b/src/plugins/validUser/index.tsx @@ -23,7 +23,7 @@ import { sleep } from "@utils/misc"; import { Queue } from "@utils/Queue"; import definePlugin from "@utils/types"; import { Constants, FluxDispatcher, RestAPI, UserProfileStore, UserStore, useState } from "@webpack/common"; -import type { ComponentType, ReactNode } from "react"; +import { type ComponentType, type ReactNode } from "react"; // LYING to the type checker here const UserFlags = Constants.UserFlags as Record; @@ -205,6 +205,7 @@ export default definePlugin({ return ( Date: Mon, 13 May 2024 01:09:19 -0400 Subject: [PATCH 06/12] feat(ShowHiddenThings): Remove Discovery banned/NSFW filters (#2453) --- src/plugins/showHiddenThings/README.md | 4 +++- src/plugins/showHiddenThings/index.ts | 24 +++++++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/plugins/showHiddenThings/README.md b/src/plugins/showHiddenThings/README.md index e969391e..753e5c14 100644 --- a/src/plugins/showHiddenThings/README.md +++ b/src/plugins/showHiddenThings/README.md @@ -1,6 +1,6 @@ # ShowHiddenThings -Displays various moderator-only elements regardless of permissions. +Displays various hidden & moderator-only things regardless of permissions. ## Features @@ -15,3 +15,5 @@ Displays various moderator-only elements regardless of permissions. ![](https://github.com/Vendicated/Vencord/assets/47677887/3dac95dd-841c-4c15-ad87-2db7bd1e4dab) - Disable filters in Server Discovery search that hide servers that don't meet discovery criteria + +- Disable filters in Server Discovery search that hide NSFW & disallowed servers diff --git a/src/plugins/showHiddenThings/index.ts b/src/plugins/showHiddenThings/index.ts index 1858582a..8de70aca 100644 --- a/src/plugins/showHiddenThings/index.ts +++ b/src/plugins/showHiddenThings/index.ts @@ -41,13 +41,18 @@ const settings = definePluginSettings({ description: "Disable filters in Server Discovery search that hide servers that don't meet discovery criteria.", default: true, }, + disableDisallowedDiscoveryFilters: { + type: OptionType.BOOLEAN, + description: "Disable filters in Server Discovery search that hide NSFW & disallowed servers.", + default: true, + }, }); migratePluginSettings("ShowHiddenThings", "ShowTimeouts"); export default definePlugin({ name: "ShowHiddenThings", tags: ["ShowTimeouts", "ShowInvitesPaused", "ShowModView", "DisableDiscoveryFilters"], - description: "Displays various moderator-only elements regardless of permissions.", + description: "Displays various hidden & moderator-only things regardless of permissions.", authors: [Devs.Dolfies], patches: [ { @@ -81,6 +86,23 @@ export default definePlugin({ match: /filters:\i\.join\(" AND "\),facets:\[/, replace: "facets:[" } + }, + { + find: "DiscoveryBannedSearchWords.includes", + predicate: () => settings.store.disableDisallowedDiscoveryFilters, + replacement: { + match: /(?<=function\(\){)(?=.{0,130}DiscoveryBannedSearchWords\.includes)/, + replace: "return false;" + } + }, + { + find: "Endpoints.GUILD_DISCOVERY_VALID_TERM", + predicate: () => settings.store.disableDisallowedDiscoveryFilters, + all: true, + replacement: { + match: /\i\.HTTP\.get\(\{url:\i\.Endpoints\.GUILD_DISCOVERY_VALID_TERM,query:\{term:\i\},oldFormErrors:!0\}\);/g, + replace: "Promise.resolve({ body: { valid: true } });" + } } ], settings, From 9621dc7bb39087a752910eab170701fb6b4be585 Mon Sep 17 00:00:00 2001 From: axiand Date: Tue, 14 May 2024 03:16:49 +0200 Subject: [PATCH 07/12] EmoteCloner: allow cloning from reactions (#2458) --- src/plugins/emoteCloner/index.tsx | 5 +++-- src/utils/constants.ts | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/plugins/emoteCloner/index.tsx b/src/plugins/emoteCloner/index.tsx index cd9890a8..8c3ded6a 100644 --- a/src/plugins/emoteCloner/index.tsx +++ b/src/plugins/emoteCloner/index.tsx @@ -322,8 +322,9 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, props) = switch (favoriteableType) { case "emoji": const match = props.message.content.match(RegExp(`|https://cdn\\.discordapp\\.com/emojis/${favoriteableId}\\.`)); - if (!match) return; - const name = match[1] ?? "FakeNitroEmoji"; + const reaction = props.message.reactions.find(reaction => reaction.emoji.id === favoriteableId); + if (!match && !reaction) return; + const name = (match && match[1]) ?? reaction?.emoji.name ?? "FakeNitroEmoji"; return buildMenuItem("Emoji", () => ({ id: favoriteableId, diff --git a/src/utils/constants.ts b/src/utils/constants.ts index c1e2cea2..e446a27b 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -473,6 +473,10 @@ export const Devs = /* #__PURE__*/ Object.freeze({ ImBanana: { name: "Im_Banana", id: 635250116688871425n + }, + xocherry: { + name: "xocherry", + id: 221288171013406720n } } satisfies Record); From bd6f9e6f32e5ad95f7e16f323746a5770b1208de Mon Sep 17 00:00:00 2001 From: Amia <9750071+aamiaa@users.noreply.github.com> Date: Tue, 14 May 2024 03:22:49 +0200 Subject: [PATCH 08/12] fix(MutualGroupDMs): properly pass props (#2457) Co-authored-by: vee --- src/plugins/mutualGroupDMs/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/mutualGroupDMs/index.tsx b/src/plugins/mutualGroupDMs/index.tsx index e787fefb..94998677 100644 --- a/src/plugins/mutualGroupDMs/index.tsx +++ b/src/plugins/mutualGroupDMs/index.tsx @@ -56,12 +56,12 @@ export default definePlugin({ find: ".UserProfileSections.USER_INFO_CONNECTIONS:", replacement: { match: /(?<={user:(\i),onClose:(\i)}\);)(?=case \i\.\i\.MUTUAL_FRIENDS)/, - replace: "case \"MUTUAL_GDMS\":return $self.renderMutualGDMs($1,$2);" + replace: "case \"MUTUAL_GDMS\":return $self.renderMutualGDMs({user: $1, onClose: $2});" } } ], - renderMutualGDMs: ErrorBoundary.wrap((user: User, onClose: () => void) => { + renderMutualGDMs: ErrorBoundary.wrap(({ user, onClose }: { user: User, onClose: () => void; }) => { const entries = ChannelStore.getSortedPrivateChannels().filter(c => c.isGroupDM() && c.recipients.includes(user.id)).map(c => ( Date: Tue, 14 May 2024 04:39:05 +0300 Subject: [PATCH 09/12] FakeNitro: allow using subscription-locked emojis (#2456) Co-authored-by: Vendicated --- src/plugins/fakeNitro/index.tsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/plugins/fakeNitro/index.tsx b/src/plugins/fakeNitro/index.tsx index 087928e9..29318366 100644 --- a/src/plugins/fakeNitro/index.tsx +++ b/src/plugins/fakeNitro/index.tsx @@ -39,6 +39,7 @@ const StickerStore = findStoreLazy("StickersStore") as { const UserSettingsProtoStore = findStoreLazy("UserSettingsProtoStore"); const ProtoUtils = findByPropsLazy("BINARY_READ_OPTIONS"); +const RoleSubscriptionEmojiUtils = findByPropsLazy("isUnusableRoleSubscriptionEmoji"); function searchProtoClassField(localName: string, protoClass: any) { const field = protoClass?.fields?.find((field: any) => field.localName === localName); @@ -408,6 +409,15 @@ export default definePlugin({ match: /canUseCustomNotificationSounds:function\(\i\){/, replace: "$&return true;" } + }, + // Allows the usage of subscription-locked emojis + { + find: "isUnusableRoleSubscriptionEmoji:function", + replacement: { + match: /isUnusableRoleSubscriptionEmoji:function/, + // replace the original export with a func that always returns false and alias the original + replace: "isUnusableRoleSubscriptionEmoji:()=>()=>false,isUnusableRoleSubscriptionEmojiOriginal:function" + } } ], @@ -804,6 +814,9 @@ export default definePlugin({ if (e.require_colons === false) return true; if (e.available === false) return false; + const isUnusableRoleSubEmoji = RoleSubscriptionEmojiUtils.isUnusableRoleSubscriptionEmojiOriginal ?? RoleSubscriptionEmojiUtils.isUnusableRoleSubscriptionEmoji; + if (isUnusableRoleSubEmoji(e, this.guildId)) return false; + if (this.canUseEmotes) return e.guildId === this.guildId || hasExternalEmojiPerms(channelId); else From 892167420aa2db6fc6563c7e6ace5e37a4c946ea Mon Sep 17 00:00:00 2001 From: Anubis <102488279+AnubisNekhet@users.noreply.github.com> Date: Tue, 14 May 2024 07:27:20 +0530 Subject: [PATCH 10/12] MessageLogger: use discord variables instead of hardcoded colors (#2428) --- src/plugins/messageLogger/deleteStyleOverlay.css | 2 +- src/plugins/messageLogger/deleteStyleText.css | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/messageLogger/deleteStyleOverlay.css b/src/plugins/messageLogger/deleteStyleOverlay.css index 3778e80b..59e4ac66 100644 --- a/src/plugins/messageLogger/deleteStyleOverlay.css +++ b/src/plugins/messageLogger/deleteStyleOverlay.css @@ -1,3 +1,3 @@ .messagelogger-deleted { - background-color: rgba(240 71 71 / 15%) !important; + background-color: hsla(var(--red-430-hsl, 0 85% 61%) / 15%) !important; } diff --git a/src/plugins/messageLogger/deleteStyleText.css b/src/plugins/messageLogger/deleteStyleText.css index 8fb8bf12..3477ef22 100644 --- a/src/plugins/messageLogger/deleteStyleText.css +++ b/src/plugins/messageLogger/deleteStyleText.css @@ -1,19 +1,19 @@ /* Message content highlighting */ .messagelogger-deleted [class*="contents"] > :is(div, h1, h2, h3, p) { - color: #f04747 !important; + color: var(--status-danger, #f04747) !important; } /* Bot "thinking" text highlighting */ .messagelogger-deleted [class*="colorStandard"] { - color: #f04747 !important; + color: var(--status-danger, #f04747) !important; } /* Embed highlighting */ .messagelogger-deleted article :is(div, span, h1, h2, h3, p) { - color: #f04747 !important; + color: var(--status-danger, #f04747) !important; } .messagelogger-deleted a { - color: #be3535 !important; + color: var(--red-460, #be3535) !important; text-decoration: underline; } From 9dc8e4e24493b0dd5bd4758eb419e5d1c4052029 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Mon, 13 May 2024 22:45:57 -0300 Subject: [PATCH 11/12] Properly ErrorBoundary recent changes --- src/plugins/betterNotes/index.tsx | 12 ++-- src/plugins/pauseInvitesForever/index.tsx | 71 ++++++++++++----------- 2 files changed, 41 insertions(+), 42 deletions(-) diff --git a/src/plugins/betterNotes/index.tsx b/src/plugins/betterNotes/index.tsx index 5ebca1f8..cacdba5f 100644 --- a/src/plugins/betterNotes/index.tsx +++ b/src/plugins/betterNotes/index.tsx @@ -61,7 +61,7 @@ export default definePlugin({ find: ".popularApplicationCommandIds,", replacement: { match: /lastSection:(!?\i)}\),/, - replace: "$&$self.patchPadding($1)," + replace: "$&$self.patchPadding({lastSection:$1})," } } ], @@ -81,12 +81,10 @@ export default definePlugin({ } }, - patchPadding(lastSection: any) { - if (!lastSection) return; + patchPadding: ErrorBoundary.wrap(({ lastSection }) => { + if (!lastSection) return null; return ( - -
-
+
); - } + }) }); diff --git a/src/plugins/pauseInvitesForever/index.tsx b/src/plugins/pauseInvitesForever/index.tsx index 1e71a4ed..e7abaa17 100644 --- a/src/plugins/pauseInvitesForever/index.tsx +++ b/src/plugins/pauseInvitesForever/index.tsx @@ -24,6 +24,22 @@ import { GuildStore, i18n, RestAPI } from "@webpack/common"; const { InvitesDisabledExperiment } = findByPropsLazy("InvitesDisabledExperiment"); +function showDisableInvites(guildId: string) { + // Once the experiment is removed, this should keep working + const { enableInvitesDisabled } = InvitesDisabledExperiment?.getCurrentConfig?.({ guildId }) ?? { enableInvitesDisabled: true }; + // @ts-ignore + return enableInvitesDisabled && !GuildStore.getGuild(guildId).hasFeature("INVITES_DISABLED"); +} + +function disableInvites(guildId: string) { + const guild = GuildStore.getGuild(guildId); + const features = [...guild.features, "INVITES_DISABLED"]; + RestAPI.patch({ + url: `/guilds/${guild.id}`, + body: { features }, + }); +} + export default definePlugin({ name: "PauseInvitesForever", tags: ["DisableInvitesForever"], @@ -33,44 +49,29 @@ export default definePlugin({ patches: [ { find: "Messages.GUILD_INVITE_DISABLE_ACTION_SHEET_DESCRIPTION", - replacement: [{ - match: /children:\i\.\i\.\i\.GUILD_INVITE_DISABLE_ACTION_SHEET_DESCRIPTION/, - replace: "children: $self.renderInvitesLabel(arguments[0].guildId, setChecked)", - }, - { - match: /(\i\.hasDMsDisabled\)\(\i\),\[\i,(\i)\]=\i\.useState\(\i\))/, - replace: "$1,setChecked=$2" - }] + group: true, + replacement: [ + { + match: /children:\i\.\i\.\i\.GUILD_INVITE_DISABLE_ACTION_SHEET_DESCRIPTION/, + replace: "children: $self.renderInvitesLabel({guildId:arguments[0].guildId,setChecked})", + }, + { + match: /(\i\.hasDMsDisabled\)\(\i\),\[\i,(\i)\]=\i\.useState\(\i\))/, + replace: "$1,setChecked=$2" + } + ] } ], - showDisableInvites(guildId: string) { - // Once the experiment is removed, this should keep working - const { enableInvitesDisabled } = InvitesDisabledExperiment?.getCurrentConfig?.({ guildId }) ?? { enableInvitesDisabled: true }; - // @ts-ignore - return enableInvitesDisabled && !GuildStore.getGuild(guildId).hasFeature("INVITES_DISABLED"); - }, - - disableInvites(guildId: string) { - const guild = GuildStore.getGuild(guildId); - const features = [...guild.features, "INVITES_DISABLED"]; - RestAPI.patch({ - url: `/guilds/${guild.id}`, - body: { features }, - }); - }, - - renderInvitesLabel(guildId: string, setChecked: Function) { + renderInvitesLabel: ErrorBoundary.wrap(({ guildId, setChecked }) => { return ( - -
- {i18n.Messages.GUILD_INVITE_DISABLE_ACTION_SHEET_DESCRIPTION} - {this.showDisableInvites(guildId) && { - setChecked(true); - this.disableInvites(guildId); - }}> Pause Indefinitely.} -
-
+
+ {i18n.Messages.GUILD_INVITE_DISABLE_ACTION_SHEET_DESCRIPTION} + {showDisableInvites(guildId) && { + setChecked(true); + disableInvites(guildId); + }}> Pause Indefinitely.} +
); - } + }) }); From d4ebfc233fde9e54b76ca17cb2cac82fbb4d6aa9 Mon Sep 17 00:00:00 2001 From: Nuckyz <61953774+Nuckyz@users.noreply.github.com> Date: Mon, 13 May 2024 23:00:02 -0300 Subject: [PATCH 12/12] Make all RestAPI calls use Endpoints object --- src/plugins/betterSessions/index.tsx | 4 ++-- src/plugins/emoteCloner/index.tsx | 6 +++--- src/plugins/friendInvites/index.ts | 4 ++-- src/plugins/invisibleChat.desktop/index.tsx | 4 ++-- src/plugins/messageLinkEmbeds/index.tsx | 3 ++- src/plugins/pauseInvitesForever/index.tsx | 4 ++-- src/plugins/unsuppressEmbeds/index.tsx | 4 ++-- src/plugins/validUser/index.tsx | 2 +- src/plugins/voiceMessages/index.tsx | 4 ++-- src/plugins/whoReacted/index.tsx | 4 ++-- src/utils/discord.tsx | 4 ++-- 11 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/plugins/betterSessions/index.tsx b/src/plugins/betterSessions/index.tsx index 539508f8..9c93289c 100644 --- a/src/plugins/betterSessions/index.tsx +++ b/src/plugins/betterSessions/index.tsx @@ -22,7 +22,7 @@ import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import definePlugin, { OptionType } from "@utils/types"; import { findByPropsLazy, findExportedComponentLazy, findStoreLazy } from "@webpack"; -import { React, RestAPI, Tooltip } from "@webpack/common"; +import { Constants, React, RestAPI, Tooltip } from "@webpack/common"; import { RenameButton } from "./components/RenameButton"; import { Session, SessionInfo } from "./types"; @@ -168,7 +168,7 @@ export default definePlugin({ async checkNewSessions() { const data = await RestAPI.get({ - url: "/auth/sessions" + url: Constants.Endpoints.AUTH_SESSIONS }); for (const session of data.body.user_sessions) { diff --git a/src/plugins/emoteCloner/index.tsx b/src/plugins/emoteCloner/index.tsx index 8c3ded6a..b456c351 100644 --- a/src/plugins/emoteCloner/index.tsx +++ b/src/plugins/emoteCloner/index.tsx @@ -24,7 +24,7 @@ import { Margins } from "@utils/margins"; import { ModalContent, ModalHeader, ModalRoot, openModalLazy } from "@utils/modal"; import definePlugin from "@utils/types"; import { findByPropsLazy, findStoreLazy } from "@webpack"; -import { EmojiStore, FluxDispatcher, Forms, GuildStore, Menu, PermissionsBits, PermissionStore, React, RestAPI, Toasts, Tooltip, UserStore } from "@webpack/common"; +import { Constants, EmojiStore, FluxDispatcher, Forms, GuildStore, Menu, PermissionsBits, PermissionStore, React, RestAPI, Toasts, Tooltip, UserStore } from "@webpack/common"; import { Promisable } from "type-fest"; const StickersStore = findStoreLazy("StickersStore"); @@ -64,7 +64,7 @@ async function fetchSticker(id: string) { if (cached) return cached; const { body } = await RestAPI.get({ - url: `/stickers/${id}` + url: Constants.Endpoints.STICKER(id) }); FluxDispatcher.dispatch({ @@ -83,7 +83,7 @@ async function cloneSticker(guildId: string, sticker: Sticker) { data.append("file", await fetchBlob(getUrl(sticker))); const { body } = await RestAPI.post({ - url: `/guilds/${guildId}/stickers`, + url: Constants.Endpoints.GUILD_STICKER_PACKS(guildId), body: data, }); diff --git a/src/plugins/friendInvites/index.ts b/src/plugins/friendInvites/index.ts index e5ff447e..47e312c3 100644 --- a/src/plugins/friendInvites/index.ts +++ b/src/plugins/friendInvites/index.ts @@ -20,7 +20,7 @@ import { ApplicationCommandInputType, ApplicationCommandOptionType, findOption, import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; import { findByPropsLazy } from "@webpack"; -import { RestAPI, UserStore } from "@webpack/common"; +import { Constants, RestAPI, UserStore } from "@webpack/common"; const FriendInvites = findByPropsLazy("createFriendInvite"); const { uuid4 } = findByPropsLazy("uuid4"); @@ -58,7 +58,7 @@ export default definePlugin({ if (uses === 1) { const random = uuid4(); const { body: { invite_suggestions } } = await RestAPI.post({ - url: "/friend-finder/find-friends", + url: Constants.Endpoints.FRIEND_FINDER, body: { modified_contacts: { [random]: [1, "", ""] diff --git a/src/plugins/invisibleChat.desktop/index.tsx b/src/plugins/invisibleChat.desktop/index.tsx index fcb0af71..3dfe51e7 100644 --- a/src/plugins/invisibleChat.desktop/index.tsx +++ b/src/plugins/invisibleChat.desktop/index.tsx @@ -23,7 +23,7 @@ import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import { getStegCloak } from "@utils/dependencies"; import definePlugin, { OptionType } from "@utils/types"; -import { ChannelStore, FluxDispatcher, RestAPI, Tooltip } from "@webpack/common"; +import { ChannelStore, Constants, FluxDispatcher, RestAPI, Tooltip } from "@webpack/common"; import { Message } from "discord-types/general"; import { buildDecModal } from "./components/DecryptionModal"; @@ -153,7 +153,7 @@ export default definePlugin({ // Gets the Embed of a Link async getEmbed(url: URL): Promise { const { body } = await RestAPI.post({ - url: "/unfurler/embed-urls", + url: Constants.Endpoints.UNFURL_EMBED_URLS, body: { urls: [url] } diff --git a/src/plugins/messageLinkEmbeds/index.tsx b/src/plugins/messageLinkEmbeds/index.tsx index 2a5f8828..5c306362 100644 --- a/src/plugins/messageLinkEmbeds/index.tsx +++ b/src/plugins/messageLinkEmbeds/index.tsx @@ -27,6 +27,7 @@ import { findByPropsLazy, findComponentByCodeLazy } from "@webpack"; import { Button, ChannelStore, + Constants, FluxDispatcher, GuildStore, IconUtils, @@ -132,7 +133,7 @@ async function fetchMessage(channelID: string, messageID: string) { messageCache.set(messageID, { fetched: false }); const res = await RestAPI.get({ - url: `/channels/${channelID}/messages`, + url: Constants.Endpoints.MESSAGES(channelID), query: { limit: 1, around: messageID diff --git a/src/plugins/pauseInvitesForever/index.tsx b/src/plugins/pauseInvitesForever/index.tsx index e7abaa17..6a70be1a 100644 --- a/src/plugins/pauseInvitesForever/index.tsx +++ b/src/plugins/pauseInvitesForever/index.tsx @@ -20,7 +20,7 @@ import ErrorBoundary from "@components/ErrorBoundary"; import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; import { findByPropsLazy } from "@webpack"; -import { GuildStore, i18n, RestAPI } from "@webpack/common"; +import { Constants, GuildStore, i18n, RestAPI } from "@webpack/common"; const { InvitesDisabledExperiment } = findByPropsLazy("InvitesDisabledExperiment"); @@ -35,7 +35,7 @@ function disableInvites(guildId: string) { const guild = GuildStore.getGuild(guildId); const features = [...guild.features, "INVITES_DISABLED"]; RestAPI.patch({ - url: `/guilds/${guild.id}`, + url: Constants.Endpoints.GUILD(guildId), body: { features }, }); } diff --git a/src/plugins/unsuppressEmbeds/index.tsx b/src/plugins/unsuppressEmbeds/index.tsx index 0e87201c..16debf71 100644 --- a/src/plugins/unsuppressEmbeds/index.tsx +++ b/src/plugins/unsuppressEmbeds/index.tsx @@ -20,7 +20,7 @@ import { findGroupChildrenByChildId, NavContextMenuPatchCallback } from "@api/Co import { ImageInvisible, ImageVisible } from "@components/Icons"; import { Devs } from "@utils/constants"; import definePlugin from "@utils/types"; -import { Menu, PermissionsBits, PermissionStore, RestAPI, UserStore } from "@webpack/common"; +import { Constants, Menu, PermissionsBits, PermissionStore, RestAPI, UserStore } from "@webpack/common"; const EMBED_SUPPRESSED = 1 << 2; @@ -44,7 +44,7 @@ const messageContextMenuPatch: NavContextMenuPatchCallback = (children, { channe icon={isEmbedSuppressed ? ImageVisible : ImageInvisible} action={() => RestAPI.patch({ - url: `/channels/${channel.id}/messages/${messageId}`, + url: Constants.Endpoints.MESSAGE(channel.id, messageId), body: { flags: isEmbedSuppressed ? flags & ~EMBED_SUPPRESSED : flags | EMBED_SUPPRESSED } }) } diff --git a/src/plugins/validUser/index.tsx b/src/plugins/validUser/index.tsx index 64b734f5..4825cdaa 100644 --- a/src/plugins/validUser/index.tsx +++ b/src/plugins/validUser/index.tsx @@ -75,7 +75,7 @@ async function getUser(id: string) { if (userObj) return userObj; - const user: any = await RestAPI.get({ url: `/users/${id}` }).then(response => { + const user: any = await RestAPI.get({ url: Constants.Endpoints.USER(id) }).then(response => { FluxDispatcher.dispatch({ type: "USER_UPDATE", user: response.body, diff --git a/src/plugins/voiceMessages/index.tsx b/src/plugins/voiceMessages/index.tsx index 2f232f34..40e877df 100644 --- a/src/plugins/voiceMessages/index.tsx +++ b/src/plugins/voiceMessages/index.tsx @@ -28,7 +28,7 @@ import { useAwaiter } from "@utils/react"; import definePlugin from "@utils/types"; import { chooseFile } from "@utils/web"; import { findByPropsLazy, findStoreLazy } from "@webpack"; -import { Button, Card, FluxDispatcher, Forms, lodash, Menu, MessageActions, PermissionsBits, PermissionStore, RestAPI, SelectedChannelStore, showToast, SnowflakeUtils, Toasts, useEffect, useState } from "@webpack/common"; +import { Button, Card, Constants, FluxDispatcher, Forms, lodash, Menu, MessageActions, PermissionsBits, PermissionStore, RestAPI, SelectedChannelStore, showToast, SnowflakeUtils, Toasts, useEffect, useState } from "@webpack/common"; import { ComponentType } from "react"; import { VoiceRecorderDesktop } from "./DesktopRecorder"; @@ -98,7 +98,7 @@ function sendAudio(blob: Blob, meta: AudioMetadata) { upload.on("complete", () => { RestAPI.post({ - url: `/channels/${channelId}/messages`, + url: Constants.Endpoints.MESSAGES(channelId), body: { flags: 1 << 13, channel_id: channelId, diff --git a/src/plugins/whoReacted/index.tsx b/src/plugins/whoReacted/index.tsx index b3728c21..5721dc91 100644 --- a/src/plugins/whoReacted/index.tsx +++ b/src/plugins/whoReacted/index.tsx @@ -23,7 +23,7 @@ import { Queue } from "@utils/Queue"; import { useForceUpdater } from "@utils/react"; import definePlugin from "@utils/types"; import { findByPropsLazy, findComponentByCodeLazy } from "@webpack"; -import { ChannelStore, FluxDispatcher, React, RestAPI, Tooltip } from "@webpack/common"; +import { ChannelStore, Constants, FluxDispatcher, React, RestAPI, Tooltip } from "@webpack/common"; import { CustomEmoji } from "@webpack/types"; import { Message, ReactionEmoji, User } from "discord-types/general"; @@ -36,7 +36,7 @@ let reactions: Record; function fetchReactions(msg: Message, emoji: ReactionEmoji, type: number) { const key = emoji.name + (emoji.id ? `:${emoji.id}` : ""); return RestAPI.get({ - url: `/channels/${msg.channel_id}/messages/${msg.id}/reactions/${key}`, + url: Constants.Endpoints.REACTIONS(msg.channel_id, msg.id, key), query: { limit: 100, type diff --git a/src/utils/discord.tsx b/src/utils/discord.tsx index 74e1aefe..57202ba3 100644 --- a/src/utils/discord.tsx +++ b/src/utils/discord.tsx @@ -17,7 +17,7 @@ */ import { MessageObject } from "@api/MessageEvents"; -import { ChannelStore, ComponentDispatch, FluxDispatcher, GuildStore, InviteActions, MaskedLink, MessageActions, ModalImageClasses, PrivateChannelsStore, RestAPI, SelectedChannelStore, SelectedGuildStore, UserProfileActions, UserProfileStore, UserSettingsActionCreators, UserUtils } from "@webpack/common"; +import { ChannelStore, ComponentDispatch, Constants, FluxDispatcher, GuildStore, InviteActions, MaskedLink, MessageActions, ModalImageClasses, PrivateChannelsStore, RestAPI, SelectedChannelStore, SelectedGuildStore, UserProfileActions, UserProfileStore, UserSettingsActionCreators, UserUtils } from "@webpack/common"; import { Guild, Message, User } from "discord-types/general"; import { ImageModal, ModalRoot, ModalSize, openModal } from "./modal"; @@ -162,7 +162,7 @@ export async function fetchUserProfile(id: string, options?: FetchUserProfileOpt FluxDispatcher.dispatch({ type: "USER_PROFILE_FETCH_START", userId: id }); const { body } = await RestAPI.get({ - url: `/users/${id}/profile`, + url: Constants.Endpoints.USER_PROFILE(id), query: { with_mutual_guilds: false, with_mutual_friends_count: false,