Package: mastoposter
mastoposter - easy-to-use mastodon-to-[everything] reposterMastoposter is a simple zero-headache* service that forwards your toots from any
Mastodon-compatible Fediverse software (Pleroma also works**!) to any of your
other services! For now it supports only Discord webhooks and Telegram, but it
can be easily extended to support pretty much anything!InstallationVia pipSince recently we have package published to pip (thanks to@cybertailor@deadinsi.defor adding
pyproject file), so now you can just do the following:pipinstallmastoposterNote that you would still have to clone repository to build a Docker image.Old wayYou can run it either on your host machine, or inside a Docker container.
In any case, you have to clone that repo first in order to do anything:gitclonehttps://github.com/hatkidchan/mastoposter&&cdmastoposterAfter that, you can either run it in Docker, set up a standalone systemd
service, or just run it as it is!Dockerdockerbuild-tmastoposter.
dockerrun-d\--restart=unless-stopped\-v/path/to/config.ini:/config.ini:ro\--namemastopostermastoposterAnd you should be good to goSystemdLet's say that you've cloned that repo to the$MASTOPOSTER_ROOT, then
configuration should look something like that:[Unit]Description=Crossposter from MastodonAfter=network.target[Service]Type=simpleUser=$MASTOPOSTER_USERExecStart=/usr/bin/python3 -m mastoposter config.iniWorkingDirectory=$MASTOPOSTER_ROOTRestart=on-failure[Install]WantedBy=network.targetBefore running it though, don't forget to install dependencies from the
./requirements.txt, but it's a good idea to use a virtual environment for that.
Though, that's outside of the scope of that, so I won't cover it here.Running manuallyJust be in the folder with it, have dependencies installed and run:python3-mmastoposterconfig.iniConfigurationConfiguration file is just a regular INI file with a couple sections.Configuration wizard is still in progress, but we have a couple examples for
common use-cases. If you have troubles configuring it yourself, you could
either use discussions feature, or ask me on Fedi directly (links on profile).[main]Sectionmaincontains settings of your account (ie, your instance, list ID,
user ID, access token), as well as list of modules to load.instanceThis is your instance. It should be written without thehttps://part, so,
for example,mastodon.social.tokenThis is your access token.On Mastodon, you can acquire it by creating an application with the minimum ofread:statusesandread:listspermissions.On Pleroma you're out of luck and have to manually lure your token out of the
frontend you're using. For example, in Pleroma FE you can look in the "Network"
tab of the devtools and look forchatsrequest. Inside the request headers,
there should beAuthorization: Bearer XXXXXXXXXXXheader. That's your token.userIt's still not properly tested, but you could just leave it asautofor now.In case it fails, on Mastodon you can get your user ID by looking at your
profile picture URL. The part between "/avatars/" and "original/" without all of
the slashes is your user ID.On Pleroma you're out of luck again, I don't remember how I got mine. Just hope
that "auto" will work, lol.listThat's the main problem of this crossposter: it requires a list to be created
to function properly. Both Pleroma and Mastodon support them, so it shouldn't be
a big deal. Just create a list, add yourself into it and copy its ID (it should
be in the address bar).List is required to filter incoming events. You can't just listen for home
timeline 'cause some events are not guaranteed to be there (boosts at least).auto-reconnectYou can set it to eitheryesorno. When set toyes, it will reconnect
on any websocket error, but not on any error related to modules (even if it's a
connection error!!!)modulesMore about them laterloglevelSelf-explanatory, logging level. Can be eitherDEBUG,INFO,WARNINGorERROR. Defaults toINFOModulesThere's two types of modules supported at this point:telegramanddiscord.
Both of them are self-explanatory, but we'll go over them real quick.Each module should contain at leasttypeproperty and its name should start
with themodule/.filtersfield is also can be specified. Check the
corresponding section to learn more about them.To use module, add it to themodulesfield in themainsection. It should
not have themodule/prefix since it's always there. You can use multiple
modules and separate them using spaces.type = telegramModule with that type will work in Telegram mode.
It requires your Bot token to be set in thetokenfield, as well aschatto be set with your chat ID. You can use@usernameif the chat is public.
Also there's asilentfield, when it's set totrue, it'll setdisable_notificationflag on every post sent.templatefield contains your template for the message. It's pretty much
Jinja2 template. Since we useparse_mode=html, yourtemplateshould be
formatted appropriately. Template itself has onlystatusvariable exposed,
which contains the status/post/toot itself. There's also some handy properties
such asreblog_or_statuswhich points to either reblog, or status itself. Orname_emojilesswhich contains the name without emojis. Ornamewhich
contains eitherdisplay_nameorusername, if first one is empty.type = discordModule for Discord webhooks. The only required parameter (besides thetype) iswebhook. Itshouldhavewait=trueset. You can also usethread_idas a
GET parameter to that. You also can use filters, nothing special about that.FiltersFilters are the most powerful feature of this crossposter. They allow you to...Filter out where posts should and shouldn't go! It's that easy!There's a couple of filters with different types and options, but all of them
should be contained in sections with names starting withfilter/, as well
as have atypefield with filter type.Also, you can specify multiple filters and they'll be chained together using
AND operator. You can also prefix filter name with either~or!to invert
its behavior.type = boostSimple filter that passes through posts that are boosted from someone.It also has an optionallistproperty where you can specify the list of
accounts to check from. You can use globbing, but be aware, that it usesfnmatchfunction to glob stuff, so@*doesn't mean "any local user", but
rather it means "any user". NOTE that his behavior is not intended and may be
changed to more appropriate one later. Iflistis empty, any boost will
trigger that filter. If list is not empty, it will allow only users from that
list.type = mentionThis filter is kinda similar to theboostone, but works with mentions.
Also haslistproperty, yada yada you got the idea, same deal with fnmatch.type = spoilerMatches posts with spoilers/content-warnings.Has an optionalregexpparameter that will allow you to specify regular
expression to match your spoiler text.type = contentFilter to match post content against either a regular expression, or a list of
tags. Matching is done on the plaintext version of the post.You can have one of two properties (but not both because fuck you):tagsorregexp. It's obvious what does what: if you haveregexpset, plaintext
version of status is checked against that regular expression, and if you havetagsset, then only statuses that have those tags will be allowed.Please note that in case of tags, you should NOT use#symbol in front of
them.type = visibilitySimple filter that just checks for post visibility.
Has a single propertyoptionsthat is a space-separated list of allowed
visibility levels. Note thatdirectvisibility is always ignored so cannot
be used here.type = mediaFilter that allows only some media types to be posted.valid_mediais a space-separated list of media types from Mastodon API
(image,gifv,video,audioorunknown). If your Fedi software has
support for other types, they also should work.modeoption defines the mode of operation: it can be eitherinclude,excludeoronly. In case ofinclude, filter will trigger when post
has media with that type, but others are allowed as well.excludeis the
opposite: if status has media with that type, filter won't trigger.onlyallows statuses with either no media, or listed types only.type = combinedThe most powerful filter 'cause it allows you to combine multiple filters using
different operations.filtersoption should contain space-separated list of filters. You also can
negate them using!or~prefixes.operatoris a type of operation to be used. Can be eitherall,anyorsingle.allmeans that all of the filters should be used.anymeans
that if any filter is triggered, this one will also trigger.singlemeans
that only one filter should be triggered. Think of it as an XOR operation of
some sort.Sample configurationsFor Telegram[main]modules=tginstance=expired.mentality.riptoken=haha-nolist=42user=auto[module/tg]type=telegramtoken=12345:blahblahblahchat=12345For Telegram with a separate shitpost channel[main]modules=tg tg-shitpostinstance=expired.mentality.riptoken=haha-nolist=42user=auto[module/tg]type=telegramtoken=12345:blahblahblahchat=12345filters=!shitpost[module/tg-shitpost]type=telegramtoken=${module/tg:token}chat=@shitpostingfilters=shitpost[filters/shitpost]type=contentmode=tagtags=shitpostAsterisksWell, most of the time that is.Works only when it has lists support.