Save trending hashtags as labels
This commit is contained in:
parent
3363688977
commit
c969738736
26
src/cron.ts
26
src/cron.ts
|
@ -5,6 +5,7 @@ import { getTrendingNotes } from '@/trends/trending-notes.ts';
|
||||||
import { Time } from '@/utils/time.ts';
|
import { Time } from '@/utils/time.ts';
|
||||||
import { AdminSigner } from '@/signers/AdminSigner.ts';
|
import { AdminSigner } from '@/signers/AdminSigner.ts';
|
||||||
import { handleEvent } from '@/pipeline.ts';
|
import { handleEvent } from '@/pipeline.ts';
|
||||||
|
import { getTrendingHashtags } from '@/trends/trending-hashtags.ts';
|
||||||
|
|
||||||
const console = new Stickynotes('ditto:trends');
|
const console = new Stickynotes('ditto:trends');
|
||||||
|
|
||||||
|
@ -32,7 +33,32 @@ async function updateTrendingNotesCache() {
|
||||||
console.info('Trending notes cache updated.');
|
console.info('Trending notes cache updated.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function updateTrendingHashtagsCache() {
|
||||||
|
console.info('Updating trending hashtags cache...');
|
||||||
|
const kysely = await DittoDB.getInstance();
|
||||||
|
const yesterday = Math.floor((Date.now() - Time.days(1)) / 1000);
|
||||||
|
const signal = AbortSignal.timeout(1000);
|
||||||
|
|
||||||
|
const hashtags = await getTrendingHashtags(kysely, { since: yesterday, limit: 20, threshold: 3 });
|
||||||
|
const signer = new AdminSigner();
|
||||||
|
|
||||||
|
const label = await signer.signEvent({
|
||||||
|
kind: 1985,
|
||||||
|
content: '',
|
||||||
|
tags: [
|
||||||
|
['L', 'pub.ditto.trends'],
|
||||||
|
['l', 'hashtags', 'pub.ditto.trends'],
|
||||||
|
...hashtags.map(({ tag }) => ['t', tag]),
|
||||||
|
],
|
||||||
|
created_at: Math.floor(Date.now() / 1000),
|
||||||
|
});
|
||||||
|
|
||||||
|
await handleEvent(label, signal);
|
||||||
|
console.info('Trending hashtags cache updated.');
|
||||||
|
}
|
||||||
|
|
||||||
/** Start cron jobs for the application. */
|
/** Start cron jobs for the application. */
|
||||||
export function cron() {
|
export function cron() {
|
||||||
Deno.cron('update trending notes cache', { minute: { every: 15 } }, updateTrendingNotesCache);
|
Deno.cron('update trending notes cache', { minute: { every: 15 } }, updateTrendingNotesCache);
|
||||||
|
Deno.cron('update trending hashtags cache', { dayOfMonth: { every: 1 } }, updateTrendingHashtagsCache);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { Kysely } from 'kysely';
|
||||||
|
|
||||||
|
import { DittoTables } from '@/db/DittoTables.ts';
|
||||||
|
|
||||||
|
interface GetTrendingHashtagsOpts {
|
||||||
|
/** Unix timestamp in _seconds_ for the starting point of this query. */
|
||||||
|
since: number;
|
||||||
|
/** Maximum number of trending hashtags to return. */
|
||||||
|
limit: number;
|
||||||
|
/** Minimum number of unique accounts that have used a hashtag to be considered trending. */
|
||||||
|
threshold: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the trending hashtags in the given time frame. */
|
||||||
|
export async function getTrendingHashtags(
|
||||||
|
/** Kysely instance to execute queries on. */
|
||||||
|
kysely: Kysely<DittoTables>,
|
||||||
|
/** Options for this query. */
|
||||||
|
opts: GetTrendingHashtagsOpts,
|
||||||
|
): Promise<{ tag: string; accounts: number; uses: number }[]> {
|
||||||
|
const { since, limit, threshold } = opts;
|
||||||
|
|
||||||
|
return await kysely
|
||||||
|
.selectFrom('nostr_tags')
|
||||||
|
.innerJoin('nostr_events', 'nostr_events.id', 'nostr_tags.event_id')
|
||||||
|
.select(({ fn }) => [
|
||||||
|
'nostr_tags.value as tag',
|
||||||
|
fn.agg<number>('count', ['nostr_events.pubkey']).distinct().as('accounts'),
|
||||||
|
fn.countAll<number>().as('uses'),
|
||||||
|
])
|
||||||
|
.where('nostr_tags.name', '=', 't')
|
||||||
|
.where('nostr_events.created_at', '>', since)
|
||||||
|
.groupBy('nostr_tags.value')
|
||||||
|
.having((c) => c(c.fn.agg('count', ['nostr_events.pubkey']).distinct(), '>=', threshold))
|
||||||
|
.orderBy((c) => c.fn.agg('count', ['nostr_events.pubkey']).distinct(), 'desc')
|
||||||
|
.limit(limit)
|
||||||
|
.execute();
|
||||||
|
}
|
Loading…
Reference in New Issue