From 61bc57c77851770636be2531c33fa0903734f347 Mon Sep 17 00:00:00 2001 From: "P. Reis" Date: Mon, 30 Sep 2024 14:02:12 -0300 Subject: [PATCH] feat: support trendings by language --- src/trends.ts | 97 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 64 insertions(+), 33 deletions(-) diff --git a/src/trends.ts b/src/trends.ts index 23f7ea4..0583fd6 100644 --- a/src/trends.ts +++ b/src/trends.ts @@ -1,3 +1,4 @@ +import ISO6391, { LanguageCode } from 'iso-639-1'; import { NostrFilter } from '@nostrify/nostrify'; import { Stickynotes } from '@soapbox/stickynotes'; import { Kysely, sql } from 'kysely'; @@ -19,34 +20,49 @@ export async function getTrendingTagValues( tagNames: string[], /** Filter of eligible events. */ filter: NostrFilter, + /** Only return trending events of 'language' */ + language?: LanguageCode, ): Promise<{ value: string; authors: number; uses: number }[]> { - let query = kysely - .selectFrom([ - 'nostr_events', - sql<{ key: string; value: string }>`jsonb_each_text(nostr_events.tags_index)`.as('kv'), - sql<{ key: string; value: string }>`jsonb_array_elements_text(kv.value::jsonb)`.as('element'), - ]) - .select(({ fn }) => [ - fn('lower', ['element.value']).as('value'), - fn.agg('count', ['nostr_events.pubkey']).distinct().as('authors'), - fn.countAll().as('uses'), - ]) - .where('kv.key', '=', (eb) => eb.fn.any(eb.val(tagNames))) - .groupBy((eb) => eb.fn('lower', ['element.value'])) - .orderBy((eb) => eb.fn.agg('count', ['nostr_events.pubkey']).distinct(), 'desc'); + let query = kysely.with('trends', (db) => { + let query = db + .selectFrom([ + 'nostr_events', + sql<{ key: string; value: string }>`jsonb_each_text(nostr_events.tags_index)`.as('kv'), + sql<{ key: string; value: string }>`jsonb_array_elements_text(kv.value::jsonb)`.as('element'), + ]) + .select(({ fn }) => [ + fn('lower', ['element.value']).as('value'), + fn.agg('count', ['nostr_events.pubkey']).distinct().as('authors'), + fn.countAll().as('uses'), + ]) + .where('kv.key', '=', (eb) => eb.fn.any(eb.val(tagNames))) + .groupBy((eb) => eb.fn('lower', ['element.value'])) + .orderBy((eb) => eb.fn.agg('count', ['nostr_events.pubkey']).distinct(), 'desc'); - if (filter.kinds) { - query = query.where('nostr_events.kind', '=', ({ fn, val }) => fn.any(val(filter.kinds))); - } - if (filter.authors) { - query = query.where('nostr_events.pubkey', '=', ({ fn, val }) => fn.any(val(filter.authors))); - } - if (typeof filter.since === 'number') { - query = query.where('nostr_events.created_at', '>=', filter.since); - } - if (typeof filter.until === 'number') { - query = query.where('nostr_events.created_at', '<=', filter.until); + if (filter.kinds) { + query = query.where('nostr_events.kind', '=', ({ fn, val }) => fn.any(val(filter.kinds))); + } + if (filter.authors) { + query = query.where('nostr_events.pubkey', '=', ({ fn, val }) => fn.any(val(filter.authors))); + } + if (typeof filter.since === 'number') { + query = query.where('nostr_events.created_at', '>=', filter.since); + } + if (typeof filter.until === 'number') { + query = query.where('nostr_events.created_at', '<=', filter.until); + } + return query; + }) + .selectFrom(['trends']) + .innerJoin('nostr_events', 'trends.value', 'nostr_events.id') + .select(['value', 'authors', 'uses']); + + if (language) { + query = query.where('nostr_events.language', '=', language); } + + query = query.orderBy('authors desc'); + if (typeof filter.limit === 'number') { query = query.limit(filter.limit); } @@ -68,6 +84,7 @@ export async function updateTrendingTags( limit: number, extra = '', aliases?: string[], + language?: LanguageCode, ) { console.info(`Updating trending ${l}...`); const kysely = await Storages.kysely(); @@ -84,7 +101,7 @@ export async function updateTrendingTags( since: yesterday, until: now, limit, - }); + }, language); if (!trends.length) { console.info(`No trending ${l} found. Skipping.`); @@ -93,14 +110,19 @@ export async function updateTrendingTags( const signer = new AdminSigner(); + const tags = [ + ['L', 'pub.ditto.trends'], + ['l', l, 'pub.ditto.trends'], + ...trends.map(({ value, authors, uses }) => [tagName, value, extra, authors.toString(), uses.toString()]), + ]; + if (language) { + tags.push(['lang', language]); + } + const label = await signer.signEvent({ kind: 1985, content: '', - tags: [ - ['L', 'pub.ditto.trends'], - ['l', l, 'pub.ditto.trends'], - ...trends.map(({ value, authors, uses }) => [tagName, value, extra, authors.toString(), uses.toString()]), - ], + tags, created_at: Math.floor(Date.now() / 1000), }); @@ -122,8 +144,17 @@ export function updateTrendingZappedEvents(): Promise { } /** Update trending events. */ -export function updateTrendingEvents(): Promise { - return updateTrendingTags('#e', 'e', [1, 6, 7, 9735], 40, Conf.relay, ['q']); +export async function updateTrendingEvents(): Promise { + const languages = Conf.trendLanguages; + if (!languages) return updateTrendingTags('#e', 'e', [1, 6, 7, 9735], 40, Conf.relay, ['q']); + + const promise: Promise[] = []; + + for (const language of languages) { + promise.push(updateTrendingTags('#e', 'e', [1, 6, 7, 9735], 40, Conf.relay, ['q'], language)); + } + + await Promise.allSettled(promise); } /** Update trending hashtags. */