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```