A specialized feed service for Brandon Sanderson's Cosmere universe fans, powered by the AT Protocol SDK for Python. This service intelligently filters and combines trending and chronological posts to deliver a curated Cosmere content stream.
π« Built upon the original Python feed generator by @MarshalX.
-
π Smart Filtering with advanced regexp:
- β‘ Individual keywords (with automatic plural forms)
- π Multi-word tokens (order-independent matching)
- π Exact phrase matching
- π€ Specific handle inclusion
-
π PostgreSQL Database
- π³ Docker containerization
- πΎ Persistent data storage
-
π Trending Posts Integration
- βοΈ Interaction score calculation
- π§Ή Automated database cleanup via
apscheduler
-
π³ Docker Compose Deployment
- π Orchestrates
web
,firehose
, andpostgres
services
- π Orchestrates
β οΈ Note: Posts are retained for 30 days, with trending calculations based on 24-hour interaction windows
allomancy
,bondsmith
,cosmere
,dalinar
,dawnshard
,dragonsteel
,dustbringer
,edgedancer
,elantris
,elsecaller
,stormblessed
,thaidakar
,kholin
,lightweaver
,mistborn
,oathbringer
,sanderlanche
,sazed
,shadesmar
,skybreaker
,spren
,stoneward
,stormlight
,surgebinding
,truthwatcher
,warbreaker
,willshaper
,windrunner
,roshar
,scadrial
,taldain
,voidbringer
,shardblade
,shardplate
,shardbearer
,feruchemy
,hemalurgy
,lerasium
,atium
,mistcloak
,kandra
,koloss
,skaa
,highstorm
,parshendi
,urithiru
,honorblade
,surgebinder
,dawnshard
,worldhopper
,perpendicularity
,adonalsium
,chasmfiend
,worldbringer
,allomancer
,highspren
,elantrian
,inkspren
,honorspren
,cultivationspren
,peakspren
,ashspren
,luckspren
,windspren
,lifespren
,towerlight
,voidlight
,brandosando
,numuhukumakiaki'ialunamor
,dsnx24
,dsnx2024
,dragonsteelnexus
,dragonsteelnexus2024
brandon sanderson
,yumi sanderson
,vin elend
,yumi painter
,shallan adolin
,kaladin syl
,kaladin adolin
,kaladin shallan
,navani kholin
,shallan pattern
,shallan veil
,shallan radiant
,vin kelsier
,kelsier survivor
,wax wayne marasi
,steris marasi
,cryptic spren
,steris wax
,szeth nightblood
,shades threnody
,threnody hell
17th shard
,bands of mourning
,brandon sanderson
,cognitive realm
,rhythm of war
,shadows of self
,sixth of the dusk
,shadows for silence
,shadows of silence
,ember dark
,emperor's soul
,isles of the ember dark
,stormlight archive
,sunlit man
,alloy of law
,hero of ages
,lost metal
,way of kings
,well of ascension
,tress of the emerald sea
,wind and truth
,words of radiance
,yumi and the nightmare painter
,shattered planes
,knight radiant
,knights radiant
,journey before destination
,life before death, strength before weakness
,dragon steel nexus
stormlightmemes.bsky.social
,brotherwisegames.bsky.social
-
Clone the repository
git clone https://github.com/richardr1126/cosmere-feed-bsky.git cd cosmere-feed-bsky/
-
Create and configure environment variables
cp example.env .env
Edit
.env
with your settings:HOSTNAME=feed.yourdomain.com # Domain name for the feed HANDLE=your-handle.bsky.social # A Bluesky handle for api access PASSWORD=your-password # A Bluesky app password CHRONOLOGICAL_TRENDING_URI= # Leave empty for now POSTGRES_USER=postgres # Postgres user to create POSTGRES_PASSWORD=your-db-password # Postgres password to create and use POSTGRES_DB=feed # Postgres db name to create and use
-
Edit
publish_feed.py
with your feed details:RECORD_NAME
: Short name for the feed identifier (lowercase, no spaces)DISPLAY_NAME
: User-facing feed nameDESCRIPTION
: Feed descriptionAVATAR_PATH
: Path to feed avatar image (optional)
-
Modify filters in
firehose/filter_config.json
(optional):HANDLES
: Accounts to always includeEXCLUDE_HANDLES
: Accounts to always excludePHRASES
: Exact phrases to matchINCLUSIVE_MULTI_TOKENS
: Multi-word matches (any order)TOKENS
: Single words to matchEXCLUDE_TOKENS
: Words to exclude
-
Install the ATProto SDK:
pip install atproto
-
Run the publisher:
python publish_feed.py
-
Copy the output Feed URI into your
.env
file asCHRONOLOGICAL_TRENDING_URI
-
Ensure Docker and Docker Compose are installed
-
Build and start services:
docker compose up --build
This launches:
- PostgreSQL database (with persistence)
- Firehose data stream processor
- Feed generator web server (4 Gunicorn workers)
-
Your feed should now be accessible at:
http://localhost:8000/xrpc/app.bsky.feed.getFeedSkeleton?feed=[CHRONOLOGICAL_TRENDING_URI]&limit=30
By default, the feed will be accessible at http://localhost:8000
. For production deployment:
- Deploy to a cloud provider like AWS, Azure, or Google Cloud with persistent storage for Docker volumes
- Configure your domain's DNS records to point to the server
- Use your domain
HOSTNAME
in the.env
file
Alternative methods:
- Use free ngrok for temporary public access
- Set the ngrok domain as
HOSTNAME
in.env
- Set the ngrok domain as
- Set up a free Cloudflare Tunnel for permanent local server access
- Point your domain to the Cloudflare Tunnel endpoint, and use your domain as
HOSTNAME
in.env
- Optioanlly setup your
docker compose up --build
as a systemctl service for automatic startup (need Linux)
- Point your domain to the Cloudflare Tunnel endpoint, and use your domain as
The server provides the following endpoints:
- π Well-Known DID Document:
GET /.well-known/did.json
- π Feed Generator Description:
GET /xrpc/app.bsky.feed.describeFeedGenerator
- π Feed Skeleton:
GET /xrpc/app.bsky.feed.getFeedSkeleton
This project is licensed under the MIT License.
Special thanks to:
- @MarshalX for the foundational work on the AT Protocol SDK for Python
- Bluesky Social for the AT Protocol
- Brandon Sanderson for creating the inspiring Cosmere universe
- π« Handles to Exclude:
flintds.bsky.social
- β Exclude Tokens:
trump
,sylvana
,sylvanna
,alleria
,uriele
,mormon