No description
Find a file
2026-03-11 13:58:29 +00:00
.forgejo/workflows Update build.yml 2025-09-30 19:36:00 +01:00
bsky RefreshSession code changes 2026-03-11 12:14:42 +00:00
.gitignore add files 2025-06-05 07:22:57 +01:00
Dockerfile Add ffmpeg to right place 2025-11-26 14:15:53 +00:00
go.mod add files 2025-06-05 07:22:57 +01:00
go.sum add files 2025-06-05 07:22:57 +01:00
LICENSE Update README.md, add LICENSE 2026-03-11 13:58:29 +00:00
main.go Add error message output for media 2025-11-26 14:11:23 +00:00
README.md Update README.md, add LICENSE 2026-03-11 13:58:29 +00:00

bsky2tg

A real-time bridge that forwards Bluesky posts to Telegram. Monitor your Bluesky account and automatically send posts to a Telegram channel with full media support, quote posts, and more.

Features

  • 🦋 Real-time sync - Posts appear on Telegram seconds after posting on Bluesky
  • 📸 Full media support - Images, videos, GIFs (from Tenor)
  • 💬 Quote posts - Properly formatted with links to original posts
  • ✏️ Edit support - Updates Telegram message when you edit a Bluesky post
  • 🗑️ Delete sync - Removes from Telegram when you delete from Bluesky
  • 🔗 Rich links - @mentions, hashtags, and custom aliases converted to clickable links
  • Time filtering - Ignore old posts and replies if desired
  • 🎬 Video metadata - Includes duration, dimensions, and thumbnail

Setup

Prerequisites

  • Go 1.21+
  • A Bluesky account
  • A Telegram bot and channel

Installation

  1. Clone the repository

    git clone https://git.zio.sh/astra/bsky2tg
    cd bsky2tg
    
  2. Build the project

    go build
    
  3. Set environment variables

    export BSKY_HANDLE="your.bsky.handle"
    export BSKY_PASSWORD="your-app-password"  # NOT your main password
    export TG_TOKEN="your-telegram-bot-token"
    export TG_CHANNEL_ID="your-channel-id"
    

    Optional:

    export TG_API_ENDPOINT="https://api.telegram.org/bot%s/%s"  # Custom Telegram API endpoint
    export OLDPOSTTIME="1"  # Ignore posts older than this many hours (default: 1)
    
  4. Run the daemon

    ./bsky2tg
    

Running with Podman

Run the bot in a container using Podman:

With .env file

podman run -it --name bsky2tg_<profile> \
  --env-file /path/to/.env \
  git.zio.sh/astra/bsky2tg:latest

With environment variables

podman run -it --name bsky2tg_<profile> \
  --env TG_TOKEN=<your-token> \
  --env TG_CHANNEL_ID=<your-channel-id> \
  --env BSKY_HANDLE=<your.handle> \
  --env BSKY_PASSWORD=<your-app-password> \
  git.zio.sh/astra/bsky2tg:latest

Getting Your Credentials

Bluesky App Password:

  • Go to Settings → Privacy and Security → App Passwords
  • Create a new app password (NOT your main Bluesky password)

Telegram Bot Token:

  • Message @BotFather on Telegram
  • Create a new bot with /newbot
  • Copy the token

Telegram Channel ID:

  • Create a channel (can also be private)
  • Add your bot as an admin
  • Use @userinfobot to get the channel ID

Usage

Daemon Mode

The bot runs continuously and syncs new posts in real-time:

./bsky2tg

One-Shot Post Sync

Send a specific post to Telegram:

./bsky2tg -post "https://bsky.app/profile/user.bsky/post/abc123"

Delete a Post

Remove a post from Telegram (delete from Bluesky first):

./bsky2tg -post "https://bsky.app/profile/user.bsky/post/abc123" -delete

Ignore Old Posts

Ignore posts created more than 2 hours ago:

./bsky2tg -oldposttime 2

How It Works

  1. Authentication - Logs into Bluesky via ATProto and stores the session
  2. Jetstream Connection - Subscribes to real-time post events from your account
  3. Post Processing - Parses posts, extracts media, processes facets (links/mentions)
  4. Telegram Delivery - Sends formatted messages with media to your channel
  5. Metadata Storage - Records post mapping (Bluesky → Telegram) for edits/deletes

Configuration

Post Format

Posts are sent with this format:

[Post text with @mentions and #hashtags]
—
🦋 @your.handle

Quote posts include the quoted post above in a blockquote.

Custom Aliases

You can set up custom link replacements by creating entries in the blue.zio.bsky2tg.alias collection on your PDS.

Troubleshooting

Auth errors

  • Verify BSKY_HANDLE and BSKY_PASSWORD are correct
  • Use an app password, not your main Bluesky password
  • Check auth-session.json file permissions

Posts not syncing

  • Ensure the bot is admin in the channel
  • Check TG_CHANNEL_ID is correct
  • Verify Jetstream connection with logs

Video errors

  • FFmpeg must be installed for video processing
  • Check that video file can be read

Project Structure

.
├── main.go              # Event handler, post processing, Telegram sender
├── bsky/
│   ├── client.go        # Bluesky session management, handle resolution
│   ├── bluesky.go       # ATProto API calls (posts, records, sessions)
│   └── parse.go         # Post parsing, facet processing
├── auth-session.json    # Stored auth session (auto-created)
└── README.md            # This file

API Integration

  • Bluesky ATProto - Session creation, post fetching, record management
  • Jetstream - Real-time firehose subscription
  • Telegram Bot API - Message/media sending, editing, deleting

Notes

  • Auth sessions are persisted in auth-session.json
  • Tokens are automatically refreshed when expired
  • Posts are deduplicated to prevent duplicates on sync restart
  • Media is fetched from your PDS via blob endpoints

License

See LICENSE file