diff --git a/src/plugins/pronoundb/index.ts b/src/plugins/pronoundb/index.ts index 227e07d55..0b8fd5f77 100644 --- a/src/plugins/pronoundb/index.ts +++ b/src/plugins/pronoundb/index.ts @@ -52,7 +52,7 @@ export default definePlugin({ find: ".userTagNoNickname", replacement: { match: /=(\i)\.pronouns/, - replace: "=$self.useProfilePronouns($1.user.id)" + replace: "=$self.useProfilePronouns($1.user.id,$1.pronouns)" } }, // Patch the profile modal username header to use our pronoun hook instead of Discord's pronouns @@ -60,7 +60,7 @@ export default definePlugin({ find: ".USER_PROFILE_ACTIVITY", replacement: { match: /\).showPronouns/, - replace: ").showPronouns||true;const vcPronounce=$self.useProfilePronouns(arguments[0].user.id);if(arguments[0].displayProfile)arguments[0].displayProfile.pronouns=vcPronounce" + replace: ").showPronouns||true;const vcPronounce=$self.useProfilePronouns(arguments[0].user.id,arguments[0].displayProfile?.pronouns);if(arguments[0].displayProfile&&vcPronounce)arguments[0].displayProfile.pronouns=vcPronounce" } } ], diff --git a/src/plugins/pronoundb/pronoundbUtils.ts b/src/plugins/pronoundb/pronoundbUtils.ts index 6a1fb31c8..b6c447038 100644 --- a/src/plugins/pronoundb/pronoundbUtils.ts +++ b/src/plugins/pronoundb/pronoundbUtils.ts @@ -19,17 +19,26 @@ import { Settings } from "@api/Settings"; import { VENCORD_USER_AGENT } from "@utils/constants"; import { debounce } from "@utils/debounce"; +import { getCurrentChannel } from "@utils/discord"; import { useAwaiter } from "@utils/react"; +import { findStoreLazy } from "@webpack"; import { UserStore } from "@webpack/common"; import { settings } from "./settings"; import { PronounCode, PronounMapping, PronounsResponse } from "./types"; +const UserProfileStore = findStoreLazy("UserProfileStore"); + export const enum PronounsFormat { Lowercase = "LOWERCASE", Capitalized = "CAPITALIZED" } +export const enum PronounSource { + PreferPDB, + PreferDiscord +} + // A map of cached pronouns so the same request isn't sent twice const cache: Record = {}; // A map of ids and callbacks that should be triggered on fetch @@ -46,21 +55,29 @@ const bulkFetch = debounce(async () => { } }); -export function useFormattedPronouns(id: string): string | null { - const [result] = useAwaiter(() => fetchPronouns(id), { - fallbackValue: getCachedPronouns(id), +function getDiscordPronouns(id: string) { + return ( + UserProfileStore.getGuildMemberProfile(id, getCurrentChannel()?.guild_id)?.pronouns + || UserProfileStore.getUserProfile(id)?.pronouns + ); +} + +export function useFormattedPronouns(id: string, discordPronouns: string = getDiscordPronouns(id)): string | null { + const [result] = useAwaiter(() => fetchPronouns(id, discordPronouns), { + fallbackValue: getCachedPronouns(id, discordPronouns), onError: e => console.error("Fetching pronouns failed: ", e) }); - // If the result is present and not "unspecified", and there is a mapping for the code, then return the mappings - if (result && result !== "unspecified" && PronounMapping[result]) - return formatPronouns(result); + if (result && result !== "unspecified") + return Object.hasOwn(PronounMapping, result) + ? formatPronouns(result) // PronounDB + : result; // Discord return null; } -export function useProfilePronouns(id: string) { - const pronouns = useFormattedPronouns(id); +export function useProfilePronouns(id: string, discordPronouns: string) { + const pronouns = useFormattedPronouns(id, discordPronouns); if (!settings.store.showInProfile) return null; if (!settings.store.showSelf && id === UserStore.getCurrentUser().id) return null; @@ -70,22 +87,28 @@ export function useProfilePronouns(id: string) { // Gets the cached pronouns, if you're too impatient for a promise! -export function getCachedPronouns(id: string): PronounCode | null { - return cache[id] ?? null; +export function getCachedPronouns(id: string, discordPronouns: string): string | null { + if (settings.store.pronounSource === PronounSource.PreferDiscord && discordPronouns) + return discordPronouns; + + const cached = cache[id]; + if (cached && cached !== "unspecified") return cached; + + return discordPronouns || cached || null; } // Fetches the pronouns for one id, returning a promise that resolves if it was cached, or once the request is completed -export function fetchPronouns(id: string): Promise { +export function fetchPronouns(id: string, discordPronouns: string): Promise { return new Promise(res => { - // If cached, return the cached pronouns - if (id in cache) res(getCachedPronouns(id)!); + const cached = getCachedPronouns(id, discordPronouns); + if (cached) return res(cached); + // If there is already a request added, then just add this callback to it - else if (id in requestQueue) requestQueue[id].push(res); + if (id in requestQueue) return requestQueue[id].push(res); + // If not already added, then add it and call the debounced function to make sure the request gets executed - else { - requestQueue[id] = [res]; - bulkFetch(); - } + requestQueue[id] = [res]; + bulkFetch(); }); } @@ -116,7 +139,7 @@ async function bulkFetchPronouns(ids: string[]): Promise { } } -export function formatPronouns(pronouns: PronounCode): string { +export function formatPronouns(pronouns: string): string { const { pronounsFormat } = Settings.plugins.PronounDB as { pronounsFormat: PronounsFormat, enabled: boolean; }; // For capitalized pronouns, just return the mapping (it is by default capitalized) if (pronounsFormat === PronounsFormat.Capitalized) return PronounMapping[pronouns]; diff --git a/src/plugins/pronoundb/settings.ts b/src/plugins/pronoundb/settings.ts index 2bd82887c..5d227978c 100644 --- a/src/plugins/pronoundb/settings.ts +++ b/src/plugins/pronoundb/settings.ts @@ -19,7 +19,7 @@ import { definePluginSettings } from "@api/Settings"; import { OptionType } from "@utils/types"; -import { PronounsFormat } from "./pronoundbUtils"; +import { PronounsFormat, PronounSource } from "./pronoundbUtils"; export const settings = definePluginSettings({ pronounsFormat: { @@ -37,6 +37,21 @@ export const settings = definePluginSettings({ } ] }, + pronounSource: { + type: OptionType.SELECT, + description: "Where to source pronouns from", + options: [ + { + label: "Prefer PronounDB, fall back to Discord", + value: PronounSource.PreferPDB, + default: true + }, + { + label: "Prefer Discord, fall back to PronounDB (might lead to inconsistency between pronouns in chat and profile)", + value: PronounSource.PreferDiscord + } + ] + }, showSelf: { type: OptionType.BOOLEAN, description: "Enable or disable showing pronouns for the current user",