AMONG CATS AND BOOKS

Dynamic Blogroll for Bearblog (and other sites)

Recently, an anonymous bird made a bold claim on Discord:

The perpetrator is Prismatic Wasteland!

Comparing Anne's blog over on DIY & Dragons to social media isn't an exaggeration. You can find curated lists of active blogs for the TTRPG hobby thereβ€”a collection of links to the latest posts from numerous amazing blogs. This provides you with direction and permission to discover more content elsewhere. That's why links are important. That's why links are powerful. And that's why big platforms gaslight users into thinking that using links is bad and should be punished.

The blogroll feature is, in my opinion, the biggest (and perhaps only) reason to use Google's Blogger platform. It made me ask: How can I create a similar feature for other websites? Essentially, I wanted a system that dynamically generates a curated list of recent posts from other blogs, without requiring manual updates.

Inspired by my previous post about adding Bluesky as comments and its JavaScript-based approach, I realized I might use my FreshRSS instance. FreshRSS has an API, so why not leverage that?

That idea quickly grew into a prototype. After two weeks of refinement, it's now stable enough to share. Ready to see the results? Check out my Blogroll. If you want to build your own, keep reading!

✱ WARNING

This approach is quite technical and may not fit every scenario. While it's as low-code as possible, you need a basic understanding of the following:



Prerequisites

To create a similar setup, you'll need:

You can use this approach on any site where you can edit HTML and CSS, such as Blot or other platforms.

Why a Python application? It acts as a secure proxy between your webpage and FreshRSS, ensuring your credentials remain private and simplifying API calls.

✱ NOTE

If you're using a different RSS reader that mimics the old Google Reader API, it might work as well. However, I've only tested this with FreshRSS.


Getting Started

Step 1: Set an API password

  1. Go to your FreshRSS profile.
  2. Scroll down to External access via API.
  3. Set an API password.

Step 2: Retrieve the API Token

Run the following command in your terminal, replacing <your-freshrss-url>, <your-user-name>, and <your-api-password>:

curl 'https://<your-freshrss-url>/api/greader.php/accounts/ClientLogin?Email=<your-user-name>&Passwd=<your-api-password>'

The response should look like this:

SID=<username>/<hash>
LSID=null
Auth=<username>/<hash>

Copy the <username>/<hash> value. You'll use it in your proxy configuration.

Setup Proxy

I developed FreshProxy specifically for this purpose. Detailed instructions are available in the repository, but here's a concise guide.

Log in to the server where you'll host FreshProxy to get started.

Step 1: Clone the Repository

git clone https://github.com/hstct/FreshProxy.git
cd FreshProxy

Step 2: Create and Configure an Environment File

Use the example file to get started:

cp .env.example .env

Open .env and edit these variables:

FRESHRSS_API_TOKEN=<your-api-token>
FRESHRSS_BASE_URL=https://<your-freshrss-url>/api/greader.php/reader/api/0
FRESHPROXY_ALLOWED_ORIGINS=<your-blog-url>

For additional details, see the README.

Step 3: Run the Proxy Application on Your Server

Using a container (Docker or Podman) is simplest:

docker build -t freshproxy .
docker run -p 8000:8000 \
    -e FRESHRSS_API_TOKEN="<your-api-token>" \
    -e FRESHRSS_BASE_URL="https://<your-freshrss-url>/api/greader.php/reader/api/0" \
    -e FRESHPROXY_ALLOWED_ORIGIN="<your-blog-url>,<your-other-blog-url>" \
    --name freshproxy \
    --detach
    freshproxy

You can start/stop the container:

docker stop freshproxy
docker start freshproxy

Alternatively, you can run the application directly (given you have gunicorn installed):

gunicorn --bind 0.0.0.0:8000 freshproxy.wsgi:app --worker-class sync --workers 4 --daemon --pid /tmp/freshproxy.pid

You can stop the process like this:

kill $(cat /tmp/freshproxy.pid)

✱ NOTE

Some hosting providers may require a different port or configuration. Adjust accordingly.


Step 4: Test the Proxy

Check if it's running correctly:

curl "https://<your-proxy-url>/digest"

If successful, you'll receive valid JSON data.

Prepare your Client

To reduce your workload, I created a JavaScript package called blogroller. You can import and configure it to fetch and display your blogroll. The default styling is neutral, but you can customize it with CSS.

Step 1: Add stylesheet

In your <head>:

<head>
  <!-- Add to the end of your header -->
  <link rel="stylesheet" href="https://unpkg.com/blogroller@latest/dist/blogroller.css" />
</head>

Step 2: Load the Script

Place this in your <footer> or anywhere on your page:

< script type="module">
  import { Blogroll } from 'https://unpkg.com/blogroller@latest/dist/blogroller.esm.js';

  document.addEventListener('DOMContentLoaded', function () {
    if (document.body.classList.contains('blogroll')) {
      const blogroll = new Blogroll();
      blogroll.initialize({
	proxyUrl: 'https://<url-to-your-proxy>',
        categoryLabel: '<name-of-the-freshrss-feed-category>',
        containerId: 'rss-feed',
        batchSize: 10,
      });
    }
  });
</script>

Key Configuration Options:

Step 3: Prepage Your Blogroll Page

If your <body> tag has class="blogroll", the script will only run on that page. For Bearblog users, be sure to specify the attribute class_name: blogroll when creating a new page.

Anywhere you want the blogroll to appear:

<div id="rss-widget">
  <div id="rss-feed"></div>
</div>

✱ NOTE

If you change containerId in the initialization, update the corresponding id in your HTML as well. You can use multiple containers (and categories) on one page by replicating this pattern.


Step 4: Customize Styling (Optional)

To customize the colors, add the following CSS variables to your stylesheet's :root and change the values to your liking:

:root {
  --blogroller-border-color: #3c3836;
  --blogroller-feed-title-color: #d79921;
  --blogroller-feed-title-hover-bg: #d79921;
  --blogroller-feed-title-hover-color: #282828;
  --blogroller-link-color: #83a598;
  --blogroller-link-hover-color: #282828;
  --blogroller-text-italic-color: #98971a;
  --blogroller-text-italic-hl-color: #b8bb26;
}

Alternatively, if you prefer, you can style each part of the blogroll using the unique blogroller-* class prefixes provided by the blogroller package.

Closing

I hope this guide helps you create a dynamic blogroll. Links are powerful tools for discoveryβ€”sharing your favorite blogs spreads valuable reading lists across the community!

If you try this, I'd love to hear how it went. Feel free to reach out or share your blogroll. Next time, I promise more TTRPG-related content again!

#bearblog #meta