social media crossposting tool. 3rd time's the charm
mastodon
misskey
crossposting
bluesky
1# XPost
2
3XPost is a social media cross-posting tool that differs from others by using streaming APIs to allow instant, zero-input cross-posting. this means you can continue posting on your preferred platform without using special apps.
4
5XPost tries to support as many features as possible. for example, when cross-posting from mastodon to bluesky, unsupported file types will be attached as links. posts with mixed media or too many files will be split and spread across text.
6
7the tool may undergo breaking changes as new features are added, so proceed with caution when deploying.
8
9# Installation
10
11## Native
12
13first install `ffmpeg`, `ffprobe` and `libmagic`, make sure that `ffmpeg` is available on PATH! `ffmpeg` and `libmagic` are required to crosspost media.
14
15then get [uv](https://github.com/astral-sh/uv) and sync the project
16
17```
18uv sync
19```
20
21generate settings.json on first launch
22
23```
24uv run main.py
25```
26
27## Docker Compose
28
29the official immage is available on [docker hub](https://hub.docker.com/r/melontini/xpost). example `compose.yaml`. this assumes that data dir is `./data`, and env file is `./.config/docker.env`. add `:Z` to volume mounts for podman.
30
31```yaml
32services:
33 xpost:
34 image: melontini/xpost:latest
35 restart: unless-stopped
36 env_file: ./.config/docker.env
37 volumes:
38 - ./data:/app/data
39```
40
41# Settings
42
43the tool allows you to specify an input and multiple outputs to post to.
44
45some options accept a envvar syntax:
46
47```json
48{
49 "token": "env:TOKEN"
50}
51```
52
53## Inputs
54
55all inputs have common options.
56
57```json5
58{
59 "options": {
60 "regex_filters": [ //posts matching any of the following regexes will be skipped
61 "(?i)\\b(?:test|hello|hi)\\b"
62 ]
63 }
64}
65```
66
67### Bluesky Jetstream
68
69listens to repo operation events emmited by Jetstream. handle becomes optional if you specify a DID.
70
71```json5
72{
73 "type": "bluesky-jetstream-wss",
74 "handle": "env:BLUESKY_HANDLE", // handle (e.g. melontini.me)
75 "did": "env:BLUESKY_DID", // use a DID instead of handle (avoids handle resolution)
76 "jetstream": "wss://jetstream2.us-east.bsky.network/subscribe" //optional, change jetstream endpoint
77}
78```
79
80### Mastodon WebSocket `mastodon-wss`
81
82listens to the user's home timeline for new posts, crossposts only the public/unlisted ones by the user.
83
84```json5
85{
86 "type": "mastodon-wss", // type
87 "instance": "env:MASTODON_INSTANCE", // mastodon api compatible instance
88 "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
89 "options": {
90 "allowed_visibility": [
91 "public",
92 "unlisted"
93 ]
94 }
95}
96```
97
98any instance implementing `/api/v1/instance`, `/api/v1/accounts/verify_credentials` and `/api/v1/streaming?stream` will work fine.
99
100confirmed supported:
101- Mastodon
102- Iceshrimp.NET
103- Akkoma
104
105confirmed unsupported:
106- Mitra
107- Sharkey
108
109### Misskey WebSocket
110
111listens to the homeTimeline channel for new posts, crossposts only the public/home ones by the user.
112
113**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.
114
115```json5
116{
117 "type": "misskey-wss", // type
118 "instance": "env:MISSKEY_INSTANCE", // misskey instance
119 "token": "env:MISSKEY_TOKEN", // access token with the `View your account information` scope
120 "options": {
121 "allowed_visibility": [
122 "public",
123 "home"
124 ]
125 }
126}
127```
128
129Misskey API is not very good, this also wasn't tested on vanilla misskey.
130
131confirmed supported:
132- Sharkey
133
134## Outputs
135
136### Mastodon API
137
138no remarks.
139
140```json5
141{
142 "type": "mastodon",
143 "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%20write%20profile but doesn't work with all software
144 "instance": "env:MASTODON_INSTNACE", // mastodon api compatible instance
145 "options": {
146 "visibility": "public"
147 }
148}
149```
150
151### Bluesky
152
153in 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.
154
155```json5
156{
157 "type": "bluesky", // type
158 "handle": "env:BLUESKY_HANDLE", // handle (e.g. melontini.me)
159 "app_password": "env:BLUESKY_APP_PASSWORD", // https://bsky.app/settings/app-passwords
160 "did": "env:BLUESKY_DID", // use a DID instead of handle (avoids handle resolution)
161 "pds": "env:BLUESKY_PDS", // specify Your PDS directly (avoids DID doc lookup)
162 "bsky_appview": "env:BLUESKY_APPVIEW", // bypass suspensions by specifying a different appview (e.g. did:web:bsky.zeppelin.social)
163 "options": {
164 "encode_videos": true, // bluesky only accepts mp4 videos, try to convert if the video is not mp4
165 "quote_gate": false, // block users from quoting the post
166 "thread_gate": [ // block replies. leave empty to disable replies
167 "mentioned",
168 "following",
169 "followers",
170 "everybody" // allow everybody to reply (ignores other options)
171 ]
172 }
173}
174```