UNPKG

rsshub

Version:
113 lines (97 loc) 4.19 kB
import cache from '@/utils/cache'; import got from '@/utils/got'; import { parseDate } from '@/utils/parse-date'; import { art } from '@/utils/render'; import path from 'node:path'; import { MisskeyNote, MisskeyUser } from './types'; const allowSiteList = ['misskey.io', 'madost.one', 'mk.nixnet.social']; const parseNotes = (data: MisskeyNote[], site: string, simplifyAuthor: boolean = false) => data.map((item: MisskeyNote) => { const isRenote = item.renote && Object.keys(item.renote).length > 0; const isReply = item.reply && Object.keys(item.reply).length > 0; const noteToUse: MisskeyNote = isRenote ? (item.renote as MisskeyNote) : item; const host = noteToUse.user.host ?? site; const author = simplifyAuthor ? String(noteToUse.user.name) : `${noteToUse.user.name} (${noteToUse.user.username}@${host})`; const description = art(path.join(__dirname, 'templates/note.art'), { text: noteToUse.text, files: noteToUse.files, reply: item.reply, site, }); let title = ''; if (isReply && item.reply) { const replyToHost = item.reply.user.host ?? site; const replyToAuthor = simplifyAuthor ? item.reply.user.name : `${item.reply.user.name} (${item.reply.user.username}@${replyToHost})`; title = `Reply to ${replyToAuthor}: "${noteToUse.text ?? ''}"`; } else if (isRenote) { title = `Renote: ${author}: "${noteToUse.text ?? ''}"`; } else { title = `${author}: "${noteToUse.text ?? ''}"`; } /** * For renotes from non-Misskey instances (e.g. Mastodon, Pleroma), * we can't use noteToUse.id to link to the original note since: * 1. The URL format differs from Misskey's /notes/{id} pattern * 2. Direct access to the original note may not be possible * Therefore, we link to the renote itself in such cases */ let noteId = noteToUse.id; if (isRenote) { const renoteHost = item.user.host ?? site; const noteHost = noteToUse.user.host ?? site; // Use renote's ID if the note is from a different host or not in allowSiteList if (renoteHost !== noteHost || !allowSiteList.includes(noteHost)) { noteId = item.id; } } const link = `https://${host}/notes/${noteId}`; const pubDate = parseDate(noteToUse.createdAt); return { title, description, pubDate, link, author, }; }); async function getUserTimelineByUsername(username, site, { withRenotes = false, mediaOnly = false }) { const searchUrl = `https://${site}/api/users/search-by-username-and-host`; const cacheUid = `misskey_username/${site}/${username}`; const userData = (await cache.tryGet(cacheUid, async () => { const searchResponse = await got({ method: 'post', url: searchUrl, json: { username, host: site, detail: true, limit: 1, }, }); const user = searchResponse.data.find((item) => item.username === username); if (!user) { throw new Error(`username ${username} not found`); } return user; })) as MisskeyUser; const accountId = userData.id; const avatarUrl = userData.avatarUrl; // https://misskey.io/api-doc#tag/users/operation/users___notes const usernotesUrl = `https://${site}/api/users/notes`; const usernotesResponse = await got({ method: 'post', url: usernotesUrl, json: { userId: accountId, withChannelNotes: true, withRenotes, withReplies: !mediaOnly, // Disable replies if mediaOnly is true withFiles: mediaOnly, limit: 10, offset: 0, }, }); const accountData = usernotesResponse.data; return { site, accountId, accountData, avatarUrl }; } export default { parseNotes, getUserTimelineByUsername, allowSiteList };