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 store = await Storages.db();
const [label] = await store.query([{
kinds: [1985],
'#L': ['pub.ditto.trends'],
'#l': ['#t'],
authors: [Conf.pubkey],
limit: 1,
}]);
if (!label) {
return [];
}
const tags = label.tags.filter(([name]) => name === 't');
const now = new Date(); const now = new Date();
const yesterday = new Date(now.getTime() - Time.days(1));
const lastWeek = new Date(now.getTime() - Time.days(7)); const lastWeek = new Date(now.getTime() - Time.days(7));
const dates = generateDateRange(lastWeek, now);
/** Most used hashtags within the past 24h. */ return Promise.all(tags.map(async ([_, hashtag]) => {
const tags = await TrendsWorker.getTrendingTags({ const filters = dates.map((date) => ({
since: yesterday, kinds: [1985],
until: now, '#L': ['pub.ditto.trends'],
limit: 20, '#l': ['#t'],
}); '#t': [hashtag],
authors: [Conf.pubkey],
since: Math.floor(date.getTime() / 1000),
until: Math.floor((date.getTime() + Time.days(1)) / 1000),
limit: 1,
}));
return Promise.all(tags.map(async ({ tag, uses, accounts }) => ({ const labels = await store.query(filters);
name: tag,
url: Conf.local(`/tags/${tag}`), const history = dates.map((date) => {
history: [ const label = labels.find((label) => {
// Use the full 24h query for the current day. Then use `offset: 1` to adjust for this below. const since = Math.floor(date.getTime() / 1000);
// This result is more accurate than what Mastodon returns. const until = Math.floor((date.getTime() + Time.days(1)) / 1000);
{ return label.created_at >= since && label.created_at < until;
day: String(Math.floor(stripTime(now).getTime() / 1000)), });
accounts: String(accounts),
uses: String(uses), const [, , accounts, uses] = label?.tags.find(([name, value]) => name === 't' && value === hashtag) ?? [];
},
...(await TrendsWorker.getTagHistory({ return {
tag, day: String(date.getTime() / 1000),
since: lastWeek, accounts: accounts || '0',
until: now, uses: uses || '0',
limit: 6, };
offset: 1, });
})).map((history) => ({
// For some reason, Mastodon wants these to be strings... oh well. return {
day: String(Math.floor(history.day.getTime() / 1000)), name: hashtag,
accounts: String(history.accounts), url: Conf.local(`/tags/${hashtag}`),
uses: String(history.uses), history,
})), };
], }));
})));
} }
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,
}; };