A simple tool which lets you scrape twitter accounts and crosspost them to bluesky accounts! Comes with a CLI and a webapp for managing profiles! Works with images/videos/link embeds/threads.
11
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 230 lines 5.1 kB view raw view rendered
1# tweets-2-bsky 2 3Cross-post from Twitter/X to Bluesky with thread support, media handling, account mapping, and a web dashboard. 4 5This repo is also mirrored on Tangled: [j4ck.xyz/tweets2bsky](https://tangled.org/j4ck.xyz/tweets2bsky) 6 7## How It Works (Simple) 8 91. You connect one or more Twitter/X source accounts to a Bluesky account. 102. The app reads tweets from X using `@the-convocation/twitter-scraper` with your cookies (`auth_token` + `ct0`). 113. It posts to Bluesky using the official AT Protocol client (`@atproto/api`). 124. It tracks what was already posted in SQLite so it does not repost duplicates. 135. A scheduler runs automatically, and you can also trigger `Run now` from the dashboard or CLI. 14 15## Installation (Pick One Path) 16 17Use either: 18 19- Docker (recommended) 20- Source install (PM2 or manual runtime) 21 22Do not do both on the same machine unless you intentionally want two separate deployments. 23 24### Option A: Docker (Recommended) 25 26Prerequisite: Docker Desktop (macOS/Windows) or Docker Engine (Linux). 27 28Start with the included compose file: 29 30```bash 31docker compose up -d 32``` 33 34Open `http://localhost:3000`. 35 36If you prefer `docker run`: 37 38```bash 39docker run -d \ 40 --name tweets-2-bsky \ 41 -p 3000:3000 \ 42 -v tweets2bsky_data:/app/data \ 43 --restart unless-stopped \ 44 j4ckxyz/tweets-2-bsky:latest 45``` 46 47Important: keep a persistent volume (`-v tweets2bsky_data:/app/data`) so mappings/history survive container recreation. 48 49Useful Docker commands: 50 51```bash 52docker logs -f tweets-2-bsky 53docker exec -it tweets-2-bsky bun dist/cli.js status 54docker stop tweets-2-bsky 55docker start tweets-2-bsky 56``` 57 58Update Docker deployment: 59 60```bash 61docker pull j4ckxyz/tweets-2-bsky:latest 62docker stop tweets-2-bsky 63docker rm tweets-2-bsky 64docker run -d \ 65 --name tweets-2-bsky \ 66 -p 3000:3000 \ 67 -v tweets2bsky_data:/app/data \ 68 --restart unless-stopped \ 69 j4ckxyz/tweets-2-bsky:latest 70``` 71 72Alternative image: `ghcr.io/j4ckxyz/tweets-2-bsky:latest`. 73 74### Option B: Source Install (PM2 or Manual) 75 76Prerequisites: 77 78- `git` 79- Bun 1.x+ (the installer auto-installs/upgrades Bun when needed) 80- PM2 (optional, but recommended for background runtime) 81 82Clone and install: 83 84```bash 85git clone https://github.com/j4ckxyz/tweets-2-bsky 86cd tweets-2-bsky 87chmod +x install.sh 88./install.sh 89``` 90 91`install.sh` does install/build/start and uses: 92 93- PM2 when PM2 is available 94- `nohup` when PM2 is not installed 95 96Useful installer commands: 97 98```bash 99./install.sh --status 100./install.sh --stop 101./install.sh --start-only 102./install.sh --no-start 103./install.sh --port 3100 104``` 105 106#### PM2 Manual Runtime (if you want direct PM2 control) 107 108```bash 109bun install 110bun run build 111pm2 start "$HOME/.bun/bin/bun" --name tweets-2-bsky --cwd "$PWD" -- dist/index.js 112pm2 logs tweets-2-bsky 113pm2 save 114``` 115 116#### Manual Foreground Runtime (no PM2) 117 118```bash 119bun install 120bun run build 121bun run start 122``` 123 124#### Manual Nohup Runtime (no PM2) 125 126```bash 127mkdir -p data/runtime 128nohup bun run start > data/runtime/tweets-2-bsky.log 2>&1 & 129echo $! > data/runtime/tweets-2-bsky.pid 130``` 131 132Stop nohup process: 133 134```bash 135kill "$(cat data/runtime/tweets-2-bsky.pid)" 136``` 137 138## First-Time Setup (After Install) 139 1401. Open `http://localhost:3000`. 1412. Register the first user (this account becomes admin). 1423. In Settings, add Twitter cookies (`auth_token`, `ct0`; backup pair optional). 1434. Add a mapping (Twitter source usernames -> Bluesky account). 1445. Click `Run now`. 145 146## Twitter/X Integration Notes 147 148- This project does not use Twitter's paid official API. 149- It uses `@the-convocation/twitter-scraper` and authenticated browser cookies to read account/tweet data. 150- Required cookies: `auth_token` and `ct0`. 151- If cookies expire, update them in Settings. 152- Keep cookies private; they are sensitive credentials. 153 154For some quote-tweet screenshot fallbacks, Chromium is used (bundled in Docker, optional dependency for source installs). 155 156## CLI Quick Commands 157 158Always run CLI commands as: 159 160```bash 161bun run cli -- <command> 162``` 163 164Common commands: 165 166```bash 167bun run cli -- status 168bun run cli -- list 169bun run cli -- run-now 170bun run cli -- run-now --dry-run 171bun run cli -- add-mapping 172bun run cli -- backfill <mapping-id-or-handle> --limit 50 173``` 174 175## Updating 176 177Source installs: 178 179```bash 180./update.sh 181``` 182 183Useful flags: 184 185```bash 186./update.sh --no-restart 187./update.sh --skip-install --skip-build 188``` 189 190## Data and Security 191 192Important files: 193 194- `config.json` (mappings, credentials, users) 195- `data/database.sqlite` (processed history) 196- `data/.jwt-secret` (generated signing key when `JWT_SECRET` is unset) 197- `.env` (runtime env values) 198 199Security basics: 200 201- First registered user becomes admin. 202- Prefer Bluesky app passwords instead of your full Bluesky password. 203- Set an explicit `JWT_SECRET` in `.env` for predictable secret management. 204- Keep `config.json`, cookie values, and `.env` private. 205 206## Development 207 208```bash 209bun run dev 210bun run dev:web 211bun run build 212bun run typecheck 213bun run lint 214``` 215 216## Troubleshooting 217 218See `TROUBLESHOOTING.md`. 219 220Common native module recovery: 221 222```bash 223bun run rebuild:native 224bun run build 225bun run start 226``` 227 228## License 229 230MIT