# Bluesky Threads — FreshRSS Extension A FreshRSS extension that enriches Bluesky posts in your RSS feeds by fetching the full reply thread and embedded content via the Bluesky public API, collapsing everything into a single article. ## Features - Fetches full reply threads when a post is first saved, so API sync clients (Fever, GReader, etc.) receive enriched content immediately - Automatically refreshes thread content as it ages, with progressively relaxed refresh intervals - Renders rich text with working links, mentions, and hashtags - Renders all embed types: images, external link cards, quoted posts, and videos - No Bluesky account or API credentials required ## Installation 1. Download or clone this repository into FreshRSS's `extensions/` directory. The folder must be named `xExtension-BlueskyThreads`. 2. In FreshRSS, go to **Extensions** and enable **Bluesky Threads**. ## Configuration In the extension settings, you can set **Thread depth** (default: 10, max: 1000) — how many levels of replies to fetch per post. ## How it works ### Hooks Two hooks work in tandem so both the web UI and API sync clients receive enriched content: - **`EntryBeforeInsert`** — fires once when a new entry is first saved. Fetches the thread immediately and stores the rendered HTML. - **`EntryBeforeDisplay`** — fires on every web render. Checks if the cached thread is stale; if so, re-fetches and writes the updated HTML back to the database. ### Cache & staleness Thread HTML is cached as JSON files in `DATA_PATH/BlueskyThreads/{md5(url)}.json`. Staleness is determined by the post's age: | Post age | Cache refresh interval | |--------------|------------------------| | < 1 hour | Every 10 minutes | | < 24 hours | Every 1 hour | | < 7 days | Every 12 hours | | 7+ days | Never (frozen) | On API failure, the stale cache is served as a fallback. ### API endpoints used All requests go to `public.api.bsky.app` — no authentication required. - **Handle resolution:** `com.atproto.identity.resolveHandle` - **Thread fetch:** `app.bsky.feed.getPostThread`