social media crossposting tool. 3rd time's the charm
mastodon misskey crossposting bluesky
1# XPost 2 3> put more readme here uhhh 4 5a silly little crossposting tool based on the mastodon streaming api. 6 7this tool is very, very not production ready or something. use with caution. 8 9# Installation 10 11first install `ffmpeg`, `ffprobe` and `libmagic`, make sure that `ffmpeg` is available on PATH! `ffmpeg` and `libmagic` are required to crosspost media. 12 13then get [uv](https://github.com/astral-sh/uv) and sync the project 14 15``` 16uv sync 17``` 18 19generate settings.json on first launch 20 21``` 22uv run main.py 23``` 24 25# Settings 26 27the tool allows you to specify an input and multiple outputs to post to. 28 29some options accept a envvar syntax: 30 31```json 32{ 33 "token": "env:TOKEN" 34} 35``` 36 37## Inputs 38 39### Bluesky PDS WebSocket 40 41**this is meant for self-hosted PDSs that don't emmit a billion events per second.** a jetstream version will be available soon. 42 43listens to repo operation events emmited by the PDS. handle becomes optional if you specify a DID. 44 45```json5 46{ 47 "type": "bluesky-pds-wss", 48 "handle": "env:BLUESKY_HANDLE", // handle (e.g. melontini.me) 49 "did": "env:BLUESKY_DID", // use a DID instead of handle (avoids handle resolution) 50 "pds": "end:BLUESKY_PDS" // specify Your PDS directly (avoids DID doc lookup) 51} 52``` 53 54### Mastodon WebSocket `mastodon-wss` 55 56listens to the user's home timeline for new posts, crossposts only the public/unlisted ones by the user. 57 58```json5 59{ 60 "type": "mastodon-wss", // type 61 "instance": "env:MASTODON_INSTANCE", // mastodon api compatible instance 62 "token": "env:MASTODON_TOKEN", // Must be a mastodon token. get from something like phanpy + webtools. or https://getauth.thms.uk/?client_name=xpost&scopes=read:statuses%20write:statuses%20profile but doesn't work with all software 63 "options": { 64 "allowed_visibility": [ 65 "public", 66 "unlisted" 67 ] 68 } 69} 70``` 71 72any instance implementing `/api/v1/instance`, `/api/v1/accounts/verify_credentials` and `/api/v1/streaming?stream` will work fine. 73 74confirmed supported: 75- Mastodon 76- Iceshrimp.NET 77- Akkoma 78 79confirmed unsupported: 80- Mitra 81- Sharkey 82 83### Misskey WebSocket 84 85listens to the homeTimeline channel for new posts, crossposts only the public/home ones by the user. 86 87**IMPORTANT**: Misskey WSS does Not support deletes, you must delete posts manually. if you know how i can listen to all note events, i would appreciate your help. 88 89```json5 90{ 91 "type": "misskey-wss", // type 92 "instance": "env:MISSKEY_INSTANCE", // misskey instance 93 "token": "env:MISSKEY_TOKEN", // access token with the `View your account information` scope 94 "options": { 95 "allowed_visibility": [ 96 "public", 97 "home" 98 ] 99 } 100} 101``` 102 103Misskey API is not very good, this also wasn't tested on vanilla misskey. 104 105confirmed supported: 106- Sharkey 107 108## Outputs 109 110### Mastodon API 111 112no remarks. 113 114```json5 115{ 116 "type": "mastodon", 117 "token": "env:MASTODON_TOKEN", // Must be a mastodon token. get from something like phanpy + webtools. or https://getauth.thms.uk/?client_name=xpost&scopes=read:statuses%20write:statuses%20profile but doesn't work with all software 118 "instance": "env:MASTODON_INSTNACE", // mastodon api compatible instance 119 "options": { 120 "visibility": "public" 121 } 122} 123``` 124 125### Bluesky 126 127in the bluesky block, you can configure who is allowed to reply to and quote the new posts. handle becomes optional if you specify a DID. 128 129```json5 130{ 131 "type": "bluesky", // type 132 "handle": "env:BLUESKY_HANDLE", // handle (e.g. melontini.me) 133 "app_password": "env:BLUESKY_APP_PASSWORD", // https://bsky.app/settings/app-passwords 134 "did": "env:BLUESKY_DID", // use a DID instead of handle (avoids handle resolution) 135 "pds": "env:BLUESKY_PDS", // specify Your PDS directly (avoids DID doc lookup) 136 "options": { 137 "encode_videos": true, // bluesky only accepts mp4 videos, try to convert if the video is not mp4 138 "quote_gate": false, // block users from quoting the post 139 "thread_gate": [ // block replies. leave empty to disable replies 140 "mentioned", 141 "following", 142 "followers", 143 "everybody" // allow everybody to reply (ignores other options) 144 ] 145 } 146} 147```