- TypeScript 100%
- Docker <1%
Dobré zprávy – feed pro Bluesky #
Vlastní feed pro Bluesky, který sbírá všechny posty s hashtagem #dobrázpráva. Vychází z oficiálního feed-generator starter kitu, ale místo firehose odebírá Jetstream, který je mnohem lehčí na CPU i provoz.
Jak to funguje #
src/util/subscription.tsse připojí na Jetstream přes WebSocket a odebírá jen kolekciapp.bsky.feed.post. Při výpadku se znovu připojí a naváže od uloženého kurzoru (time_us, ukládá se do tabulkysub_state).src/subscription.tskaždý nový post zkontroluje. Do SQLite uloží jen ty, které mají hashtagdobrázprávav tag facetu nebo v politags. Smazané posty z databáze odstraní.- Porovnání ignoruje velikost písmen i diakritiku, takže projde
#dobrázpráva,#DobráZprávai#dobrazprava. Upravit to jde ve funkcinormalizeTag.
- Porovnání ignoruje velikost písmen i diakritiku, takže projde
src/algos/dobra-zprava.tsvrací uložené posty od nejnovějších, se stránkováním přes kurzor (čas události z Jetstreamu + CID).- Server (Express) odpovídá na
app.bsky.feed.getFeedSkeletonaapp.bsky.feed.describeFeedGenerator. Bluesky z vrácených URI sám poskládá hotové posty.
Požadavky #
- Node.js 22 (nebo ≥ 18) a Yarn 1
- Veřejná doména s HTTPS na portu 443, na které feed poběží (identifikuje se přes
did:web) - Bluesky účet a app password pro publikaci feedu
Konfigurace #
Vytvoř soubor .env (načítá se přes dotenv):
| Proměnná | Výchozí | Popis |
|---|---|---|
FEEDGEN_HOSTNAME |
example.com |
Doména, na které feed běží |
FEEDGEN_SERVICE_DID |
did:web:<hostname> |
DID služby |
FEEDGEN_PUBLISHER_DID |
did:example:alice |
DID účtu, který feed publikuje |
FEEDGEN_PORT |
3000 |
Port serveru |
FEEDGEN_LISTENHOST |
localhost |
Adresa, na které server naslouchá |
FEEDGEN_SQLITE_LOCATION |
:memory: |
Cesta k SQLite souboru. Pro ostrý provoz nastav soubor, jinak se po restartu data ztratí |
FEEDGEN_SUBSCRIPTION_ENDPOINT |
wss://jetstream2.us-east.bsky.network/subscribe |
Jetstream endpoint |
FEEDGEN_SUBSCRIPTION_RECONNECT_DELAY |
3000 |
Prodleva před opětovným připojením (ms) |
Spuštění #
yarn
yarn start
Feed si pak můžeš lokálně vyzkoušet na:
http://localhost:3000/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://<PUBLISHER_DID>/app.bsky.feed.generator/dobra-zprava
Docker viz sekce Nasazení.
Nasazení (Docker) #
Repo obsahuje Dockerfile a compose.yaml. Kontejner naslouchá na 127.0.0.1:3100 hostitele, databáze je ve volume feed-data (/data/feed.db). Před kontejner patří reverzní proxy s HTTPS, např. Caddy:
feed.atproto.cz {
reverse_proxy http://localhost:3100
}
Na serveru:
git clone <repo> /opt/dobrezpravyfeed && cd /opt/dobrezpravyfeed
cp deploy/env.example .env # a uprav FEEDGEN_PUBLISHER_DID
docker compose up -d --build
Kontrola: curl https://feed.atproto.cz/.well-known/did.json a docker compose logs -f feed.
Aktualizace: git pull && docker compose up -d --build. Databáze přežije, je ve volume.
Skripty běží uvnitř kontejneru, aby viděly stejnou databázi:
docker compose exec feed yarn moderate block-author did:plc:...
Zálohu databáze uděláš např. přes docker compose exec feed cp /data/feed.db /data/backup.db, případně zálohou volume.
Publikace feedu #
yarn publishFeed
Skript se interaktivně zeptá na handle, app password, název záznamu (použij dobra-zprava, musí odpovídat názvu algoritmu v src/algos), zobrazované jméno, popis a avatar. Opětovným spuštěním aktualizuješ údaje feedu. Zrušit publikaci jde přes yarn unpublishFeed.
Zpětné naplnění #
Server indexuje jen nové posty. Starší posty s hashtagem doplníš skriptem, který je dohledá přes vyhledávání Bluesky (vyžaduje přihlášení, doporučen app password):
docker compose exec feed yarn backfill
Skript prochází výsledky od nejnovějších po nejstarší, použije stejný filtr i blocklist jako živá indexace a lze ho bezpečně spouštět opakovaně. Dostupná historie je dána hloubkou vyhledávacího indexu Bluesky.
Jazyky obsahu #
Feed nefiltruje podle jazyka, ale klienti Bluesky ano. Podle nastavení Content languages (Nastavení → Languages) skrývají ve feedech posty v jazycích, které uživatel nemá zapnuté. Kdo má zapnutou jen angličtinu, neuvidí česky psané posty a feed mu bude připadat neúplný nebo prázdný. Řešení je v klientu přidat Čeština (případně Slovenština) mezi jazyky obsahu. Na straně serveru se to ovlivnit nedá.
Moderace #
Posty a autory lze z feedu vyřadit příkazem (vyžaduje FEEDGEN_SQLITE_LOCATION nastavené na souborovou databázi, stejnou jako používá server):
yarn moderate block-post at://did:plc:.../app.bsky.feed.post/...
yarn moderate block-author did:plc:...
yarn moderate unblock-post <at-uri>
yarn moderate unblock-author <did>
block-postsmaže post z feedu a zabrání jeho opětovné indexaci.block-authorsmaže z feedu všechny dosavadní posty autora a ignoruje jeho nové.- Odblokování smazané posty nevrací, jen umožní indexaci nových.
- Změna se projeví hned, server není potřeba restartovat.
Struktura #
src/
index.ts načtení konfigurace a start serveru
server.ts Express + XRPC server
subscription.ts filtr postů s #dobrázpráva
util/subscription.ts Jetstream klient (reconnect, kurzor)
algos/ algoritmy feedu (název souboru = rkey feedu)
moderation.ts blokace postů a autorů
db/ SQLite schéma a migrace
methods/ XRPC endpointy
scripts/ publikace / zrušení feedu, moderace, backfill
Licence #
MIT, viz LICENSE. Původní kód je z bluesky-social/feed-generator.