diff --git a/src/@types/pronouns.d.ts b/src/@types/pronouns.d.ts index ed02307..6cbe470 100644 --- a/src/@types/pronouns.d.ts +++ b/src/@types/pronouns.d.ts @@ -1,12 +1,25 @@ namespace Pronouns { type User = { - id: string // Twitch ID - login: string // Twitch username - pronoun_id: string // maps to name in Data + channel_id: string // Twitch ID + channel_login: string // Twitch username + pronoun_id: string // maps to id in All + alt_pronoun_id: string | null // maps to id in All, can be null } type Data = { name: string // pronouns ID - display: string // pronouns display (for example: 'She/Her') + subject: string // for "She/Her", this is "She" + object: string // for "She/Her", this is "Her" + /** + * if this is true, + * and the user has this as their pronoun_id, + * and has no alt_pronoun_id, + * then only display the subject (for example "Any" instead of "Any/Any") + */ + singular: boolean + } + + type All = { + [id: string]: Data // id = name } } diff --git a/src/services/platforms/twitch/chat/useEmulate.ts b/src/services/platforms/twitch/chat/useEmulate.ts index aa142e0..822f68a 100644 --- a/src/services/platforms/twitch/chat/useEmulate.ts +++ b/src/services/platforms/twitch/chat/useEmulate.ts @@ -4,7 +4,7 @@ import Random from '@/services/random' import useBadges from '../useBadges' import useChannelEmotes from '../useChannelEmotes' import useCheermotes from '../useCheermotes' -import { useAllPronouns } from '../usePronouns' +import { displayPronouns, useAllPronouns } from '../usePronouns' import useThirdPartyEmotes from '../useThirdPartyEmotes' import useUserColor from './transforms/useUserColor' @@ -21,7 +21,23 @@ export default function useEmulateTwitchMessage() { async function emulate() { if (!isPlatformReady('twitch')) return - const allPronouns = Array.from(pronounsMap!.values()) + const allPronouns = Object.values(pronounsMap || {}) + let pronouns = null + + // 50% chance of showing pronouns + if (Random.boolean() && allPronouns.length) { + const primary = Random.item(allPronouns) + + // 50% chance of having a secondary pronoun + const secondary = Random.boolean() ? Random.item(allPronouns) : null + + pronouns = displayPronouns( + primary, + // ensure that primary and secondary don't match + secondary && primary.name === secondary.name ? null : secondary, + ) + } + const emotes = [ ...channelEmotes!, ...Array.from(thirdPartyEmoteMap!.values()), @@ -53,9 +69,7 @@ export default function useEmulateTwitchMessage() { id: `test-user-${date.getTime()}`, userName: 'testuser', displayName: 'testUser', - pronouns: Random.boolean() // 50% chance of showing pronouns - ? null - : Random.item(allPronouns), + pronouns, badges: [], color: await transformUserColor('testuser'), roles: { diff --git a/src/services/platforms/twitch/usePronouns.ts b/src/services/platforms/twitch/usePronouns.ts index 4cd0d5a..1490461 100644 --- a/src/services/platforms/twitch/usePronouns.ts +++ b/src/services/platforms/twitch/usePronouns.ts @@ -12,10 +12,15 @@ export default function usePronouns() { return await queryClient.fetchQuery({ queryKey: ['twitch', 'pronouns', 'user', userName], queryFn: async () => { - const pronounsId = await getUserPronouns(userName) - if (!pronounsId) return null + const pronouns = await getUserPronouns(userName) + if (!pronouns) return null - return pronounsMap!.get(pronounsId) + const [primary, secondary] = pronouns + + return displayPronouns( + pronounsMap[primary], + secondary ? pronounsMap[secondary] : null, + ) }, staleTime: 5 * 60 * 1000, // stale after 5 minutes gcTime: 1 * 60 * 60 * 1000, // garbage collected after 1 hour @@ -27,7 +32,7 @@ export default function usePronouns() { } export function useAllPronouns() { - return useQuery>({ + return useQuery({ queryKey: ['twitch', 'pronouns', 'all'], queryFn: async () => { return getAllPronouns() @@ -37,38 +42,40 @@ export function useAllPronouns() { } const pronounsApi = axios.create({ - baseURL: 'https://pronouns.alejo.io/api', + baseURL: 'https://api.pronouns.alejo.io/v1', }) export async function getUserPronouns( userName: string, -): Promise { - const data = await pronounsApi - .get(`/users/${userName}`) +): Promise<[string, string | null] | null> { + const user = await pronounsApi + .get(`/users/${userName}`) .then(response => response.data) .catch(() => null) - if (!data) return null // if Alejo's server is down - - // pronouns API returns either - // an array that contains a single User - // or an empty array if that user hasn't set pronouns - const [user] = data - if (!user) return null // no pronouns set + if (!user) return null // user hasn't set pronouns or server is down - return user.pronoun_id + return [user.pronoun_id, user.alt_pronoun_id] } -export async function getAllPronouns(): Promise> { - const pronounsMap = new Map() - +export async function getAllPronouns(): Promise { const allPronouns = await pronounsApi - .get('/pronouns') + .get('/pronouns') .then(response => response.data) + .catch(() => null) // server is down - allPronouns.forEach(({ name, display }) => { - pronounsMap.set(name, display) - }) + return allPronouns +} + +export function displayPronouns( + primary: Pronouns.Data, + secondary: Pronouns.Data | null, +): string { + if (!secondary) { + return primary.singular + ? primary.subject + : `${primary.subject}/${primary.object}` + } - return pronounsMap + return `${primary.subject}/${secondary.object}` }