Index: src/services/ActivityPubService.js
===================================================================
--- src/services/ActivityPubService.js	(revision 9e4e4ff6bb278ba6345cdd8e21bb9c6fd0d8f0c6)
+++ src/services/ActivityPubService.js	(revision c6bd87ed4f341b97961f1dc553c82f4855ad969d)
@@ -965,4 +965,18 @@
 }
 
+// attributedTo may be a string, an object {id}, or an ARRAY — e.g. a PeerTube Video is
+// attributed to [Person (account), Group (channel)]. Pick a usable actor URI (prefer Person).
+function actorUriOf(att) {
+  if (!att) return null;
+  if (typeof att === 'string') return att;
+  if (Array.isArray(att)) {
+    const person = att.find((a) => a && typeof a === 'object' && a.type === 'Person' && a.id);
+    if (person) return person.id;
+    for (const a of att) { if (typeof a === 'string') return a; if (a && a.id) return a.id; }
+    return null;
+  }
+  return att.id || null;
+}
+
 // Resolve a remote post URL (any fediverse/Klonkt post) into a reply target.
 // Returns a parent-shaped object usable by deliverReply(), or null.
@@ -972,5 +986,5 @@
   if (!note || !note.id) return null;
   const att = note.attributedTo;
-  const actorUri = typeof att === 'string' ? att : (att && att.id);
+  const actorUri = actorUriOf(att);
   if (!actorUri) return null;
   const actor = await fetchActor(actorUri).catch(() => null);
@@ -990,5 +1004,5 @@
     const pn = await fetchActor(url).catch(() => null);
     if (!pn) break;
-    const pa = typeof pn.attributedTo === 'string' ? pn.attributedTo : (pn.attributedTo && pn.attributedTo.id);
+    const pa = actorUriOf(pn.attributedTo);
     if (pa && pa !== actorUri) {
       const paDoc = await fetchActor(pa).catch(() => null);
@@ -998,5 +1012,8 @@
     cursor = pn.inReplyTo; // climb to the next ancestor
   }
-  const rawHtml = String(note.content || '').replace(/\[\[(track|album|playlist):[^\]]+\]\]/gi, '');
+  // For non-Note objects (PeerTube Video, Article, …) the meaningful label is `name` (the
+  // title); prepend it so the reply page shows what you're replying to (sanitize cleans it).
+  let rawHtml = String(note.content || '').replace(/\[\[(track|album|playlist):[^\]]+\]\]/gi, '');
+  if (note.name && note.type && note.type !== 'Note') rawHtml = `<p><strong>${note.name}</strong></p>` + rawHtml;
   const images = (Array.isArray(note.attachment) ? note.attachment : [])
     .filter((a) => a && a.url && (!a.mediaType || /^image\//i.test(a.mediaType)))
