Crunch the tag history in the controller

This commit is contained in:
Alex Gleason 2024-06-02 17:47:36 -05:00
parent b46bcc559e
commit 76c882d836
No known key found for this signature in database
GPG key ID: 7211D1F99744FBB7
2 changed files with 54 additions and 38 deletions

View file

@ -5,12 +5,8 @@ import { type AppController } from '@/app.ts';
import { Conf } from '@/config.ts'; import { Conf } from '@/config.ts';
import { hydrateEvents } from '@/storages/hydrate.ts'; import { hydrateEvents } from '@/storages/hydrate.ts';
import { Storages } from '@/storages.ts'; import { Storages } from '@/storages.ts';
import { Time } from '@/utils.ts'; import { generateDateRange, Time } from '@/utils/time.ts';
import { stripTime } from '@/utils/time.ts';
import { renderStatus } from '@/views/mastodon/statuses.ts'; import { renderStatus } from '@/views/mastodon/statuses.ts';
import { TrendsWorker } from '@/workers/trends.ts';
await TrendsWorker.open('data/trends.sqlite3');
let trendingHashtagsCache = getTrendingHashtags(); let trendingHashtagsCache = getTrendingHashtags();
@ -31,42 +27,62 @@ const trendingTagsController: AppController = async (c) => {
}; };
async function getTrendingHashtags() { async function getTrendingHashtags() {
const now = new Date(); const store = await Storages.db();
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 [label] = await store.query([{
const tags = await TrendsWorker.getTrendingTags({ kinds: [1985],
since: yesterday, '#L': ['pub.ditto.trends'],
until: now, '#l': ['#t'],
limit: 20, authors: [Conf.pubkey],
limit: 1,
}]);
if (!label) {
return [];
}
const tags = label.tags.filter(([name]) => name === 't');
const now = new Date();
const lastWeek = new Date(now.getTime() - Time.days(7));
const dates = generateDateRange(lastWeek, now);
return Promise.all(tags.map(async ([_, hashtag]) => {
const filters = dates.map((date) => ({
kinds: [1985],
'#L': ['pub.ditto.trends'],
'#l': ['#t'],
'#t': [hashtag],
authors: [Conf.pubkey],
since: Math.floor(date.getTime() / 1000),
until: Math.floor((date.getTime() + Time.days(1)) / 1000),
limit: 1,
}));
const labels = await store.query(filters);
const history = dates.map((date) => {
const label = labels.find((label) => {
const since = Math.floor(date.getTime() / 1000);
const until = Math.floor((date.getTime() + Time.days(1)) / 1000);
return label.created_at >= since && label.created_at < until;
}); });
return Promise.all(tags.map(async ({ tag, uses, accounts }) => ({ const [, , accounts, uses] = label?.tags.find(([name, value]) => name === 't' && value === hashtag) ?? [];
name: tag,
url: Conf.local(`/tags/${tag}`), return {
history: [ day: String(date.getTime() / 1000),
// Use the full 24h query for the current day. Then use `offset: 1` to adjust for this below. accounts: accounts || '0',
// This result is more accurate than what Mastodon returns. uses: uses || '0',
{ };
day: String(Math.floor(stripTime(now).getTime() / 1000)), });
accounts: String(accounts),
uses: String(uses), return {
}, name: hashtag,
...(await TrendsWorker.getTagHistory({ url: Conf.local(`/tags/${hashtag}`),
tag, history,
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),
})),
],
})));
} }
const trendingStatusesQuerySchema = z.object({ const trendingStatusesQuerySchema = z.object({

View file

@ -36,7 +36,7 @@ class EventsDB implements NStore {
'p': ({ event, count, value }) => (count < 15 || event.kind === 3) && isNostrId(value), 'p': ({ event, count, value }) => (count < 15 || event.kind === 3) && isNostrId(value),
'proxy': ({ count, value }) => count === 0 && isURL(value), 'proxy': ({ count, value }) => count === 0 && isURL(value),
'q': ({ event, count, value }) => count === 0 && event.kind === 1 && isNostrId(value), 'q': ({ event, count, value }) => count === 0 && event.kind === 1 && isNostrId(value),
't': ({ count, value }) => count < 5 && value.length < 50, 't': ({ event, count, value }) => (event.kind === 1985 ? count < 20 : count < 5) && value.length < 50,
'name': ({ event, count }) => event.kind === 30361 && count === 0, 'name': ({ event, count }) => event.kind === 30361 && count === 0,
'role': ({ event, count }) => event.kind === 30361 && count === 0, 'role': ({ event, count }) => event.kind === 30361 && count === 0,
}; };