Skip to content

Commit

Permalink
Pronouns update (resolves #22)
Browse files Browse the repository at this point in the history
  • Loading branch information
zaytri committed Feb 15, 2024
1 parent ee82038 commit dceda94
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 33 deletions.
21 changes: 17 additions & 4 deletions src/@types/pronouns.d.ts
Original file line number Diff line number Diff line change
@@ -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
}
}
24 changes: 19 additions & 5 deletions src/services/platforms/twitch/chat/useEmulate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand All @@ -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()),
Expand Down Expand Up @@ -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: {
Expand Down
55 changes: 31 additions & 24 deletions src/services/platforms/twitch/usePronouns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -27,7 +32,7 @@ export default function usePronouns() {
}

export function useAllPronouns() {
return useQuery<Map<string, string>>({
return useQuery<Pronouns.All | null>({
queryKey: ['twitch', 'pronouns', 'all'],
queryFn: async () => {
return getAllPronouns()
Expand All @@ -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<string | null> {
const data = await pronounsApi
.get<Pronouns.User[]>(`/users/${userName}`)
): Promise<[string, string | null] | null> {
const user = await pronounsApi
.get<Pronouns.User>(`/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<Map<string, string>> {
const pronounsMap = new Map<string, string>()

export async function getAllPronouns(): Promise<Pronouns.All | null> {
const allPronouns = await pronounsApi
.get<Pronouns.Data[]>('/pronouns')
.get<Pronouns.All>('/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}`
}

0 comments on commit dceda94

Please sign in to comment.