Add trends controller... and it kind of works!

This commit is contained in:
Alex Gleason 2023-07-25 17:07:09 -05:00
parent 11f21e3922
commit 1d67181e52
No known key found for this signature in database
GPG Key ID: 7211D1F99744FBB7
6 changed files with 51 additions and 13 deletions

View File

@ -2,7 +2,7 @@
"$schema": "https://deno.land/x/deno@v1.32.3/cli/schemas/config-file.v1.json", "$schema": "https://deno.land/x/deno@v1.32.3/cli/schemas/config-file.v1.json",
"lock": false, "lock": false,
"tasks": { "tasks": {
"dev": "deno run --allow-read --allow-env --allow-net --allow-ffi --unstable --watch src/server.ts", "dev": "deno run --allow-read --allow-write --allow-env --allow-net --allow-ffi --unstable --watch src/server.ts",
"test": "deno test -A --unstable src" "test": "deno test -A --unstable src"
}, },
"imports": { "imports": {

View File

@ -27,6 +27,7 @@ import {
statusController, statusController,
} from './controllers/api/statuses.ts'; } from './controllers/api/statuses.ts';
import { streamingController } from './controllers/api/streaming.ts'; import { streamingController } from './controllers/api/streaming.ts';
import { trendingTagsController } from './controllers/api/trends.ts';
import { indexController } from './controllers/site.ts'; import { indexController } from './controllers/site.ts';
import { hostMetaController } from './controllers/well-known/host-meta.ts'; import { hostMetaController } from './controllers/well-known/host-meta.ts';
import { nodeInfoController, nodeInfoSchemaController } from './controllers/well-known/nodeinfo.ts'; import { nodeInfoController, nodeInfoSchemaController } from './controllers/well-known/nodeinfo.ts';
@ -101,6 +102,9 @@ app.get('/api/v2/search', searchController);
app.get('/api/pleroma/frontend_configurations', frontendConfigController); app.get('/api/pleroma/frontend_configurations', frontendConfigController);
app.get('/api/v1/trends/tags', trendingTagsController);
app.get('/api/v1/trends', trendingTagsController);
// Not (yet) implemented. // Not (yet) implemented.
app.get('/api/v1/notifications', emptyArrayController); app.get('/api/v1/notifications', emptyArrayController);
app.get('/api/v1/bookmarks', emptyArrayController); app.get('/api/v1/bookmarks', emptyArrayController);

View File

@ -0,0 +1,23 @@
import { type AppController } from '@/app.ts';
import { Conf } from '@/config.ts';
import { trends } from '@/trends.ts';
import { Time } from '@/utils.ts';
const trendingTagsController: AppController = (c) => {
const yesterday = new Date(new Date().getTime() - Time.days(1));
const now = new Date();
const tags = trends.getTrendingTags(yesterday, now);
return c.json(tags.map(({ name, accounts }) => ({
name,
url: Conf.local(`/tags/${name}`),
history: [{
day: String(Math.floor(yesterday.getTime() / 1000)),
uses: String(accounts), // Not actually true - we don't collect this
accounts: String(accounts),
}],
})));
};
export { trendingTagsController };

View File

@ -1,17 +1,15 @@
import { Conf } from '@/config.ts'; import { Conf } from '@/config.ts';
import { relayInit, Sqlite } from '@/deps.ts'; import { relayInit } from '@/deps.ts';
import { TrendsDB } from '@/trends.ts'; import { trends } from '@/trends.ts';
import { nostrNow } from '@/utils.ts';
const db = new Sqlite('data/trends.sqlite3');
const trends = new TrendsDB(db);
const relay = relayInit(Conf.relay); const relay = relayInit(Conf.relay);
await relay.connect(); await relay.connect();
const sub = relay.sub([{ kinds: [1] }]); const sub = relay.sub([{ kinds: [1], since: nostrNow() }]);
sub.on('eose', sub.unsub);
sub.on('event', (event) => { sub.on('event', (event) => {
console.info('loopback event:', event.id);
const tags = event.tags const tags = event.tags
.filter((tag) => tag[0] === 't') .filter((tag) => tag[0] === 't')
.map((tag) => tag[1]); .map((tag) => tag[1]);

View File

@ -18,7 +18,13 @@ Deno.test('getTrendingTags', () => {
new Date('2999-01-01T00:00:00'), new Date('2999-01-01T00:00:00'),
); );
assertEquals(result, ['ditto', 'hello', 'yolo']); const expected = [
{ name: 'ditto', accounts: 3 },
{ name: 'hello', accounts: 2 },
{ name: 'yolo', accounts: 1 },
];
assertEquals(result, expected);
trends.cleanupTagUsages(new Date('2999-01-01T00:00:00')); trends.cleanupTagUsages(new Date('2999-01-01T00:00:00'));
}); });

View File

@ -18,7 +18,7 @@ class TrendsDB {
`); `);
} }
getTrendingTags(since: Date, until: Date): string[] { getTrendingTags(since: Date, until: Date) {
return this.#db.query<string[]>( return this.#db.query<string[]>(
` `
SELECT tag, COUNT(DISTINCT pubkey8) SELECT tag, COUNT(DISTINCT pubkey8)
@ -29,12 +29,15 @@ class TrendsDB {
DESC LIMIT 10; DESC LIMIT 10;
`, `,
[since, until], [since, until],
).map((row) => row[0]); ).map((row) => ({
name: row[0],
accounts: Number(row[1]),
}));
} }
addTagUsages(pubkey: string, hashtags: string[]): void { addTagUsages(pubkey: string, hashtags: string[]): void {
const pubkey8 = hexIdSchema.parse(pubkey).substring(0, 8); const pubkey8 = hexIdSchema.parse(pubkey).substring(0, 8);
const tags = hashtagSchema.array().parse(hashtags); const tags = hashtagSchema.array().min(1).parse(hashtags);
const now = new Date(); const now = new Date();
this.#db.query( this.#db.query(
@ -51,4 +54,8 @@ class TrendsDB {
} }
} }
export { TrendsDB }; const trends = new TrendsDB(
new Sqlite('data/trends.sqlite3'),
);
export { trends, TrendsDB };