A tool to generate an RSS feed combining your starred/favorite content from Mastodon favorites and/or bookmarks, LinkedIn reactions and any personalized RSS feed you may have (for example Feedbin or Linkding or even GitHub). A GitHub Action rebuilds and publishes the feed every night.
- Combines multiple star sources into a single RSS feed
- Configurable number of items per feed
- Support for Mastodon media attachments in feed items
- Hashtags of Mastodon posts become feed categories (tags)
- Environment variable support for sensitive tokens
- Detailed logging options
- Short headlines for Mastodon and LinkedIn posts, generated via OpenRouter and cached
- LinkedIn reactions (except plain likes) as a source, see below
- Clone this repository
- Install dependencies with
uv sync - Copy
.env.sampleto.envand configure your tokens (includingOPENROUTER_API_KEYfor headlines) - Create a
sc_config.yaml(see below) and configure your settings
Create a sc_config.yaml file with your settings:
mastodon:
access_token: "your-token-here" # Can also be set via MASTODON_ACCESS_TOKEN env var
mastodon_instance: "https://your.instance"
mastodon_username: "yourusername"
import_tags: true # use the hashtags of a post as feed categories (default)
# Optional RSS configuration
rss:
urls:
- url: https://feedbin.com/starred/${FEEDBIN_ID}.xml
tag: feedbin
- url: https://bookmarks.ping13.net/feeds/${LINKDING_ID}/all
tag: linkding
# Optional: headline generation, see "Headline generation"
titles:
model: anthropic/claude-haiku-5.5
# Optional: LinkedIn reactions, see "LinkedIn reactions"
linkedin:
enabled: true
exclude_reactions: [LIKE]# Basic usage (outputs to stdout)
uv run rss.py
# With options
uv run rss.py --config sc_config.yaml --output feed.xml --limit 10 --debug
Options:
-c, --config TEXT Path to configuration file (default: sc_config.yaml)
--debug / --no-debug Enable debug output
-o, --output TEXT Output file (optional, defaults to stdout)
-l, --limit INTEGER Number of feed items to include (default: 5)
-L, --log-level [DEBUG|INFO|WARNING|ERROR|CRITICAL]
Set logging level (default: ERROR)
--help Show this message and exit- Spotify
- GitHub stars
- ...
- Currently, there is no way to use the creation date of a like in Mastodon, see this issue.
Reactions on LinkedIn posts (except plain likes) and your reposts can be added as a star source through LinkedIn's Member Data Portability API (EEA/Switzerland members only):
- Create a LinkedIn developer app with the Member Data Portability API
(Member) product and add
http://localhost:8799/callbackas redirect URL. - Put
LINKEDIN_CLIENT_IDandLINKEDIN_CLIENT_SECRETinto.env, then runmake linkedin-token(once a year). Usemake linkedin-token-cito also update the GitHub secretLINKEDIN_ACCESS_TOKENand the variableLINKEDIN_TOKEN_EXPIRES. - Enable the
linkedin:block insc_config.yaml.exclude_reactionstakes reaction types (LIKE,PRAISE,EMPATHY, ...) andREPOST.
The API only returns the last 28 days, so reactions are accumulated in
linkedin-state.json, which is published next to the feed and re-read on the
next run. The state also remembers the last processed event, so a normal run
asks LinkedIn only for new events (one request, which keeps well below the
daily API quota); once a week, or when the state is missing, the whole
28-day window is read again. Post text is read from the public post page and turned into a
headline. If the token expires, the feed still builds from the stored items and
a warning is logged.
Token renewal. The token is valid for about a year. When fewer than 30 days
remain, the nightly job opens a GitHub issue ("LinkedIn token expires soon")
and you get the usual GitHub notification. Renew with
make linkedin-token-ci and close the issue. The expiry date is kept in the
repository variable LINKEDIN_TOKEN_EXPIRES.
Mastodon posts have no title, so one is generated with an LLM through
OpenRouter (needs OPENROUTER_API_KEY; without it, the
start of the post is used). Configure it in sc_config.yaml:
titles:
model: anthropic/claude-haiku-5.5 # default
fallback_model: qwen/qwen3.7-flash # used if the primary fails
max_new_titles_per_run: 100 # cost guardTitles are cached in title-generator.cache (keyed by model, prompt and text),
so only new posts cost money: typically well under USD 0.10 per month. The
GitHub Action persists the cache between runs. Compare models with
make title-bakeoff.
make help # all targets, grouped by purpose
make test # run tests (no network)
make lint # ruffArchitecture diagrams live in docs/diagrams/.