From 5811a1915146457189e818dee4834e2e4930b4ed Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 7 Feb 2025 19:05:37 -0600 Subject: [PATCH] Fix mentions in statuses? --- src/interfaces/DittoEvent.ts | 1 + src/storages/hydrate.ts | 38 +++++++++++++++++++++++++++++++++- src/views/mastodon/statuses.ts | 26 ++++++----------------- 3 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/interfaces/DittoEvent.ts b/src/interfaces/DittoEvent.ts index 75db7f73..bca65856 100644 --- a/src/interfaces/DittoEvent.ts +++ b/src/interfaces/DittoEvent.ts @@ -30,6 +30,7 @@ export interface DittoEvent extends NostrEvent { author_domain?: string; author_stats?: AuthorStats; event_stats?: EventStats; + mentions?: DittoEvent[]; user?: DittoEvent; repost?: DittoEvent; quote?: DittoEvent; diff --git a/src/storages/hydrate.ts b/src/storages/hydrate.ts index aff68f39..77b64fdc 100644 --- a/src/storages/hydrate.ts +++ b/src/storages/hydrate.ts @@ -30,6 +30,10 @@ async function hydrateEvents(opts: HydrateOpts): Promise { const cache = [...events]; + for (const event of await gatherMentions({ events: cache, store, signal })) { + cache.push(event); + } + for (const event of await gatherReposts({ events: cache, store, signal })) { cache.push(event); } @@ -146,6 +150,9 @@ export function assembleEvents( if (id) { event.quote = b.find((e) => matchFilter({ kinds: [1, 20], ids: [id] }, e)); } + + const pubkeys = event.tags.filter(([name]) => name === 'p').map(([_name, value]) => value); + event.mentions = b.filter((e) => matchFilter({ kinds: [0], authors: pubkeys }, e)); } if (event.kind === 6) { @@ -267,6 +274,35 @@ function gatherQuotes({ events, store, signal }: HydrateOpts): Promise { + const pubkeys = new Set(); + + for (const event of events) { + if (event.kind === 1) { + const pubkey = event.tags.find(([name]) => name === 'p')?.[1]; + if (pubkey) { + pubkeys.add(pubkey); + } + } + } + + const authors = await store.query( + [{ kinds: [0], authors: [...pubkeys], limit: pubkeys.size }], + { signal }, + ); + + for (const pubkey of pubkeys) { + const author = authors.find((e) => matchFilter({ kinds: [0], authors: [pubkey] }, e)); + if (!author) { + const fallback = fallbackAuthor(pubkey); + authors.push(fallback); + } + } + + return authors; +} + /** Collect authors from the events. */ async function gatherAuthors({ events, store, signal }: HydrateOpts): Promise { const pubkeys = new Set(); @@ -297,7 +333,7 @@ async function gatherAuthors({ events, store, signal }: HydrateOpts): Promise matchFilter({ kinds: [0], authors: [pubkey] }, e)); - if (author) { + if (!author) { const fallback = fallbackAuthor(pubkey); authors.push(fallback); } diff --git a/src/views/mastodon/statuses.ts b/src/views/mastodon/statuses.ts index 265cf442..0c0eb9f2 100644 --- a/src/views/mastodon/statuses.ts +++ b/src/views/mastodon/statuses.ts @@ -7,7 +7,7 @@ import { MastodonMention } from '@/entities/MastodonMention.ts'; import { MastodonStatus } from '@/entities/MastodonStatus.ts'; import { type DittoEvent } from '@/interfaces/DittoEvent.ts'; import { Storages } from '@/storages.ts'; -import { isNostrId, nostrDate } from '@/utils.ts'; +import { nostrDate } from '@/utils.ts'; import { getMediaLinks, parseNoteContent, stripimeta } from '@/utils/note.ts'; import { findReplyTag } from '@/utils/tags.ts'; import { unfurlCardCached } from '@/utils/unfurl.ts'; @@ -33,28 +33,14 @@ async function renderStatus(event: DittoEvent, opts: RenderStatusOpts): Promise< }); const account = event.author - ? await renderAccount({ ...event.author, author_stats: event.author_stats }) - : await accountFromPubkey(event.pubkey); + ? renderAccount({ ...event.author, author_stats: event.author_stats }) + : accountFromPubkey(event.pubkey); const replyId = findReplyTag(event.tags)?.[1]; - const mentionedPubkeys = [ - ...new Set( - event.tags - .filter(([name, value]) => name === 'p' && isNostrId(value)) - .map(([, value]) => value), - ), - ]; - const store = await Storages.db(); - const mentionedProfiles = await store.query( - [{ kinds: [0], authors: mentionedPubkeys, limit: mentionedPubkeys.length }], - ); - - const mentions = await Promise.all( - mentionedPubkeys.map((pubkey) => renderMention(pubkey, mentionedProfiles.find((event) => event.pubkey === pubkey))), - ); + const mentions = event.mentions?.map((event) => renderMention(event)) ?? []; const { html, links, firstUrl } = parseNoteContent(stripimeta(event.content, event.tags), mentions); @@ -170,8 +156,8 @@ async function renderReblog(event: DittoEvent, opts: RenderStatusOpts): Promise< }; } -async function renderMention(pubkey: string, event?: NostrEvent): Promise { - const account = event ? await renderAccount(event) : await accountFromPubkey(pubkey); +function renderMention(event: NostrEvent): MastodonMention { + const account = renderAccount(event); return { id: account.id, acct: account.acct,