Plugin
ValidUser
Fix mentions for unknown users showing up as '@unknown-user' (hover over a mention to fix it)
1
import ErrorBoundary from "@components/ErrorBoundary";2
import { Devs } from "@utils/constants";3
import { isNonNullish } from "@utils/guards";4
import { sleep } from "@utils/misc";5
import { Queue } from "@utils/Queue";6
import definePlugin from "@utils/types";7
import { ProfileBadge } from "@vencord/discord-types";8
import { Constants, FluxDispatcher, RestAPI, UserProfileStore, UserStore, useState } from "@webpack/common";9
import { type ComponentType, type ReactNode } from "react";10
11
// LYING to the type checker here12
const UserFlags = Constants.UserFlags as Record<string, number>;13
const badges: Record<string, ProfileBadge> = {14
active_developer: { id: "active_developer", description: "Active Developer", icon: "6bdc42827a38498929a4920da12695d9", link: "https:class="ts-cmt">//support-dev.discord.com/hc/en-us/articles/10113997751447" },15
bug_hunter_level_1: { id: "bug_hunter_level_1", description: "Discord Bug Hunter", icon: "2717692c7dca7289b35297368a940dd0", link: "https:class="ts-cmt">//support.discord.com/hc/en-us/articles/360046057772-Discord-Bugs" },16
bug_hunter_level_2: { id: "bug_hunter_level_2", description: "Discord Bug Hunter", icon: "848f79194d4be5ff5f81505cbd0ce1e6", link: "https:class="ts-cmt">//support.discord.com/hc/en-us/articles/360046057772-Discord-Bugs" },17
certified_moderator: { id: "certified_moderator", description: "Moderator Programs Alumni", icon: "fee1624003e2fee35cb398e125dc479b", link: "https:class="ts-cmt">//discord.com/safety" },18
discord_employee: { id: "staff", description: "Discord Staff", icon: "5e74e9b61934fc1f67c65515d1f7e60d", link: "https:class="ts-cmt">//discord.com/company" },19
get staff() { return this.discord_employee; },20
hypesquad: { id: "hypesquad", description: "HypeSquad Events", icon: "bf01d1073931f921909045f3a39fd264", link: "https:class="ts-cmt">//discord.com/hypesquad" },21
hypesquad_online_house_1: { id: "hypesquad_house_1", description: "HypeSquad Bravery", icon: "8a88d63823d8a71cd5e390baa45efa02", link: "https:class="ts-cmt">//discord.com/settings/hypesquad-online" },22
hypesquad_online_house_2: { id: "hypesquad_house_2", description: "HypeSquad Brilliance", icon: "011940fd013da3f7fb926e4a1cd2e618", link: "https:class="ts-cmt">//discord.com/settings/hypesquad-online" },23
hypesquad_online_house_3: { id: "hypesquad_house_3", description: "HypeSquad Balance", icon: "3aa41de486fa12454c3761e8e223442e", link: "https:class="ts-cmt">//discord.com/settings/hypesquad-online" },24
partner: { id: "partner", description: "Partnered Server Owner", icon: "3f9748e53446a137a052f3454e2de41e", link: "https:class="ts-cmt">//discord.com/partners" },25
premium: { id: "premium", description: "Subscriber", icon: "2ba85e8026a8614b640c2837bcdfe21b", link: "https:class="ts-cmt">//discord.com/settings/premium" },26
premium_early_supporter: { id: "early_supporter", description: "Early Supporter", icon: "7060786766c9c840eb3019e725d2b358", link: "https:class="ts-cmt">//discord.com/settings/premium" },27
verified_developer: { id: "verified_developer", description: "Early Verified Bot Developer", icon: "6df5892e0f35b051f8b61eace34f4967" },28
};29
30
const fetching = new Set<string>();31
const queue = new Queue(5);32
33
interface MentionProps {34
data: {35
userId?: string;36
channelId?: string;37
content: any;38
};39
parse: (content: any, props: MentionProps["props"]) => ReactNode;40
props: {41
key: string;42
formatInline: boolean;43
noStyleAndInteraction: boolean;44
};45
RoleMention: ComponentType<any>;46
UserMention: ComponentType<any>;47
}48
49
async function getUser(id: string) {50
let userObj = UserStore.getUser(id);51
if (userObj)52
return userObj;53
54
const user: any = await RestAPI.get({ url: Constants.Endpoints.USER(id) }).then(response => {55
FluxDispatcher.dispatch({56
type: "USER_UPDATE",57
user: response.body,58
});59
60
return response.body;61
});62
63
// Populate the profile64
await FluxDispatcher.dispatch(65
{66
type: "USER_PROFILE_FETCH_FAILURE",67
userId: id,68
}69
);70
71
userObj = UserStore.getUser(id);72
const fakeBadges: ProfileBadge[] = Object.entries(UserFlags)73
.filter(([_, flag]) => !isNaN(flag) && userObj.hasFlag(flag))74
.map(([key]) => badges[key.toLowerCase()])75
.filter(isNonNullish);76
if (user.premium_type || !user.bot && (user.banner || user.avatar?.startsWith?.("a_")))77
fakeBadges.push(badges.premium);78
79
// Fill in what we can deduce80
const profile = UserProfileStore.getUserProfile(id);81
if (profile) {82
profile.accentColor = user.accent_color;83
profile.badges = fakeBadges;84
profile.banner = user.banner;85
profile.premiumType = user.premium_type;86
}87
88
return userObj;89
}90
91
function MentionWrapper({ data, UserMention, RoleMention, parse, props }: MentionProps) {92
const [userId, setUserId] = useState(data.userId);93
94
// if userId is set it means the user is cached. Uncached users have userId set to undefined95
if (userId)96
return (97
<UserMention98
className="mention"99
userId={userId}100
channelId={data.channelId}101
inlinePreview={props.noStyleAndInteraction}102
key={props.key}103
/>104
);105
106
// Parses the raw text node array data.content into a ReactNode[]: ["<@userid>"]107
const children = parse(data.content, props);108
109
return (110
// Discord is deranged and renders unknown user mentions as role mentions111
<RoleMention112
{...data}113
inlinePreview={props.formatInline}114
>115
<span116
onMouseEnter={() => {117
const mention = children?.[0]?.props?.children;118
if (typeof mention !== "string") return;119
120
const id = mention.match(/<@!?(\d+)>/)?.[1];121
if (!id) return;122
123
if (fetching.has(id))124
return;125
126
if (UserStore.getUser(id))127
return setUserId(id);128
129
const fetch = () => {130
fetching.add(id);131
132
queue.unshift(() =>133
getUser(id)134
.then(() => {135
setUserId(id);136
fetching.delete(id);137
})138
.catch(e => {139
if (e?.status === 429) {140
queue.unshift(() => sleep(e?.body?.retry_after ?? 1000).then(fetch));141
fetching.delete(id);142
}143
})144
.finally(() => sleep(300))145
);146
};147
148
fetch();149
}}150
>151
{children}152
</span>153
</RoleMention>154
);155
}156
157
export default definePlugin({158
name: "ValidUser",159
description: "Fix mentions for unknown users showing up as 039;@unknown-user039; (hover over a mention to fix it)",160
tags: ["Chat", "Utility"],161
authors: [Devs.Ven, Devs.Dolfies],162
searchTerms: ["MentionCacheFix"],163
164
patches: [165
{166
find: 039;className:"mention"039;,167
replacement: {168
// mention = { react: function (data, parse, props) { if (data.userId == null) return RoleMention() else return UserMention()169
match: /react(?=\(\i,\i,\i\).{0,100}return null==.{0,70}\?\(0,\i\.jsx\)\((\i\.\i),.+?jsx\)\((\i\.\i),\{className:"mention")/,170
// react: (...args) => OurWrapper(RoleMention, UserMention, ...args), originalReact: theirFunc171
replace: "react:(...args)=>$self.renderMention($1,$2,...args),originalReact"172
}173
},174
{175
find: "unknownUserMentionPlaceholder:",176
replacement: {177
match: /unknownUserMentionPlaceholder:/,178
replace: "$&false&&"179
}180
}181
],182
183
renderMention(RoleMention, UserMention, data, parse, props) {184
return (185
<ErrorBoundary noop>186
<MentionWrapper187
key={"mention" + data.userId}188
RoleMention={RoleMention}189
UserMention={UserMention}190
data={data}191
parse={parse}192
props={props}193
/>194
</ErrorBoundary>195
);196
},197
});198