No description
  • Python 98.8%
  • Dockerfile 1.2%
Find a file
2025-08-27 18:49:10 +07:00
bluesky run a formatter 2025-08-27 18:49:10 +07:00
mastodon run a formatter 2025-08-27 18:49:10 +07:00
misskey run a formatter 2025-08-27 18:49:10 +07:00
util run a formatter 2025-08-27 18:49:10 +07:00
.gitignore add .idea to .gitignore 2025-06-07 17:51:25 +07:00
.python-version god, this sucks 2025-06-04 21:41:00 +07:00
Containerfile remove targetplatform as we're not using docker buildx 2025-07-11 19:53:29 +07:00
Containerfile-alpine add alpine container 2025-08-10 23:52:50 +07:00
cross.py run a formatter 2025-08-27 18:49:10 +07:00
LICENSE add license and refactor websockets a bit 2025-06-06 20:18:55 +07:00
main.py run a formatter 2025-08-27 18:49:10 +07:00
pyproject.toml fix: remove bs4 2025-08-03 17:31:04 +07:00
README.md update docs a bit 2025-08-09 02:18:38 +07:00
uv.lock fix: remove bs4 2025-08-03 17:31:04 +07:00

XPost

put more readme here uhhh

a silly little crossposting tool based on the mastodon streaming api.

this tool is very, very not production ready or something. use with caution.

Installation

Native

first install ffmpeg, ffprobe and libmagic, make sure that ffmpeg is available on PATH! ffmpeg and libmagic are required to crosspost media.

then get uv and sync the project

uv sync

generate settings.json on first launch

uv run main.py

Docker Compose

atm the image must be built locally. this can be done like this:

git clone https://tangled.sh/@melontini.me/xpost xpost
cd xpost
docker build -t melontini/xpost:latest -f Containerfile .

for podman:

podman build --security-opt label=disable -t melontini/xpost:latest -f Containerfile .

example compose.yaml. this assumes that data dir is ./data, and env file is ./.config/docker.env. add :Z to volume mounts for podman.

services:
  xpost:
    image: melontini/xpost:latest
    restart: unless-stopped
    env_file: ./.config/docker.env
    volumes:
      - ./data:/app/data

Settings

the tool allows you to specify an input and multiple outputs to post to.

some options accept a envvar syntax:

{
    "token": "env:TOKEN"
}

Inputs

all inputs have common options.

{
    "options": {
        "regex_filters": [ //posts matching any of the following regexes will be skipped
            "(?i)\\b(?:test|hello|hi)\\b"
        ]
    }
}

Bluesky Jetstream

listens to repo operation events emmited by Jetstream. handle becomes optional if you specify a DID.

{
    "type": "bluesky-jetstream-wss",
    "handle": "env:BLUESKY_HANDLE", // handle (e.g. melontini.me)
    "did": "env:BLUESKY_DID", // use a DID instead of handle (avoids handle resolution)
    "jetstream": "wss://jetstream2.us-east.bsky.network/subscribe" //optional, change jetstream endpoint
}

Mastodon WebSocket mastodon-wss

listens to the user's home timeline for new posts, crossposts only the public/unlisted ones by the user.

{
    "type": "mastodon-wss", // type
    "instance": "env:MASTODON_INSTANCE", // mastodon api compatible instance
    "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
    "options": {
        "allowed_visibility": [
            "public",
            "unlisted"
        ]
    }
}

any instance implementing /api/v1/instance, /api/v1/accounts/verify_credentials and /api/v1/streaming?stream will work fine.

confirmed supported:

  • Mastodon
  • Iceshrimp.NET
  • Akkoma

confirmed unsupported:

  • Mitra
  • Sharkey

Misskey WebSocket

listens to the homeTimeline channel for new posts, crossposts only the public/home ones by the user.

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.

{
    "type": "misskey-wss", // type
    "instance": "env:MISSKEY_INSTANCE",  // misskey instance
    "token": "env:MISSKEY_TOKEN", // access token with the `View your account information` scope
    "options": {
        "allowed_visibility": [
            "public",
            "home"
        ]
    }
}

Misskey API is not very good, this also wasn't tested on vanilla misskey.

confirmed supported:

  • Sharkey

Outputs

Mastodon API

no remarks.

{
    "type": "mastodon",
    "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
    "instance": "env:MASTODON_INSTNACE", // mastodon api compatible instance
    "options": {
        "visibility": "public"
    }
}

Bluesky

in 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.

{
    "type": "bluesky", // type
    "handle": "env:BLUESKY_HANDLE", // handle (e.g. melontini.me)
    "app_password": "env:BLUESKY_APP_PASSWORD", // https://bsky.app/settings/app-passwords
    "did": "env:BLUESKY_DID", // use a DID instead of handle (avoids handle resolution)
    "pds": "env:BLUESKY_PDS", // specify Your PDS directly (avoids DID doc lookup)
    "bsky_appview": "env:BLUESKY_APPVIEW", // bypass suspensions by specifying a different appview (e.g. did:web:bsky.zeppelin.social)
    "options": {
        "encode_videos": true, // bluesky only accepts mp4 videos, try to convert if the video is not mp4
        "quote_gate": false, // block users from quoting the post
        "thread_gate": [ // block replies. leave empty to disable replies
          "mentioned",
          "following",
          "followers",
          "everybody" // allow everybody to reply (ignores other options)
        ]
    }
}