fix
Generate plugins.json / generate (push) Has been cancelled

This commit is contained in:
HackTips2
2026-06-02 19:43:48 +02:00
parent e754e70c28
commit 635c82093b
+106 -42
View File
@@ -1,4 +1,4 @@
/*
/*
* Vencord, a Discord client mod
* Copyright (c) 2026 Vendicated and contributors
* SPDX-License-Identifier: GPL-3.0-or-later
@@ -62,7 +62,7 @@ const NITRO_LEVELS = [
{ label: t("Or (3 mois)"), icon: "https://cdn.discordapp.com/badge-icons/2895086c18d5531d499862e41d1155a6.png" },
{ label: t("Platine (6 mois)"), icon: "https://cdn.discordapp.com/badge-icons/0334688279c8359120922938dcb1d6f8.png" },
{ label: t("Diamant (12 mois)"), icon: "https://cdn.discordapp.com/badge-icons/0d61871f72bb9a33a7ae568c1fb4f20a.png" },
{ label: t("Émeraude (24 mois)"), icon: "https://cdn.discordapp.com/badge-icons/11e2d339068b55d3a506cff34d3780f3.png" },
{ label: t("Émeraude (24 mois)"), icon: "https://cdn.discordapp.com/badge-icons/11e2d339068b55d3a506cff34d3780f3.png" },
{ label: t("Rubis (36 mois)"), icon: "https://cdn.discordapp.com/badge-icons/cd5e2cfd9d7f27a8cdcd3e8a8d5dc9f4.png" },
{ label: t("Opale (72 mois)"), icon: "https://cdn.discordapp.com/badge-icons/5b154df19c53dce2af92c9b61e6be5e2.png" },
];
@@ -286,25 +286,35 @@ function removeHideStyle() {
if (isEnabled) injectHideStyle();
let _avatarPatchApplied = false;
let _avatarPatchOrig: any = null;
function applyAvatarPatchEarly() {
if (_avatarPatchApplied || !isEnabled || !storedData.avatar) return;
if (_avatarPatchApplied) return;
try {
const IU = (window as any).Vencord?.Webpack?.findByProps?.("getUserAvatarURL");
// findByProps is more reliable than the imported IconUtils as it returns
// the actual live webpack module object — patching it affects all consumers.
const IU = (window as any).Vencord?.Webpack?.findByProps?.("getUserAvatarURL", "getDefaultAvatarURL")
?? (window as any).Vencord?.Webpack?.findByProps?.("getUserAvatarURL")
?? IconUtils;
if (!IU?.getUserAvatarURL) return;
const orig = IU.getUserAvatarURL;
_avatarPatchOrig = IU.getUserAvatarURL;
const orig = _avatarPatchOrig;
// The patch reads storedData/isEnabled at call-time, not at install-time
// so it works even if called before loadData() finishes.
IU.getUserAvatarURL = function (user: any, ...args: any[]) {
if (!user) return orig(user, ...args);
const uid = user.id ?? user.userId;
if (isEnabled && storedData.avatar && uid && isMe(uid)) {
if (!uid) return orig(user, ...args);
// Own user
if (isEnabled && storedData.avatar && isMe(uid)) {
return storedData.avatar;
}
// Other users via public cache
checkSeeAllSettingChange();
if (Settings.seeAllCustomProfile && uid) {
if (Settings.seeAllCustomProfile && !isMe(uid)) {
const cached = publicProfilesCache.get(uid);
if (cached?.fetched && cached.data?.avatar) {
return cached.data.avatar;
}
// Trigger a background fetch so next render is populated
fetchPublicProfileIfNeeded(uid);
}
return orig(user, ...args);
@@ -734,7 +744,7 @@ function BadgePicker({ selected, onChange, nitroType, onNitroType, boostLevel, o
icon="https://cdn.discordapp.com/badge-icons/7d9ae358c8c5e118768335dbe68b4fb8.png"
active={customIds.includes("quest")}
onClick={() => onCustomIds(customIds.includes("quest") ? customIds.filter(x => x !== "quest") : [...customIds, "quest"])} />
<BadgeBtn label={t("Orbs — Apprentice")}
<BadgeBtn label={t("Orbs Apprentice")}
icon="https://cdn.discordapp.com/badge-icons/83d8a1eb09a8d64e59233eec5d4d5c2d.png"
active={customIds.includes("orbs")}
onClick={() => onCustomIds(customIds.includes("orbs") ? customIds.filter(x => x !== "orbs") : [...customIds, "orbs"])} />
@@ -747,7 +757,7 @@ function BadgePicker({ selected, onChange, nitroType, onNitroType, boostLevel, o
<input className="cp-input" value={oldName} placeholder="OldUser#0000"
onChange={e => onOldName(e.target.value)} />
<div style={{ fontSize: 11, color: "var(--text-muted)", marginTop: 3 }}>
{t('Ex : Triggerr#5954 — will appear as "Old username: Triggerr#5954" when hovering the badge.')}
{t('Ex : Triggerr#5954 will appear as "Old username: Triggerr#5954" when hovering the badge.')}
</div>
</div>
)}
@@ -815,7 +825,7 @@ function CustomProfileModal({ rootProps }: { rootProps: any; }) {
} catch (e) { console.error("[CustomProfile] Failed to fetch accounts:", e); }
const me = UserStore.getCurrentUser();
// Pour debug: si on ne trouve qu'un compte, on simule quand même pour voir si la barre s'affiche
// Pour debug: si on ne trouve qu'un compte, on simule quand même pour voir si la barre s'affiche
return me ? [me, { ...me, id: "debug-placeholder", username: "Second Account?", globalName: "Simulation" }] : [];
}, []);
@@ -995,7 +1005,7 @@ function CustomProfileModal({ rootProps }: { rootProps: any; }) {
<Field label={t("Bio")} value={data.bio ?? ""} placeholder={t("My description...")} onChange={v => set("bio", v)} />
<Field label={t("Pronouns")} value={data.pronouns ?? ""} placeholder={t("he/him")} onChange={v => set("pronouns", v)} />
<div className="cp-field">
<SectionLabel>{t("Profile color (Nitro — gradient possible)")}</SectionLabel>
<SectionLabel>{t("Profile color (Nitro gradient possible)")}</SectionLabel>
<div className="cp-color-row" style={{ marginBottom: 6 }}>
<span style={{ fontSize: 11, color: "var(--text-muted)", marginRight: 6 }}>{t("Color 1")}</span>
<input type="color" value={accentHex || "#5865f2"} onChange={e => { const n = parseInt(e.target.value.replace("#", ""), 16); if (!isNaN(n)) set("accentColor", n); }} className="cp-color-swatch" />
@@ -1067,7 +1077,7 @@ function CustomProfileModal({ rootProps }: { rootProps: any; }) {
}
}}
>
Share your Custom Profile with everyone â click to manage in Nightcord Settings
Share your Custom Profile with everyone click to manage in Nightcord Settings
</a>
</div>
</ModalContent>
@@ -1159,7 +1169,7 @@ function fakeUser(user: any): any {
export default definePlugin({
name: "CustomProfile",
enabledByDefault: true,
description: t("Visually customize your Discord profile (username, PFP, banner, badges, bio...) — persistent, only visible to you."),
description: t("Visually customize your Discord profile (username, PFP, banner, badges, bio...) persistent, only visible to you."),
authors: [{ name: "Nightcord", id: 0n }],
dependencies: ["HeaderBarAPI", "ContextMenuAPI"],
@@ -1180,7 +1190,7 @@ export default definePlugin({
replace: "$self.patchBannerUrl(arguments[0])||$&"
}
},
// UserProfileStore patch removed — caused invisible channels for members
// UserProfileStore patch removed caused invisible channels for members
// with high permissions. getUserProfile is called by Discord to calculate
// VIEW_CHANNEL and other permissions. virtualMerge with premiumType:2 corrupted
// these calculations even with isMe() guard. DomObserver + fakeCurrentUser are enough.
@@ -1377,8 +1387,8 @@ export default definePlugin({
clone.premiumGuildSince = null;
}
} else if (isEnabled) {
// Si le plugin est activé mais Nitro simulation OFF
// On force la suppression des badges Nitro/Boost si demandés ou si simulés par erreur
// Si le plugin est activé mais Nitro simulation OFF
// On force la suppression des badges Nitro/Boost si demandés ou si simulés par erreur
if (storedData.nitro === false) {
clone.premiumType = 0;
clone.premiumSince = null;
@@ -1524,7 +1534,7 @@ export default definePlugin({
const badgesArr = Array.isArray(profile.badges) ? [...profile.badges] : [];
const customIds = data.customBadgeIds ?? [];
if (customIds.includes("quest")) badgesArr.push({ id: "quest", icon: "7d9ae358c8c5e118768335dbe68b4fb8", description: "Completed a quest" });
if (customIds.includes("orbs")) badgesArr.push({ id: "orbs", icon: "83d8a1eb09a8d64e59233eec5d4d5c2d", description: "Orbs — Apprentice" });
if (customIds.includes("orbs")) badgesArr.push({ id: "orbs", icon: "83d8a1eb09a8d64e59233eec5d4d5c2d", description: "Orbs Apprentice" });
if (customIds.includes("oldname")) {
const dText = data.oldName ? "Originally known as " + data.oldName : "Originally known as ...";
badgesArr.push({ id: "legacy_username", icon: "6de6d34650760ba5551a79732e98ed60", description: dText });
@@ -1592,11 +1602,11 @@ export default definePlugin({
merged.premiumGuildSince = null;
}
// On s'assure que les badges originaux sont écrasés dans le profil
// On s'assure que les badges originaux sont écrasés dans le profil
merged.publicFlags = (storedData.badgeFlags != null) ? storedData.badgeFlags : profile.publicFlags;
merged.badges = []; // Force Discord à recalculer la liste à partir de publicFlags et premiumType
merged.badges = []; // Force Discord à recalculer la liste à partir de publicFlags et premiumType
} else if (isEnabled && storedData.nitro === false) {
// Si Nitro simulation est OFF, on force la suppression des badges simulés
// Si Nitro simulation est OFF, on force la suppression des badges simulés
merged.premiumType = profile.premiumType ?? 0;
merged.premiumSince = profile.premiumSince ?? null;
merged.premiumGuildSince = profile.premiumGuildSince ?? null;
@@ -1759,6 +1769,28 @@ export default definePlugin({
}
} catch { }
// INTERCEPTION ON GuildMemberStore (for server member list nickname + avatar)
try {
const GMS = (Vencord as any).Webpack?.findByProps?.("getMember", "getMembers", "getMemberIds");
if (GMS && !GMS._cp_member_hook) {
const origGetMember = GMS.getMember.bind(GMS);
GMS.getMember = (guildId: string, userId: string) => {
const member = origGetMember(guildId, userId);
if (!member) return member;
// Only patch own user — never expose custom nick to other users' views
if (isEnabled && isMe(userId)) {
const patched = { ...member };
if (storedData.username) patched.nick = storedData.globalName || storedData.username;
return patched;
}
return member;
};
GMS._cp_member_hook = true;
}
} catch { }
// INTERCEPTION ON UserProfileStore (for native Nitro/Boost badges in popout/modal profile)
try {
const UPS = (Vencord as any).Webpack?.findByProps?.("getUserProfile", "getGuildMemberProfile");
@@ -1855,7 +1887,7 @@ export default definePlugin({
}
} catch { }
// Patch SnowflakeUtils.extractTimestamp pour faker la date de création
// Patch SnowflakeUtils.extractTimestamp pour faker la date de création
try {
if (SnowflakeUtils?.extractTimestamp && !this._origExtractTimestamp) {
this._origExtractTimestamp = SnowflakeUtils.extractTimestamp;
@@ -1879,7 +1911,13 @@ export default definePlugin({
loadData().then(() => {
updateCachedRealData();
applyAvatarPatchEarly();
// Retry avatar patch — may have failed at early boot if module wasn't ready yet
if (!_avatarPatchApplied) {
applyAvatarPatchEarly();
} else {
// Module already patched but storedData was empty at patch time — the patch
// reads storedData at call-time so no re-patch needed, just rerender.
}
if (isEnabled) {
forceAccountPanelRerender();
requestAnimationFrame(() => removeHideStyle());
@@ -1888,7 +1926,7 @@ export default definePlugin({
}
});
// Patch getAvatarDecorationURL pour injecter notre déco uniquement sur notre user
// Patch getAvatarDecorationURL pour injecter notre déco uniquement sur notre user
try {
const decoMod = (Vencord as any).Webpack?.findByProps?.("getAvatarDecorationURL");
if (decoMod?.getAvatarDecorationURL) {
@@ -1927,18 +1965,35 @@ export default definePlugin({
}
} catch { }
// Avatar patch is already applied by applyAvatarPatchEarly() above.
// We only apply this fallback if the early patch somehow missed.
if (IconUtils?.getUserAvatarURL && !_avatarPatchApplied) {
this._origGetUserAvatarURL = IconUtils.getUserAvatarURL;
const orig = this._origGetUserAvatarURL;
(IconUtils as any).getUserAvatarURL = (user: any, ...args: any[]) => {
if (isEnabled && storedData.avatar) {
const uid = user?.id ?? user?.userId;
if (uid && isMe(uid)) return storedData.avatar;
}
return orig(user, ...args);
};
_avatarPatchApplied = true;
applyAvatarPatchEarly();
}
// Hook GuildMemberStore.getMember — only patches nick for own user
try {
const GMS = (Vencord as any).Webpack?.findByProps?.("getMember", "getMembers", "getMemberIds");
if (GMS?.getMember && !GMS._cp_member_hook) {
const _origGetMember = GMS.getMember.bind(GMS);
GMS.getMember = (guildId: string, userId: string) => {
const member = _origGetMember(guildId, userId);
try {
const myId = UserStore.getCurrentUser()?.id;
// Only patch our own member entry
if (isEnabled && userId === myId && member) {
const customNick = storedData.globalName || storedData.username;
if (customNick) {
return { ...member, nick: customNick };
}
}
} catch { }
return member;
};
GMS._cp_member_hook = true;
GMS._cp_orig_getMember = _origGetMember;
}
} catch { }
},
userProfileBadges: [
@@ -2021,11 +2076,13 @@ export default definePlugin({
// Logic for other flags (Staff, Partner, HypeSquad, etc.)
for (const badge of BADGES) {
if (wantedFlags & badge.flag) {
// Match on CDN icon hash (reliable across all locales)
const iconParts = badge.icon.split("/");
const iconHash = iconParts[iconParts.length - 1].replace(".png", "");
if (icon.includes(iconHash)) return false;
// Fallback: match EN keywords from the CDN URL path
const badgeKeywords = badge.label.toLowerCase().split(" ");
if (badgeKeywords.some(k => k.length > 3 && desc.includes(k))) return false;
const iconParts = badge.icon.split("/");
const iconName = iconParts[iconParts.length - 1];
if (icon.includes(iconName)) return false;
}
}
@@ -2092,7 +2149,7 @@ export default definePlugin({
// 11. SERVER BOOST (Right after Early Supporter on image 2)
if (hasBoostFake) {
badgeList.push({ description: `Server Booster — ${BOOST_LABELS[bm]}`, iconSrc: BOOST_ICONS[bm], position: 0, props: { style, title: `Server Booster — ${BOOST_LABELS[bm]}` } });
badgeList.push({ description: `Server Booster ${BOOST_LABELS[bm]}`, iconSrc: BOOST_ICONS[bm], position: 0, props: { style, title: `Server Booster ${BOOST_LABELS[bm]}` } });
}
// 12. Active Developer
@@ -2106,14 +2163,14 @@ export default definePlugin({
badgeList.push({ description: oldNameText, iconSrc: OLD_NAME_BADGE_ICON, position: 0, props: { style, title: oldNameText } });
}
// 14. Completed Quest (Quêtes)
// 14. Completed Quest (Quêtes)
if (storedData.customBadgeIds?.includes("quest")) {
badgeList.push({ description: "Completed a quest", iconSrc: "https://cdn.discordapp.com/badge-icons/7d9ae358c8c5e118768335dbe68b4fb8.png", position: 0, props: { style } });
}
// 15. Orbs
if (storedData.customBadgeIds?.includes("orbs")) {
badgeList.push({ description: "Orbs — Apprentice", iconSrc: "https://cdn.discordapp.com/badge-icons/83d8a1eb09a8d64e59233eec5d4d5c2d.png", position: 0, props: { style } });
badgeList.push({ description: "Orbs Apprentice", iconSrc: "https://cdn.discordapp.com/badge-icons/83d8a1eb09a8d64e59233eec5d4d5c2d.png", position: 0, props: { style } });
}
badges.push(...badgeList);
@@ -2136,6 +2193,15 @@ export default definePlugin({
(IconUtils as any).getUserAvatarURL = this._origGetUserAvatarURL;
this._origGetUserAvatarURL = null;
}
// Clean up GuildMemberStore hook
try {
const GMS = (Vencord as any).Webpack?.findByProps?.("getMember", "getMembers", "getMemberIds");
if (GMS?._cp_member_hook) {
if (GMS._cp_orig_getMember) GMS.getMember = GMS._cp_orig_getMember;
delete GMS._cp_member_hook;
delete GMS._cp_orig_getMember;
}
} catch { }
// Nettoyer le patch avatarDecoration
try {
const myUser = UserStore.getCurrentUser() as any;
@@ -2150,5 +2216,3 @@ export default definePlugin({
return <Button onClick={() => openModal(props => <CustomProfileModal rootProps={props} />)}>Open Custom Profile</Button>;
},
});