[Cool Thing] Mein neues Autotweet/Autotoot Skript.

Wie in der Vergangenheit schonmal beschrieben lebt dieses Blog als ein Haufen Textfiles in einem Git repository. Wenn ich einen neues Post schreibe wird der zum Repo hinzugefügt, ein Commit erstellt und das ganze dann auf den Server gepusht, wo ein Git Hook dann schaut, ob es Zeit ist eine neue Version des Blogs zu bauen und zu veröffentlichen.

(Genauso ist übrigens auch der Prozess für das Webcomic.)

Schon vor einer Weile hab ich dann diesen Hook um ein Skript erweitert, daß mir semi-automatisch einen Tweet absetzt, wenn ein neuer Post gebaut wird. (Das “Semi-”, weil das Skript auf einen “Befehl” in der Commitmessage lauscht.) Und als ich dann angefangen hab Mastodon zu verwenden wurde es wieder erweitert, um auch dort einen Toot abzusetzen.

Und alles war gut. Ende.

...

Naja, nicht so ganz. Zum einen war das Skript jetzt lange Zeit super-messy und nicht sauber konfigurierbar. Zugangsdaten waren hardcoded im Quelltext, was ok war solange es nur mein Blog bediente und ich niemandem das Skript zeigen wollte, aber nachdem das gleiche Programm dann auch das Webcomic autotweeten sollte waren da auf einmal zwei Versionen des Programms die es zu warten gab.

Alles was am Programm gebastelt wurde musste in zwei Dateien parallel gemact werden und es war irgendwie ein Krampf. Noch dazu wusste ich ja, das es Scheiße war es so zu machen, aber ein Hack baut halt auf dem Anderen und bevor man noch “technical dept” sagen kann hat man ein Programm zusammengeschustert das läuft, aber man am liebsten garnicht mehr anschauen mag.

Es war also schon länger mal am Plan das Ding umzuschreiben: Code aufräumen, Konfiguration auslagern, mehr Features, etc. Letzteres war besonders motivierend seit ich angefangen hab hier auf dem Blog meine Glitchexperimente zu veröffentlichen, denn die hätte ich dann eigentlich auch gerne im Tweet/Toot drin gehabt.

Um diese viel zu lange Einleitung abzukürzen: Ich hab mich jetzt endlich hingesetzt und das ganze umgebaut! \o/

Autotweet/-toot

Die Grundfunktionalität des Skript ist supereasy. (Und das Skript dafür vermutlich eigentlich overengineered.)

  1. Holt es sich das RSS Feed meines Blogs und parsed da den letzten Post raus.
  2. Es schaut nach, ob im Blogpost irgendwo ein Bild verlinkt ist und speichert das.
  3. Dann packt es den Titel des Posts, einen Link zum Post und ggf. ein verlinktes Bild in einen Twitter/Mastodon Post und haut den über die passende API raus.

Gestartet wird dieses Skript immer von einem Post-Receive Hook des Remote Git Repos in dem mein Blog gespeichert wird. Dieser Hook schaut sich die letzte Commit Message an und führt danach dann gewissen andere Programme auf. (Pelican, um das Blog neu zu bauen, oder eben das Skript um Tweets zu schicken.)

Um das gleiche Skript sowohl für mein Blog als auch für Kexcomics verwenden zu können musste ich die Informationen wie API Zugangsdaten oder das RSS Feed in eine Konfigurationsdatei auslagern. Der Einfachheit halber hab ich mich hier für json entschieden, denn das kann Python von Haus aus, es liest sich einfach und es arbeitet sich angenehmer damit als mit Ini-Dateien. (IMO.)

autotweet.json

{
    "mastodon": {
        "clientfile": "Filepath to your Mastodon clients credential file",
        "userfile": "Filepath to your Mastodon User credential file."
    },
    "feed": "RSS/ATOM feed of your blog.",
    "twitter": {
        "CONSUMER_KEY": "Your Twitter Apps Consumer Key",
        "CONSUMER_SECRET": "Your Twitter Apps Consumer Secret",
        "OAUTH_SECRET": "The OAuth Secret of your Twitter User",
        "OAUTH_TOKEN": "The OAuth Token of your Twitter User"
    }
}

