fedicrawl/application/src/Fediverse/Providers/Misskey/retrieveUsersPage.ts

129 wiersze
3.6 KiB
TypeScript
Czysty Zwykły widok Historia

2022-01-08 18:13:56 +00:00
import { assertSuccessJsonResponse } from '../../assertSuccessJsonResponse'
import { z } from 'zod'
2022-11-29 13:11:27 +00:00
import getTimeoutMilliseconds from '../../getTimeoutMilliseconds.js'
import { NoMoreFeedsError } from '../NoMoreFeedsError'
import { FeedProviderMethod } from '../FeedProviderMethod'
2022-09-18 11:32:25 +00:00
import { FeedData } from '../FeedData'
import { FieldData } from '../FieldData'
2022-01-08 18:13:56 +00:00
const limit = 100
const emojiSchema = z.object({
name: z.string(),
url: z.string()
})
const schema = z.array(
z.object({
id: z.string(),
name: z.string().nullable(),
username: z.string(),
2022-01-08 18:25:44 +00:00
avatarUrl: z.string().nullable(),
2022-01-08 18:13:56 +00:00
isBot: z.boolean(),
emojis: z.array(emojiSchema),
createdAt: z.string(),
2022-01-08 18:25:44 +00:00
updatedAt: z.string().nullable(),
2022-01-08 18:13:56 +00:00
isLocked: z.boolean(),
description: z.string().nullable(),
location: z.string().nullable(),
birthday: z.string().nullable(),
lang: z.string().nullable(),
fields: z.array(
z.object({
name: z.string(),
value: z.string()
})
),
followersCount: z.number(),
followingCount: z.number(),
notesCount: z.number()
})
)
type Emoji = z.infer<typeof emojiSchema>
const replaceEmojis = (text: string, emojis: Emoji[]): string => {
2022-09-18 11:32:25 +00:00
emojis.forEach((emoji) => {
2022-01-08 18:13:56 +00:00
text = text.replace(
RegExp(`:${emoji.name}:`, 'gi'),
2022-09-18 11:32:25 +00:00
`<img draggable="false" class="emoji" title="${emoji.name}" alt="${emoji.name}" src="${emoji.url}" />`
2022-01-08 18:13:56 +00:00
)
})
return text
}
2022-09-18 11:32:25 +00:00
const parseDescription = (description: string | null): string => {
2022-01-08 18:13:56 +00:00
if (typeof description !== 'string') {
return ''
}
2022-09-18 11:32:25 +00:00
return description
.split('\n\n')
.map((paragraph) => {
paragraph = paragraph.replace('\n', '</br>\n')
return `<p>${paragraph}</p>`
})
.join('\n')
2022-01-08 18:13:56 +00:00
}
2022-09-18 11:32:25 +00:00
export const retrieveUsersPage: FeedProviderMethod = async (
domain,
2022-11-22 15:37:11 +00:00
page,
robotsTxt
2022-09-18 11:32:25 +00:00
): Promise<FeedData[]> => {
2022-11-22 15:37:11 +00:00
const response = await robotsTxt.postIfAllowed(
2022-11-29 13:11:27 +00:00
new URL(`https://${domain}/api/users`),
2022-09-18 11:32:25 +00:00
{
state: 'all',
origin: 'local',
sort: '+createdAt',
limit,
offset: limit * page
},
{
2022-11-29 13:11:27 +00:00
timeout: getTimeoutMilliseconds(domain)
2022-09-18 11:32:25 +00:00
}
)
assertSuccessJsonResponse(response)
const responseData = schema.parse(response.data)
if (responseData.length === 0) {
throw new NoMoreFeedsError('user')
2022-01-08 18:13:56 +00:00
}
2022-09-18 11:32:25 +00:00
return responseData.map((item) => {
return {
name: item.username,
displayName: replaceEmojis(item.name ?? item.username, item.emojis),
description: replaceEmojis(
parseDescription(item.description ?? ''),
item.emojis
),
followersCount: item.followersCount,
followingCount: item.followingCount,
statusesCount: item.notesCount,
bot: item.isBot,
url: `https://${domain}/@${item.username}`,
avatar: item.avatarUrl ?? undefined,
locked: item.isLocked,
lastStatusAt:
item.updatedAt !== null ? new Date(item.updatedAt) : undefined,
createdAt: new Date(item.createdAt),
fields: [
...item.fields.map((field) => {
return {
name: replaceEmojis(field.name, item.emojis),
value: replaceEmojis(field.value, item.emojis),
verifiedAt: undefined
}
}),
...([
{ name: 'Location', value: item.location, verifiedAt: undefined },
{ name: 'Birthday', value: item.birthday, verifiedAt: undefined },
{ name: 'Language', value: item.lang, verifiedAt: undefined }
].filter((field) => field.value !== null) as FieldData[])
],
type: 'account',
2022-11-22 16:01:25 +00:00
parentFeed: undefined,
indexable: true
}
2022-09-18 11:32:25 +00:00
})
2022-01-08 18:13:56 +00:00
}