Changeset 5a93ac0 in Klonkt
- Timestamp:
- 06/24/2026 11:16:28 AM (3 months ago)
- Branches:
- main
- Children:
- eb852c5
- Parents:
- 065452a
- Location:
- src
- Files:
-
- 3 edited
-
routes/activitypub.js (modified) (1 diff)
-
routes/posts.js (modified) (1 diff)
-
services/ActivityPubService.js (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/routes/activitypub.js
r065452a r5a93ac0 54 54 if (!site) return res.status(404).end(); 55 55 const posts = db.prepare( 56 `SELECT id, slug, title, content, published_at, created_at56 `SELECT id, slug, title, content, cover_image_url, published_at, created_at 57 57 FROM posts WHERE site_id = ? AND status = 'published' AND (fan_only IS NULL OR fan_only = 0) 58 58 ORDER BY COALESCE(published_at, created_at) DESC LIMIT 20` -
src/routes/posts.js
r065452a r5a93ac0 236 236 ActivityPubService.deliverCreate(site, { 237 237 id: postId, slug: finalSlug, title: title || finalSlug, 238 content: cleanContent, published_at: publishedAt, created_at: now, 238 content: cleanContent, cover_image_url: cover_image_url || null, 239 published_at: publishedAt, created_at: now, 239 240 }).catch(() => { /* best-effort */ }); 240 241 } -
src/services/ActivityPubService.js
r065452a r5a93ac0 106 106 const escTitle = String(post.title || '').replace(/[<>&]/g, (c) => ({ '<': '<', '>': '>', '&': '&' }[c])); 107 107 const titleHtml = post.title ? `<p><strong>${escTitle}</strong></p>` : ''; 108 const html = titleHtml + (post.content || ''); 109 return { 108 109 // Images travel as AP `attachment` (Mastodon strips <img> from content). Collect 110 // the cover + any inline <img>, make absolute, then strip <img> from the content 111 // to avoid duplicate rendering on clients that DO keep them. 112 const abs = (u) => !u ? null : (/^https?:/i.test(u) ? u : `${base}${u.startsWith('/') ? '' : '/'}${u}`); 113 const mediaType = (u) => { 114 const e = ((u || '').split('?')[0].match(/\.(\w+)$/) || [])[1]; 115 return ({ jpg: 'image/jpeg', jpeg: 'image/jpeg', png: 'image/png', gif: 'image/gif', webp: 'image/webp', avif: 'image/avif' })[(e || '').toLowerCase()] || 'image/jpeg'; 116 }; 117 const urls = []; 118 if (post.cover_image_url) urls.push(abs(post.cover_image_url)); 119 let body = post.content || ''; 120 for (const m of body.matchAll(/<img\b[^>]*\bsrc="([^"]+)"[^>]*>/gi)) urls.push(abs(m[1])); 121 body = body.replace(/<img\b[^>]*>/gi, ''); 122 const seen = new Set(); 123 const attachment = urls.filter(Boolean) 124 .filter((u) => { if (seen.has(u)) return false; seen.add(u); return true; }) 125 .map((u) => ({ type: 'Document', mediaType: mediaType(u), url: u })); 126 127 const note = { 110 128 id, 111 129 type: 'Note', 112 130 attributedTo: aId, 113 content: html,131 content: titleHtml + body, 114 132 url: human, 115 133 published: new Date(post.published_at || post.created_at || Date.now()).toISOString(), … … 118 136 tag: Array.isArray(post.tags) ? post.tags.map((t) => ({ type: 'Hashtag', name: '#' + String(t).replace(/\s+/g, '') })) : [], 119 137 }; 138 if (attachment.length) note.attachment = attachment; 139 return note; 120 140 } 121 141
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)