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;
+}