A command-line tool that fetches RSS/Atom feeds and posts new entries to Mastodon with customizable templates.
There are many other tools like this, but this one is mine.
- Fetch RSS and Atom feeds
- Store entries in a local SQLite database
- Post entries to Mastodon with customizable templates
- OAuth authentication flow for Mastodon
- Dry-run mode for testing
- Automatic duplicate detection
- Automatic purging of entries no longer in feed
- Configurable post visibility and content warnings
- Character limit validation
- Support for posts-per-run limits
- Catchup mode to skip old entries
- Account verification in status command
git clone https://github.com/lorchard/feed-to-mastodon.git
cd feed-to-mastodon
go build ./cmd/feed-to-mastodonThe binary will be created as feed-to-mastodon in the current directory.
./feed-to-mastodon initThis creates:
feed-to-mastodon.yaml- Configuration filepost-template.txt- Post templatefeed-to-mastodon.db- SQLite database
Edit feed-to-mastodon.yaml:
# REQUIRED: Feed URL to fetch
feed_url: "https://example.com/feed.xml"
# REQUIRED: Mastodon server URL
mastodon_server: "https://mastodon.social"
# AUTHENTICATION: Choose one of two methods:
#
# Method 1 - Direct Access Token (quick but manual):
# Create at: Settings > Development > New Application
# Required scopes: write:statuses
mastodon_token: "your-access-token-here"
#
# Method 2 - OAuth Flow (recommended, see Authentication section below):
# mastodon_client_id: "your-client-id"
# mastodon_client_secret: "your-client-secret"./feed-to-mastodon fetch./feed-to-mastodon statusTest with dry-run first:
./feed-to-mastodon post --dry-runThen post for real:
./feed-to-mastodon postThere are two ways to authenticate with Mastodon:
- Go to your Mastodon instance: Settings > Development > New Application
- Create an application with
write:statusesscope - Copy the access token
- Add it to your config:
mastodon_token: "your-access-token-here"
- Go to your Mastodon instance: Settings > Development > New Application
- Create an application with
read writescopes - Copy the Client ID and Client Secret
- Add them to your config:
mastodon_client_id: "your-client-id" mastodon_client_secret: "your-client-secret"
- Generate authorization link:
./feed-to-mastodon link
- Visit the URL, authorize the application, and copy the authorization code
- Exchange the code for an access token:
./feed-to-mastodon code <authorization-code>
The access token is stored in the database and used automatically for future posts.
You can verify authentication with:
./feed-to-mastodon statusInitialize a new feed-to-mastodon project.
feed-to-mastodon init [--directory DIR]Options:
-d, --directory- Directory to initialize (default: current directory)
Fetch feed entries and save them to the database. By default, also purges entries that are no longer in the feed.
feed-to-mastodon fetch [--no-purge]Options:
--no-purge- Skip purging entries that are no longer in the feed
Show database status, authenticated account info, and preview next entries to be posted.
feed-to-mastodon statusPost unposted entries to Mastodon.
feed-to-mastodon post [--dry-run] [--posts N]Options:
--dry-run- Preview posts without actually posting--posts N- Maximum number of entries to post (0 = all, overrides configposts_per_run)
Mark all unposted entries as posted without actually posting them. Useful for skipping old entries.
feed-to-mastodon catchup [--dry-run]Options:
--dry-run- Preview entries without actually marking them
Generate OAuth authorization link for Mastodon authentication.
feed-to-mastodon linkRequires mastodon_client_id in config.
Exchange OAuth authorization code for an access token.
feed-to-mastodon code <authorization-code>Requires mastodon_client_id and mastodon_client_secret in config.
-c, --config PATH- Config file path (default:./feed-to-mastodon.yaml)-v, --verbose- Enable verbose output--debug- Enable debug output
All configuration options in feed-to-mastodon.yaml:
# REQUIRED: Feed URL to fetch
feed_url: "https://example.com/feed.xml"
# REQUIRED: Mastodon server URL
mastodon_server: "https://mastodon.social"
# AUTHENTICATION: Choose one of two methods:
#
# Method 1 - Direct Access Token:
# mastodon_token: "your-access-token-here"
#
# Method 2 - OAuth Flow (recommended):
# mastodon_client_id: "your-client-id"
# mastodon_client_secret: "your-client-secret"
# (Then use 'link' and 'code' commands to obtain access token)
# OPTIONAL: Database file path (default: ./feed-to-mastodon.db)
database_path: "feed-to-mastodon.db"
# OPTIONAL: Template file path (default: ./post-template.txt)
template_path: "post-template.txt"
# OPTIONAL: Character limit for posts (default: 500)
character_limit: 500
# OPTIONAL: Post visibility (public, unlisted, private, direct)
# Default: public
post_visibility: "public"
# OPTIONAL: Content warning / spoiler text
# Default: none
# content_warning: "Automated post"
# OPTIONAL: Number of entries to post per run (0 = all)
# Default: 0
# Can be overridden with --posts flag
posts_per_run: 0Templates use Go's text/template syntax. Both the feed item and feed metadata are available in templates.
{{.Item.Title}}
{{if .Item.Description}}{{truncate .Item.Description 100}}{{else if .Item.Content}}{{truncate .Item.Content 100}}{{end}}
{{.Item.Link}}
{{range .Item.Categories}}#{{.}} {{end}}
Via {{.Feed.Title}}
.Item.Title- Entry title.Item.Link- Entry link/URL.Item.Description- Entry description/summary.Item.Content- Full entry content.Item.Author.Name- Author name.Item.Published- Published date.Item.Updated- Updated date.Item.GUID- Unique identifier.Item.Categories- Entry categories/tags (array of strings)
See gofeed.Item documentation for all available fields.
.Feed.Title- Feed title.Feed.Description- Feed description.Feed.Link- Feed link/URL.Feed.Author.Name- Feed author.Feed.Language- Feed language.Feed.Copyright- Copyright information
See gofeed.Feed documentation for all available fields.
Truncate a string to a maximum length (UTF-8 aware).
{{.Item.Description | truncate 100}}
{{.Item.Title}}
{{.Item.Link}}
{{.Item.Title}}
{{.Item.Description}}
{{.Item.Link}}
{{.Item.Title}}
{{if .Item.Author}}By: {{.Item.Author.Name}}{{end}}
{{.Item.Description | truncate 200}}
๐ {{.Item.Link}}
{{.Item.Title}}
{{.Item.Description | truncate 150}}
{{.Item.Link}}
{{range .Item.Categories}}#{{.}} {{end}}
{{.Item.Title}}
{{if .Item.Description}}{{truncate .Item.Description 100}}{{else if .Item.Content}}{{truncate .Item.Content 100}}{{end}}
{{.Item.Link}}
Via {{.Feed.Title}}
To automatically fetch and post entries, add a cron job:
# Fetch every hour
0 * * * * cd /path/to/project && /path/to/feed-to-mastodon fetch
# Post every hour (limit to 5 posts per run)
5 * * * * cd /path/to/project && /path/to/feed-to-mastodon post --posts 5Or use a single cron job with the posts_per_run configuration option.
Tip: When setting up a new feed, use the catchup command to mark existing entries as posted so you only post new entries going forward:
./feed-to-mastodon catchupgo test ./...go build ./cmd/feed-to-mastodonThis project is licensed under the terms specified in the LICENSE file.
Contributions are welcome! Please feel free to submit issues and pull requests.