diff --git a/src/plugins/messageLatency/index.tsx b/src/plugins/messageLatency/index.tsx index 48b57863e..301e605fb 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} > diff --git a/src/plugins/pinDms/index.tsx b/src/plugins/pinDms/index.tsx index 010b5506c..60484561a 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)=>{/, @@ -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 }; diff --git a/src/plugins/showHiddenThings/README.md b/src/plugins/showHiddenThings/README.md index e969391e4..753e5c148 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 1858582a8..8de70aca9 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, diff --git a/src/plugins/validUser/index.tsx b/src/plugins/validUser/index.tsx index 7a21ac86b..64b734f53 100644 --- a/src/plugins/validUser/index.tsx +++ b/src/plugins/validUser/index.tsx @@ -18,28 +18,30 @@ 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"; 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; 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); @@ -202,6 +205,7 @@ export default definePlugin({ return ( 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; +}