Skip to content

Commit 4ce58e1

Browse files
committed
Add Bluesky post parser (storage side)
Turn the Bluesky stub from grunt into a Post: escape the plain-text body, keep line breaks, append the external link-card (dev logs almost always link out to YouTube/Modrinth/the site), and add a View-on-Bluesky backlink. Register the 'bluesky' posts-queue processor. Mirrors the Strapi parser.
1 parent a21e17a commit 4ce58e1

3 files changed

Lines changed: 50 additions & 0 deletions

File tree

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,5 +72,6 @@ const processPost = function processPost ( job ) {
7272

7373
postsQueue.process( 'reddit', processPost );
7474
postsQueue.process( 'rss', processPost );
75+
postsQueue.process( 'bluesky', processPost );
7576
postsQueue.process( 'strapi', processPost );
7677
postsQueue.process( 'discourse', processPost );

indexers/bluesky.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
const {
2+
AllHtmlEntities,
3+
} = require( 'html-entities' );
4+
5+
const Post = require( '../modules/Post.js' );
6+
7+
const htmlEntities = new AllHtmlEntities();
8+
9+
const MILLISECONDS_PER_SECOND = 1000;
10+
11+
// Builds a Post from a Bluesky post stub produced by grunt's bluesky indexer.
12+
// The stub already carries everything (text/url/date/section + an optional
13+
// external link-card), so this parser is service-agnostic and never talks to
14+
// the AppView itself. A Bluesky post body is plain text (facets are byte-range
15+
// overlays we don't expand), so we escape it, keep line breaks, append the
16+
// external link-card when present, and always link back to the post.
17+
class Bluesky {
18+
async parsePost ( accountId, currentPost ) {
19+
const data = currentPost.data || {};
20+
const post = new Post();
21+
22+
const bodyHtml = htmlEntities.encode( data.body || '' ).replace( /\n/g, '<br>' );
23+
24+
// When the post embeds an external link-card (dev logs / announcements
25+
// almost always do), surface it as its own linked line so the card's
26+
// destination isn't lost — the plain text usually only carries a
27+
// truncated "modrinth.com/datapack/viv..." display string.
28+
let embedHtml = '';
29+
30+
if ( data.embedUrl ) {
31+
const label = htmlEntities.encode( data.embedTitle || data.embedUrl );
32+
33+
embedHtml = `<p><a href="${ data.embedUrl }">${ label }</a></p>`;
34+
}
35+
36+
post.topicTitle = data.title;
37+
post.topicUrl = data.url;
38+
post.url = data.url;
39+
post.text = `<p>${ bodyHtml }</p>${ embedHtml }<p><a href="${ data.url }">View on Bluesky</a></p>`;
40+
post.section = data.section;
41+
post.accountId = accountId;
42+
post.timestamp = Math.floor( new Date( data.publishDate ).getTime() / MILLISECONDS_PER_SECOND );
43+
44+
return post;
45+
}
46+
}
47+
48+
module.exports = Bluesky;

indexers/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
module.exports = {
2+
bluesky: require( './bluesky' ),
23
reddit: require( './reddit' ),
34
rss: require( './rss' ),
45
strapi: require( './strapi' ),

0 commit comments

Comments
 (0)