Wir haben hier also ein Dictionary mit den Keys "feed" (Der RSS Feed des Blogs/Webcomics.), sowie "twitter" und "mastodon", die jeweils wieder zwei dicts beinhalten. Dabei etwas unschön da asymetrisch ist, daß im "twitter" dict die Twitter-Api Zugangsdaten direkt drin stehen, während im "mastodon" dict Dateipfande zu den entsprechenden credential files für Client und User anzugeben sind. Das ist eigentlich ein Artefakt der Python Libraries die ich verwende, denn "Mastodon.py" macht es angenehmer mit den Dateien direkt zu arbeiten, während das in den "Python Twitter Tools" irgendwie mühsamer ist.

(Oder zumindest war es das, als ich es das letzte Mal machen wollte. Vielleicht ist das jetzt schon besser, mal schaun.)

autotweet.py

So, jetzt mal zum eigentlich Skript.

#!/usr/bin/env python
# coding: utf-8

"""\
Usage:
    autotweet [-hc CONFIG] [ tweet | toot | all ]

    -h --help   Print out this help message.
    -c FILE     Specify config file. [default: ./autotweet.json]
    tweet       Post to Twitter.
    toot        Post to Mastodon.
    all         Post to all configured sites.

"""

Das Skript beginnt mit einer Zeile Shebang die klarstellt, daß es sich hier um ein Pythonscript handelt, sowie dem Encoding.

Dann kommt ein Docstring, der Beschreibt wie man dieses Programm denn eigentlich verwendet. Zwei Flags, eins von drei Befehlen und gut ist. Soweit alles selbsterklärend.

(Das schöne an diesem Docstring ist, daß er, dank Docopt, auch gleich mein Kommandozeilenargumente spezifiziert und ich fast nix mehr selber machen muss. So schön. <\3)

Nachdem ich ein fauler Coder bin und es mir zuwider ist, das Rad neu zu erfinden verwende ich einige externe Libs. Die gilt es natürlich erst mal zu importieren.

import sys
import json
import feedparser
import docopt

from twitter import *
from mastodon import Mastodon
from bs4 import BeautifulSoup

import requests as r

sys und json sind in Python schon drin, der Rest ist externes Zeugs.

requests ist eine (die?) Python HTTP Lib und lädt mir hier im Skript die Bilder runter. (Ziemlicher Overkill eigentlich, aber naja, whatever.) mastodon und twitter, respektive Mastodon.py und Python Twitter Tools, sind für die Kommunikation mit den jeweiligen APIs zuständig und beide IMO sehr angenehm zu verwenden. docopt wurde weiter oben bereits erwähnt und feedparser ist ein Python Modul um ... feeds zu parsen. XD

Last but not least: bs4 steht hier für Beautiful Soup, mein Lieblingswerkzeug wenn es darum geht Informationen aus Webseiten rauszupopeln.

Es folgt dann ein ganzer Haufen an Funktionen ("Lade die Konfigdatei", "Hol dir das Feed", ...) gefolgt von dem üblichen if __name__ == "__main__" Bla und dann ein bißchen Programmlogik und das Ganze ist halbwegs kommentiert (Ok, die meisten Funktionen haben einen Docstring, aber das ist ja fast dasselbe... *hüstl*), darum will ich da eigentlich garnicht groß weiter drauf eingehen.

(Dieser Post ist eh schon viel zu lang und die Zeit wird knapp.)

Darum, zum Abschluß:

How to autotweet.py

Wer dieses Skript verwenden möchte (WHY?!?) kann sich als aller erstes Mal das git repo in dem es seit ner halben Stunde lebt ziehen. Darin enthalten ist das Skript, die oben beschriebene Beispielkonfig autotweet.json, ein etwas kurz gehaltenes README und eine requirements.txt Datei, mit der man via Pip die nötigen Libraries installieren kann.

Wie man die Zugangsdaten für die Twitter und Mastodon APIs bekommt entnimmt man am besten der Dokumentation für die verwendeten Module. (Links dazu im README.)

Falls wer Fragen dazu, zum Skript oder zu sonst irgendwas von dem ich vermeintlich eine Ahnung hab hat kann mich ja via Twitter, Mastodon oder Jabber pieksen.

Und jetzt gute Nacht.