Skip to content

A bot for posting RSS feed updates to Bluesky using Node.js and Docker.

License

Notifications You must be signed in to change notification settings

cgillinger/Blueskybot

Repository files navigation

Blueskybot

Node.js License: MIT Docker Bluesky

A lightweight Node.js bot that monitors RSS feeds and posts new articles to Bluesky with rich embed cards.

Features

  • Monitors multiple RSS feeds on a configurable polling interval
  • Posts new articles with Open Graph metadata (title, description, thumbnail)
  • Tracks posted links locally to prevent duplicates
  • Persistent session management (logs in once, re-authenticates on expiry)
  • Respects Bluesky API rate limits with separate read/write tracking
  • Request timeouts and URL validation for reliability and security
  • Runs as non-root user in Docker with health checks

Prerequisites

Quick Start

1. Clone and install

git clone https://github.com/cgillinger/Blueskybot.git
cd Blueskybot
npm install

2. Configure credentials

cp .env.example .env

Edit .env with your Bluesky credentials:

BLUESKY_USERNAME=your_handle@bsky.social
BLUESKY_PASSWORD=your_app_password

Tip: Use an App Password instead of your main password.

3. Configure RSS feeds

cp feeds.txt.example feeds.txt

Edit feeds.txt — one feed per line, no quotes or brackets needed:

https://example.com/feed.xml | Example News
https://another.site/rss     | Another Feed
https://minimal.org/rss

Lines starting with # are comments. The title after | is optional — if provided, it prefixes the Bluesky post.

4. Run

npm start

The bot polls every minute and posts articles published within the last hour. Conditional HTTP requests (ETag/Last-Modified) keep unchanged polls near-zero cost.

Docker

Using Docker Compose (recommended)

cp .env.example .env          # configure credentials
cp feeds.txt.example feeds.txt # configure feeds
docker compose up -d --build
docker compose logs -f        # follow logs
docker compose down           # stop

Using Docker directly

docker build -t blueskybot .
docker run -d --name blueskybot --env-file .env --restart always blueskybot

The container uses node:18-alpine, runs as a non-root user, and includes a health check.

Configuration

All configuration constants are defined at the top of bot.mjs:

Constant Default Description
POLL_INTERVAL_MS 60000 Polling interval (1 min)
PUBLICATION_WINDOW_MS 3600000 Only post articles newer than this (1 hour)
MAX_TRACKED_LINKS_PER_FEED 20 Duplicate tracking buffer per feed
FETCH_TIMEOUT_MS 15000 HTTP request timeout (15 sec)
MAX_IMAGE_SIZE 1000000 Max thumbnail size in bytes (1 MB)

Project Structure

Blueskybot/
├── bot.mjs              # Main application
├── feeds.txt            # Your RSS feeds (not tracked by git)
├── feeds.txt.example    # Feed configuration template
├── Dockerfile           # Container image (Alpine, non-root)
├── docker-compose.yml   # Compose orchestration
├── package.json         # Dependencies and scripts
├── .env.example         # Credential template
├── .gitignore
├── LICENSE              # MIT
└── README.md

How It Works

┌─────────────┐     ┌──────────────┐     ┌─────────────────┐
│  RSS Feeds  │────>│   bot.mjs    │────>│  Bluesky (AT     │
│  (polling)  │     │  parse/filter│     │  Protocol API)   │
└─────────────┘     └──────┬───────┘     └─────────────────┘
                           │
                    ┌──────┴───────┐
                    │ OG metadata  │
                    │ fetch + image│
                    │ upload       │
                    └──────┬───────┘
                           │
                    ┌──────┴───────┐
                    │ lastPosted   │
                    │ Links.json   │
                    └──────────────┘
  1. Poll RSS feeds at a fixed interval
  2. Filter articles to those published within the last hour
  3. Deduplicate against locally stored posted links
  4. Fetch Open Graph metadata (title, description, image) from article URL
  5. Upload thumbnail image as blob to Bluesky
  6. Post to Bluesky with app.bsky.embed.external embed card
  7. Persist the posted link to avoid duplicates on restart

Troubleshooting

Problem Solution
Invalid identifier or password Verify .env credentials. Use an App Password.
API rate limit reached The bot automatically waits and retries. No action needed.
Thumbnails missing on some posts The source site may lack og:image tags, or the image exceeds 1 MB.
FETCH_TIMEOUT errors The target site is slow or unreachable. The post will still be created without a thumbnail.
Container unhealthy Check logs with docker compose logs — likely a credential or network issue.

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

License

MIT © Christian Gillinger

About

A bot for posting RSS feed updates to Bluesky using Node.js and Docker.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •