Scroll to top

15/12/2023


2023/12/15#p1

0 comments: click to leave a comment

Today sees three years of /journal — my private solution here that began life as a WordPress plugin to create a custom post type.

I wrote the plugin back in 2018 but, for various reasons, journalling didn't resonate with me at the time.

December 2020 saw me try again, creating a simple interface that copied the way posting to the blog worked. I said at the time:

Maybe it never stuck because I didn't have all the pieces in place. Now they are and it can't get much simpler. Here's hoping that will carry me through.

It's fair to say that it has. Out of 1095 days I have posted 1076 entries — that's only 19 days when I haven't written anything in three years.

I moved the journal to '(b)log-In' in March 2021, just a couple of months after the launch, and have never looked back.

No comments yet
Leave a reply



You can also:

Click here to reply using email Reply by email Send a webmention Send a Webmention



2023/12/15#p2

0 comments: click to leave a comment

Now that I've got everything working properly (and shouldn't be hitting any rate limits) I wanted to detail how the Bluesky integration is all set up.

As I mentioned before, I'm using Clark Rasmussen's simple BlueskyAPI library but have now forked it – more on that later.

Posting

When posting to the blog (except for certain conditions) I will send it over to Bluesky – I'll strip tags and decode any HTML entities then check the post length. For anything over 275 characters (Bluesky has a limit of 300) the post gets truncated at the nearest full-stop and a link card generated:

$args = [
  'collection' => 'app.bsky.feed.post',
  'repo' => $bluesky->getAccountDid(),
  'record' => [
    'text' => $htmlcontent,
    'createdAt' => date('c'),
    '$type' => 'app.bsky.feed.post',
    'embed' => [
      '$type' => 'app.bsky.embed.external',
      'external' => [
        'uri' => $postlink,
        'title' => $title,
        'description' => 'Read the full post on the blog...',
      ],
    ],
  ],
];

If I decide to have a featured image (add the 'feat' class to it) this gets uploaded via the uploadBlob endpoint:

$body = file_get_contents($imageUrl);
$response = $bluesky->request('POST', 'com.atproto.repo.uploadBlob', [], $body, 'image/'.$imgExt);
$image = $response->blob;

$embed = [
  'embed' => [
    '$type' => 'app.bsky.embed.images',
    'images' => [
      [
        'alt' => $imageAlt,
        'image' => $image,
      ],
    ],
  ],
];

I can then add it as the thumbnail for the link card:

$args['record']['embed']['external']['thumb'] = $image;

Or, for a short post, have it as a normal image:

$args['record'] = array_merge($args['record'], $embed);

The post is submitted to the com.atproto.repo.createRecord endpoint with the relevant body ($args), I get the at:// address of the item on Bluesky and attach it to the blog post in the database.

Replies

When viewing the blog, if a post has an at:// address attached this will get passed to the app.bsky.feed.getPostThread endpoint with the required thread depth (currently 2). If the returned data includes replies I pull out the array and reverse it (Bluesky has them newest first) then recursively get the author, avatar and content of each to be displayed under the post comments.

Limits

I was having a problem hitting the rate limits on the com.atproto.server.createSession endpoint so needed to be able to reuse sessions. This is where forking the library comes in.

When creating a session I now save the API refresh token (refreshJwt) to a PHP session variable. Instead of going straight to 'createSession' I check if the session variable exists and pass it to com.atproto.server.refreshSession to get a new apiKey. I've read that atprotocol refresh tokens last for 2 months so I could technically save them to a more permanent location (the database) but this is easiest for now.

If no refresh token exists (or one has expired – unlikely) then a new session is created as normal. Much better.

Dev
 
No comments yet
Leave a reply



You can also:

Click here to reply using email Reply by email Send a webmention Send a Webmention



Close