A tool to synchronize posts from Bluesky to Mastodon
Project description
BlueMastodon
A Python tool to automatically cross-post manual Bluesky posts to Mastodon.
Formerly known as bluemastodon
Overview
BlueMastodon monitors your Bluesky account for new posts and automatically cross-posts them to your Mastodon account. It's designed to be run as a scheduled job via GitHub Actions or any other scheduler.
This tool specifically handles synchronizing manual posts from Bluesky to Mastodon. Blog post publishing to social platforms can be managed by a separate tool.
Features
- 🔄 Automatic Synchronization: Fetches recent Bluesky posts and cross-posts to Mastodon
- 🧵 Thread Support: Supports self-replies (threads) from Bluesky
- 🖼️ Media Support: Transfers images and attachments between platforms
- 🔗 Link Handling: Preserves external links in your posts
- 🧠 Smart Synchronization: Keeps track of synced posts to avoid duplicates
- 📝 Format Preservation: Maintains post formatting during cross-posting
- 🚨 Error Handling: Robust error handling and logging
- 🔒 Secure: Handles API credentials securely
- 🤖 GitHub Action Ready: Easily deployable as a GitHub Actions workflow
Setup
Prerequisites
- Python 3.10 or higher (tested on 3.10, 3.11, 3.12, 3.13)
- A Bluesky account
- A Mastodon account with API access
Installation
Using pip
Install directly from PyPI:
pip install bluemastodon
Using Homebrew
Install using Homebrew on macOS or Linux:
# Add the tap first (only needed once)
brew tap kelp/tools
# Install bluemastodon
brew install kelp/tools/bluemastodon
After installation, you can run the tool from the command line:
# Basic usage
bluemastodon --config /path/to/your/.env
# Dry run (won't post to Mastodon, just shows what would be posted)
bluemastodon --config /path/to/your/.env --dry-run
# With debug logging enabled
bluemastodon --config /path/to/your/.env --debug
# Specify state file location (default is sync_state.json in current directory)
bluemastodon --config /path/to/your/.env --state /path/to/state.json
You can also use it as a library in your Python code:
from bluemastodon import Config, SyncManager
# Create configuration
config = Config(
bluesky_username="your_username.bsky.social",
bluesky_password="your_app_password",
mastodon_instance_url="https://your.mastodon.instance",
mastodon_access_token="your_access_token",
lookback_hours=6,
)
# Initialize sync manager
sync_manager = SyncManager(config, state_file="sync_state.json")
# Run the sync
new_records = sync_manager.run_sync()
print(f"Synced {len(new_records)} posts")
Using Poetry
- Clone the repository:
git clone https://github.com/kelp/bluemastodon.git
cd bluemastodon
- Install with Poetry:
poetry install
Configuration
Create a .env file with your credentials:
# Required credentials
BLUESKY_USERNAME=your_bluesky_username
BLUESKY_PASSWORD=your_bluesky_password
MASTODON_INSTANCE_URL=https://your.mastodon.instance
MASTODON_ACCESS_TOKEN=your_mastodon_access_token
# Optional settings with defaults
LOOKBACK_HOURS=24 # How far back to look for posts
SYNC_INTERVAL_MINUTES=60 # Frequency of synchronization
MAX_POSTS_PER_RUN=5 # Maximum posts to sync in one run
INCLUDE_MEDIA=true # Include media attachments
INCLUDE_LINKS=true # Include post links
INCLUDE_THREADS=true # Include self-replies (threads)
Obtaining API Credentials
Bluesky
For Bluesky, you'll need your username and application password.
Mastodon
- Log in to your Mastodon instance
- Go to Preferences > Development > New Application
- Give your app a name and select the following permissions:
read:accountsread:statuseswrite:mediawrite:statuses
- Save and copy the "Access token"
Usage
Command Line
Run the sync manually:
# If installed with pip
bluemastodon
# If using Poetry
poetry run python -m social_sync
Options
-c, --config Path to custom config file (.env format)
-s, --state Path to custom state file (JSON format)
-d, --debug Enable debug logging
--dry-run Simulate syncing without posting
Example Commands
# Run with debug logging
bluemastodon --debug
# Dry run (no actual posts)
bluemastodon --dry-run
# Use custom config file
bluemastodon --config /path/to/custom.env
# Specify state file location
bluemastodon --state /path/to/state.json
Scheduled Sync with GitHub Actions
Setting Up Securely with GitHub Secrets
BlueMastodon is designed to work with GitHub Actions in a secure way, using GitHub's encrypted secrets feature to store sensitive credentials:
- Fork this repository or copy the workflow files to your own repository
- In your GitHub repository, go to "Settings" > "Secrets and variables" > "Actions"
- Add the following repository secrets (these are encrypted and secure):
BLUESKY_USERNAME: Your Bluesky usernameBLUESKY_PASSWORD: Your Bluesky application passwordMASTODON_INSTANCE_URL: Your Mastodon instance URLMASTODON_ACCESS_TOKEN: Your Mastodon API access token
For detailed instructions on obtaining and setting up these secrets, see the GitHub Secrets Setup Guide.
SECURITY WARNING: Never commit your actual credentials to the repository! Always use GitHub Secrets for sensitive information.
Optional Configuration Variables
You can also add these as repository variables (not secrets, as they're not sensitive):
- Go to "Settings" > "Secrets and variables" > "Actions" > "Variables" tab
- Configure any of the following:
LOOKBACK_HOURS: How far back to look for posts (default: 24)SYNC_INTERVAL_MINUTES: How often to sync (default: 60)MAX_POSTS_PER_RUN: Maximum posts to sync (default: 5)INCLUDE_MEDIA: Whether to include media (default: true)INCLUDE_LINKS: Whether to include links (default: true)INCLUDE_THREADS: Whether to include self-replies/threads (default: true)
Running the Workflow
- Enable the workflow in your GitHub repository (go to "Actions" tab)
- The sync will run automatically according to the schedule (hourly by default)
- You can also trigger it manually from the Actions tab by clicking "Run workflow"
- For manual runs, you can enable debug mode or dry-run mode using the provided options
How Duplicate Posts Are Prevented
BlueMastodon uses a robust state tracking system to prevent duplicate posts:
- State File: Each run maintains a JSON file with IDs of previously synced posts
- GitHub Actions Cache: The state file is persisted between runs using GitHub's cache
- Lookback Window: The tool only examines posts from the last 6 hours (configurable)
- Deduplication Logic: Posts with IDs already in the state file are automatically skipped
This system ensures:
- Each post is only synced once, even across multiple workflow runs
- If a workflow run is missed, posts are still captured in the next run
- Even if the cache is lost, only posts within the lookback window might be duplicated
For advanced cache management options (including how to clear the cache), see Managing GitHub Actions Cache.
Development
Version Information
BlueMastodon follows Semantic Versioning and is currently at version 0.9.9 (beta). For more information about our versioning system and release process, see Versioning Guidelines.
Setup Development Environment
# Clone the repository
git clone https://github.com/kelp/bluemastodon.git
cd bluemastodon
# Run the setup script (installs dependencies and pre-commit hooks)
./scripts/setup-dev.sh
# Or manually:
# Install dependencies
poetry install
# Install pre-commit hooks
pre-commit install
pre-commit install --hook-type pre-push
Pre-commit Hooks
This project uses pre-commit hooks to ensure code quality. The hooks run:
- Code formatting (Black, isort)
- Linting (Flake8, pylint)
- Type checking (Mypy)
- Security analysis (Bandit)
- Tests with minimum 90% coverage requirement (pytest)
Pre-commit hooks run automatically on commit. Pre-push hooks run more comprehensive checks before pushing to the remote repository.
Testing
Run tests with coverage:
# Run all tests
make test
# Run with coverage report
make test-cov
Linting and Formatting
# Format code
make format
# Run linting
make lint
# Run type checking
make type-check
Building and Publishing
# Build package
make build
# Create a release
make release
# Publish to PyPI (requires credentials)
make publish
Troubleshooting
Common Issues
-
Authentication Errors:
- Verify your credentials in the
.envfile - Ensure your Mastodon token has the correct permissions
- Verify your credentials in the
-
No Posts Being Synced:
- Check the
LOOKBACK_HOURSsetting - Verify that you have recent posts on Bluesky
- Run with
--debugfor detailed logging
- Check the
-
Media Not Transferring:
- Ensure
INCLUDE_MEDIA=truein your configuration - Some media types might not be supported by both platforms
- Ensure
-
GitHub Actions Not Running:
- Check if the workflow is enabled
- Verify all required secrets are set
- Check the workflow logs for errors
-
Security Concerns:
- Never commit
.envfiles with real credentials to your repository - Always use GitHub Secrets for sensitive information
- Regularly rotate your API tokens for better security
- If you suspect your tokens were compromised, regenerate them immediately
- Never commit
-
Cache Issues:
- If you experience duplicate posts, the GitHub Actions cache may have been lost
- Cache can expire after 7 days of non-use or during GitHub maintenance
- To debug cache issues, check workflow logs for "Cache restored from key: sync-state"
- For instructions on how to view, clear, or reset the cache, see Managing GitHub Actions Cache
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create a feature branch:
git checkout -b feature-name - Commit your changes:
git commit -am 'Add feature' - Push to the branch:
git push origin feature-name - Submit a pull request
Acknowledgements
- atproto for Bluesky API access
- Mastodon.py for Mastodon API access
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bluemastodon-0.9.10.tar.gz.
File metadata
- Download URL: bluemastodon-0.9.10.tar.gz
- Upload date:
- Size: 291.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f85ca2881d313962139663d5c562fbf7a13c9d7404ec0f7af0cbdddfefed031d
|
|
| MD5 |
7671018c3e0cf1442c6a29500650cc66
|
|
| BLAKE2b-256 |
36a7d7b29ec3fb2406a4594ac6a1f384511a463dd6f3a5e1fef97da00cb94c29
|
Provenance
The following attestation bundles were made for bluemastodon-0.9.10.tar.gz:
Publisher:
python-release.yml on kelp/bluemastodon
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bluemastodon-0.9.10.tar.gz -
Subject digest:
f85ca2881d313962139663d5c562fbf7a13c9d7404ec0f7af0cbdddfefed031d - Sigstore transparency entry: 1191488767
- Sigstore integration time:
-
Permalink:
kelp/bluemastodon@1c7805ef76215a64bdaf22364d1de7e7041d5ce4 -
Branch / Tag:
refs/tags/v0.9.10 - Owner: https://github.com/kelp
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-release.yml@1c7805ef76215a64bdaf22364d1de7e7041d5ce4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file bluemastodon-0.9.10-py3-none-any.whl.
File metadata
- Download URL: bluemastodon-0.9.10-py3-none-any.whl
- Upload date:
- Size: 23.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
986baa22948b51b143af96ef468b07d33b627da4a929712251e96367b46fe9af
|
|
| MD5 |
c254a313bfd4173afe59a60cc4c3ba7a
|
|
| BLAKE2b-256 |
ef5be3d1faff664b403a19d4b2dd2224a0dabc6cf677f26fb696fbb3a1f6731c
|
Provenance
The following attestation bundles were made for bluemastodon-0.9.10-py3-none-any.whl:
Publisher:
python-release.yml on kelp/bluemastodon
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
bluemastodon-0.9.10-py3-none-any.whl -
Subject digest:
986baa22948b51b143af96ef468b07d33b627da4a929712251e96367b46fe9af - Sigstore transparency entry: 1191488768
- Sigstore integration time:
-
Permalink:
kelp/bluemastodon@1c7805ef76215a64bdaf22364d1de7e7041d5ce4 -
Branch / Tag:
refs/tags/v0.9.10 - Owner: https://github.com/kelp
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-release.yml@1c7805ef76215a64bdaf22364d1de7e7041d5ce4 -
Trigger Event:
push
-
Statement type: