ditto/src/controllers/api/trends.ts
2024-05-21 17:14:26 -05:00

58 lines
1.8 KiB
TypeScript

import { z } from 'zod';
import { type AppController } from '@/app.ts';
import { Conf } from '@/config.ts';
import { Time } from '@/utils.ts';
import { stripTime } from '@/utils/time.ts';
import { TrendsWorker } from '@/workers/trends.ts';
import { Context } from 'hono';
await TrendsWorker.open('data/trends.sqlite3');
const limitSchema = z.coerce.number().catch(10).transform((value) => Math.min(Math.max(value, 0), 20));
const trendingTagsController: AppController = async (c: Context) => {
const limit = limitSchema.parse(c.req.query('limit'));
if (limit < 1) return c.json([]);
const now = new Date();
const yesterday = new Date(now.getTime() - Time.days(1));
const lastWeek = new Date(now.getTime() - Time.days(7));
/** Most used hashtags within the past 24h. */
const tags = await TrendsWorker.getTrendingTags({
since: yesterday,
until: now,
limit,
});
return c.json(
await Promise.all(tags.map(async ({ tag, uses, accounts }) => ({
tag,
url: Conf.local(`/tags/${tag}`),
history: [
// Use the full 24h query for the current day. Then use `offset: 1` to adjust for this below.
// This result is more accurate than what Mastodon returns.
{
day: String(Math.floor(stripTime(now).getTime() / 1000)),
accounts: String(accounts),
uses: String(uses),
},
...(await TrendsWorker.getTagHistory({
tag,
since: lastWeek,
until: now,
limit: 6,
offset: 1,
})).map((history) => ({
// For some reason, Mastodon wants these to be strings... oh well.
day: String(Math.floor(history.day.getTime() / 1000)),
accounts: String(history.accounts),
uses: String(history.uses),
})),
],
}))),
);
};
export { trendingTagsController };