feat(route): implement user timeline endpoint for misskey (#16393)

This commit is contained in:
S.Y. Lee
2024-08-09 23:49:21 +08:00
committed by GitHub
parent 3274fe77be
commit 815f7bdba2
2 changed files with 83 additions and 1 deletions
+42
View File
@@ -0,0 +1,42 @@
import { Route } from '@/types';
import utils from './utils';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/users/notes/:username',
categories: ['social-media'],
example: '/misskey/users/notes/support@misskey.io',
parameters: { username: 'misskey username format, like support@misskey.io' },
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
name: 'User timeline',
maintainers: ['siygle'],
handler,
};
async function handler(ctx) {
const username = ctx.req.param('username');
const [, pureUsername, site] = username.match(/@?(\w+)@(\w+\.\w+)/) || [];
if (!pureUsername || !site) {
throw new InvalidParameterError('Provide a valid Misskey username');
}
if (!config.feature.allow_user_supply_unsafe_domain && !utils.allowSiteList.includes(site)) {
throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}
const { accountData } = await utils.getUserTimelineByUsername(pureUsername, site);
return {
title: `User timeline for ${username} on ${site}`,
link: `https://${site}/@${pureUsername}`,
item: utils.parseNotes(accountData, site),
};
}
+41 -1
View File
@@ -4,6 +4,8 @@ const __dirname = getCurrentPath(import.meta.url);
import { art } from '@/utils/render';
import { parseDate } from '@/utils/parse-date';
import path from 'node:path';
import cache from '@/utils/cache';
import got from '@/utils/got';
const allowSiteList = ['misskey.io', 'madost.one', 'mk.nixnet.social'];
@@ -28,4 +30,42 @@ const parseNotes = (data, site) =>
};
});
export default { parseNotes, allowSiteList };
async function getUserTimelineByUsername(username, site) {
const searchUrl = `https://${site}/api/users/search-by-username-and-host`;
const cacheUid = `misskey_username/${site}/${username}`;
const accountId = await cache.tryGet(cacheUid, async () => {
const searchResponse = await got({
method: 'post',
url: searchUrl,
json: {
username,
host: site,
detail: true,
limit: 1,
},
});
const userData = searchResponse.data.find((item) => item.username === username);
if (userData.length === 0) {
throw new Error(`username ${username} not found`);
}
return userData.id;
});
const usernotesUrl = `https://${site}/api/users/notes`;
const usernotesResponse = await got({
method: 'post',
url: usernotesUrl,
json: {
userId: accountId,
withChannelNotes: true,
limit: 10,
offset: 0,
},
});
const accountData = usernotesResponse.data;
return { site, accountId, accountData };
}
export default { parseNotes, getUserTimelineByUsername, allowSiteList };