Yee Chie Tu

Mastodon Reactions on Bearblog

Last updated: 1 month, 2 weeks ago. Modified the snippet.

Recently, I transferred my blog to Bearblog. Which was shortly after I experimented with Webmentions for the first time on my previous website. It was a pain to set it up…

I came across some talk about privacy issues on Mastodon related to some bridge, which kind of relates to Webmentions too. Without going into the specifics about Webmentions and recent privacy debates on the Fediverse, I recommend reading the article “Webmentions Redux” by Robb Knight.

After some reading and understanding on privacy concerns, I've come to agree with the points raised.

Have I mentioned that Bearblog doesn't support Webmentions? The HTML markup lacks the necessary attributes (microformats 2) for it.

I liked Robb Knight's implementation, so I aimed for something similar on my Bearblog while prioritizing people's privacy online.

Here's what I've done to implement Mastodon reactions on my Bearblog.

The script will check whether the page is of a post type. If it is, it will retrieve the numeric value from the body HTML class attribute, which will represent the Mastodon post ID. Once all conditions are met, it will fetch the results from the Mastodon API and output them as an HTML code snippet within the post, before the tags paragraph.

// Mastodon Reacts: Privacy friendly
const mastodonInstanceUrl = "https://mastodon.social";
const mastodonUsername = "yeechie";
const processMastodonReacts = async (statusId, bodyElement, tagsElement) => {
  try {
    const response = await fetch(`${mastodonInstanceUrl}/api/v1/statuses/${statusId}`, {
      headers: { "Content-Type": "application/json" },
    });
    if (!response.ok) throw new Error(`Failed to fetch Mastodon status: ${response.statusText}`);
    const { favourites_count = 0, reblogs_count = 0, replies_count = 0 } = await response.json();
    const html = `
      <div class="mastodon-reacts">
        <span class="mastodon-postlink">
        🗨️ <a href="${mastodonInstanceUrl}/@${mastodonUsername}/${statusId}" target="_blank">Reply on Mastodon</a>
        </span>
        <dl class="mastodon-status">
          <dt class="likes">❤️ Likes: </dt><dd>${favourites_count}</dd>
          <dt class="boosts"> 🔄 Reposts: </dt><dd>${reblogs_count}</dd>
          <dt class="replies"> 💬 Replies: </dt><dd>${replies_count}</dd>
        </dl>
      </div>`;
    const sanitizedHtml = DOMPurify.sanitize(html);
    tagsElement.insertAdjacentHTML("beforebegin", sanitizedHtml);
  } catch (error) {
    console.error("Error fetching Mastodon status:", error.message);
  }
};
document.addEventListener("DOMContentLoaded", () => {
  const body = document.querySelector("body.post");
  if (!body) return;
  const statusIdMatch = body.className.match(/\d+/);
  if (!statusIdMatch) return;
  const mastodonStatusId = statusIdMatch[0];
  const tagsElement = document.querySelector("p.tags");
  const script = document.createElement("script");
  script.src = "https://cdn.jsdelivr.net/npm/dompurify/dist/purify.min.js";
  script.defer = true;
  script.onload = () => processMastodonReacts(mastodonStatusId, body, tagsElement);
  document.head.appendChild(script);
});

That's it!

Pastebin

Take a look at my pastebin.yeechie.one For the up-to-date code that I use.

#bearblog #blog #mastodon #webmention