commit e48b077f41e3d05bf8378bf7b8af1ccb859e048e
parent cc31a91c6686af971af7088b156f066cd30214f6
Author: William Casarin <jb55@jb55.com>
Date: Tue, 17 Feb 2026 10:50:12 -0800
fix: fetch reply author profiles via unknowns system
After ingesting reply notes from relays, collect their author
pubkeys as unknowns and fetch the profiles so reply cards display
proper names and avatars instead of "nostrich".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat:
3 files changed, 50 insertions(+), 2 deletions(-)
diff --git a/src/html.rs b/src/html.rs
@@ -1213,8 +1213,13 @@ fn build_note_stats_html(ndb: &Ndb, txn: &Transaction, note: &Note, is_root: boo
/// Build HTML for direct replies to a note, shown below the note content.
fn build_replies_html(app: &Notecrumbs, txn: &Transaction, note: &Note, base_url: &str) -> String {
- let filter = Filter::new().kinds([1]).event(note.id()).build();
- let mut results = match app.ndb.query(txn, &[filter], 50) {
+ use crate::render::DIRECT_REPLY_LIMIT;
+ let filter = Filter::new()
+ .kinds([1])
+ .event(note.id())
+ .limit(DIRECT_REPLY_LIMIT as u64)
+ .build();
+ let mut results = match app.ndb.query(txn, &[filter], DIRECT_REPLY_LIMIT) {
Ok(r) => r,
Err(_) => return String::new(),
};
diff --git a/src/main.rs b/src/main.rs
@@ -234,6 +234,19 @@ async fn serve(
{
tracing::warn!("failed to fetch note stats: {err}");
}
+
+ // Fetch profiles for reply authors (now that replies are ingested)
+ if let Some(reply_unknowns) = render::collect_reply_unknowns(&app.ndb, ¬e_rd.note_rd) {
+ tracing::debug!(
+ "fetching {} reply author profiles",
+ reply_unknowns.ids_len()
+ );
+ if let Err(err) =
+ render::fetch_unknowns(&app.relay_pool, &app.ndb, reply_unknowns).await
+ {
+ tracing::warn!("failed to fetch reply author profiles: {err}");
+ }
+ }
}
if let RenderData::Profile(profile_opt) = &render_data {
diff --git a/src/render.rs b/src/render.rs
@@ -31,6 +31,7 @@ use tracing::{debug, error, warn};
const PURPLE: Color32 = Color32::from_rgb(0xcc, 0x43, 0xc5);
pub const PROFILE_FEED_RECENT_LIMIT: usize = 12;
pub const PROFILE_FEED_LOOKBACK_DAYS: u64 = 30;
+pub const DIRECT_REPLY_LIMIT: i32 = 50;
pub enum NoteRenderData {
Missing([u8; 32]),
@@ -736,6 +737,35 @@ pub async fn fetch_unknowns(
}
/// Fetch kind:7 reactions for a note from relays and ingest into ndb.
+/// Collect unknown profiles from reply notes (already ingested into ndb).
+/// Call this after fetch_note_stats so reply authors can be resolved.
+pub fn collect_reply_unknowns(
+ ndb: &Ndb,
+ note_rd: &NoteRenderData,
+) -> Option<crate::unknowns::UnknownIds> {
+ let txn = Transaction::new(ndb).ok()?;
+ let note = note_rd.lookup(&txn, ndb).ok()?;
+
+ let filter = nostrdb::Filter::new()
+ .kinds([1])
+ .event(note.id())
+ .limit(DIRECT_REPLY_LIMIT as u64)
+ .build();
+ let results = ndb.query(&txn, &[filter], DIRECT_REPLY_LIMIT).ok()?;
+
+ let mut unknowns = crate::unknowns::UnknownIds::new();
+
+ for result in &results {
+ unknowns.add_profile_if_missing(ndb, &txn, result.note.pubkey());
+ }
+
+ if unknowns.is_empty() {
+ None
+ } else {
+ Some(unknowns)
+ }
+}
+
/// Fetch note stats (reactions, replies, reposts) from relays and ingest into ndb.
pub async fn fetch_note_stats(
relay_pool: &Arc<RelayPool>,