Blogger Auto Poster
Zweck
Dieses Projekt ist entstanden, um aus vielen vorhandenen lokalen Projekten automatisch strukturierte Markdown-Dateien zu machen und daraus eine Blogger-Queue für klautesblog.blogspot.com aufzubauen. Die Dateien sollen nicht direkt blind veröffentlicht werden, sondern zuerst als geparkte Markdown-Posts im Backlog vorliegen. Danach kann ein Linux-Server in einem festen Intervall jeweils den nächsten Post aus der aktiven Queue hochladen.
Das eigentliche Ziel ist nicht nur ein Upload-Script. Der wichtige Teil ist der Workflow davor: Ein Workspace wird rekursiv analysiert, Projekte werden fachlich eingeordnet, uninteressante Dateien werden ausgeschlossen, relevante Projekte bekommen Story, Ziel, Labels und ein sauberes Markdown-Format.
Ausgangslage
In meinem Entwicklungsordner lagen viele kleine und größere Projekte: Smart-Home-Energiemanagement, Aquarium-Technik, Amateurfunk-Hardware, Homebridge-Integrationen, ESP32/ESP8266-Hacks, alte Software-Fixes und Tabletop-/Mordheim-Material.
Viele dieser Projekte waren technisch interessant, aber nicht direkt als Blogpost nutzbar. Es fehlte eine einheitliche Struktur:
- Was war das Problem?
- Warum wurde das Projekt angefangen?
- Was war das konkrete Ziel?
- Welche Hardware und Software gehören dazu?
- Ist das Projekt wirklich postbar?
- Welche Labels passen später in Blogger?
- Welche Dateien sollen ignoriert werden?
Grundidee
Der Ablauf besteht aus zwei getrennten Schritten:
- Codex analysiert den Workspace und erzeugt Markdown-Dokumentation.
- Der Blogger Auto Poster nimmt freigegebene Markdown-Dateien und lädt sie in festen Intervallen zu Blogger hoch.
Diese Trennung ist wichtig. Die Analyse darf ruhig interaktiv sein, weil Projektkontext oft nur im Kopf vorhanden ist. Der Upload soll dagegen langweilig und deterministisch laufen.
Prompt 1: Workspace rekursiv analysieren
Der erste Prompt beschreibt den Analyseauftrag. Er soll nicht sofort posten und auch keine Projektdateien verändern, sondern nur Dokumentation erzeugen.
Analysiere den aktuell geöffneten Workspace rekursiv.
Ziel:
- Finde alle relevanten Projekte.
- Erstelle pro Projekt eine Markdown-Datei im Ordner output/.
- Ändere keine bestehenden Projektdateien.
- Poste nichts automatisch.
- Beschreibe Zweck, Hardware, Software, Aufbau, Build, Konfiguration,
Verwendung, Schnittstellen, Stolpersteine und offene Punkte.
- Kennzeichne Unsicherheiten klar.
- Dokumentiere keine Secrets, Tokens, privaten IPs oder Passwörter.
Damit entsteht zuerst eine technische Rohdokumentation. Sie ist noch kein fertiger Blogpost, aber sie macht sichtbar, welche Projekte es überhaupt gibt.
Prompt 2: Projekte fachlich bewerten
Danach folgt die Frage, welche Dateien für einen Blog interessant sind. Dabei geht es nicht um perfekte Texte, sondern um eine harte Vorauswahl.
Prüfe alle erzeugten Markdown-Dateien.
Ziel:
- Welche Dateien sind als einzige Posts auf klautesblog.blogspot.com interessant?
- Welche passen zu einem technischen Blog?
- Welche sind eher nicht interessant?
- Nichts posten und nichts extern ändern.
- Liste klar auf, welche Dateien passen und welche nicht.
- Die Story dahinter darf noch fehlen; das ist ein eigener Schritt.
Dieser Schritt trennt technische Artefakte von echten Blog-Kandidaten.
Prompt 3: Upstream-Projekte und Quellen prüfen
Viele kleine Projekte basieren auf fremden GitHub-Repositories, Schaltplänen, YouTube-Videos oder bestehenden Bibliotheken. Das muss sauber in die Dokumentation.
Prüfe bei welchen Projekten ein bestehendes Projekt eines anderen
auf GitHub oder eine andere externe Quelle als Basis genommen wurde.
Wenn das in der Dokumentation fehlt:
- Ergänze einen Hinweis auf Basis/Upstream.
- Mache klar, was eigenes Projekt ist und was nicht.
- Verlinke das Original, wenn es erkennbar ist.
- Ändere nur die erzeugten Dokumentationsdateien.
Das ist wichtig, weil ein Blogpost sonst schnell so wirkt, als sei alles komplett selbst entwickelt worden.
Prompt 4: Entstehung und Ziel interaktiv ergänzen
Die technische Analyse allein reicht nicht. Ein Projekt wird erst durch die Entstehungsgeschichte interessant.
Frage mich zu jedem relevanten Projekt:
- Warum habe ich dieses Projekt angefangen?
- Welches konkrete Problem sollte gelöst werden?
- Was war das Ziel?
- Was ist das Ergebnis oder der aktuelle Status?
Füge diese Angaben in die jeweilige Markdown-Datei im output-Ordner ein.
Ein Beispiel dafür ist PowerMgr.
Beispiel: PowerMgr
Die reine Codeanalyse erkennt ein Python-/Docker-Projekt für Energiemanagement. Der wichtige Blogwert steckt aber in der Geschichte dahinter:
- Es sollte ein Energiemanagement entstehen, das vorhandene Geräte weiter nutzt.
- Eingebunden wurden unter anderem StecaGrid-PV-Wechselrichter, Zimmermann Proxon FTW-2, Shelly-Geräte, DIY-Wetterstation, OpenWeather, ESP32-Geräte und EVCC.io.
- Angebote von Ingenieurbüros lagen bei etwa 15.000 bis 25.000 EUR für einen Umbau des Hauses.
- Das eigene System bindet einen Victron Multiplus ein.
- Ergebnis: etwa 50 Prozent weniger Stromkosten und etwa 70 Prozent Eigenverbrauch der PV-Erzeugung.
Aus einer technischen Datei wird dadurch ein nachvollziehbarer Artikel: Problem, Eigenbau, Integration, Ergebnis.
Prompt 5: Ignorierte Projekte verschieben
Nicht alles soll in die Blogqueue. Manche Projekte waren nur Tests, Sackgassen oder reine Fremdsoftware.
Alles, was ich als "ignorieren" markiert habe,
verschiebe in output/ignore.
Diese Dateien sollen erhalten bleiben, aber nicht als Blogpost-Kandidaten gelten.
Im Auto-Poster bleibt dieser Mechanismus erhalten: posts/queue/ignore/ wird vom Upload-Script übersprungen.
Prompt 6: Neues Auto-Poster-Projekt erzeugen
Aus der analysierten Dokumentation wurde danach ein eigenes Projekt gebaut.
Erstelle ein neues Projekt für einen Blogger Auto Poster.
Anforderungen:
- Dockerfile
- docker-compose.yml
- Upload-Script
- Config-Datei für Blogger und Input-Ordner
- Shared Input-Folder im Docker Compose Setup
- Post-Intervall in der Config
- Bereits erledigte Markdown-Dateien nach done/ verschieben
- output-Ordner in das neue Projekt verschieben und umbenennen
- Neues Git-Repository initialisieren
- Markdown-Dateien mit Labels und sauberem Post-Format vorbereiten
Das Ergebnis ist dieses Repository.
Umsetzung im Projekt
Aus dem ersten Upload-Script ist inzwischen ein kleines, klar getrenntes Tooling-Projekt geworden. Die wichtigste Änderung ist die Aufteilung nach Verantwortlichkeiten: Benutzereingabe, Markdown-Logik, Blogger-API, lokale State-Datei, Zeitplanung und Docker-Runtime liegen nicht mehr vermischt in einem Script.
Der nachbaubare Stand des Tools liegt öffentlich auf GitHub: klaute/blogger-auto-poster.
Dieses öffentliche Repository enthält nur das Tooling, eine Beispielkonfiguration, einen neutralen Beispielpost und die Setup-Anleitung. Die echten Blogpost-Entwürfe, lokale State-Dateien, OAuth-Konfigurationen und Tokens bleiben im privaten Arbeitsverzeichnis.
Die aktuelle Projektstruktur sieht so aus:
config/
config.example.yml
posts/
queue/
backlog/
ignore/
done/
failed/
order.txt
scripts/
update-venv.sh
load-venv.sh
get_blogger_token.py
extract-refresh-key.py
diagnose-oauth-config.py
manage-posts.py
build-and-verify.sh
test-blogger-config.sh
src/
config.py
markdown_posts.py
state.py
scheduling.py
notifications.py
blogger_api.py
posting_runtime.py
post_management.py
blogger_auto_poster.py
prepare_posts.py
Dockerfile
docker-compose.yml
requirements.txt
Die Aufteilung ist bewusst pragmatisch:
scripts/manage-posts.pyist nur die interaktive Bedienung.src/markdown_posts.pykennt Markdown, Frontmatter, Labels und HTML-Erzeugung.src/blogger_api.pykapselt OAuth und Blogger-API-Aufrufe.src/posting_runtime.pyenthält den automatischen Posting-Zyklus.src/post_management.pyenthält manuelle Aktionen wie aktualisieren, offline nehmen oder veröffentlichen.src/state.pyverwaltet die lokale Tracking-Datei.src/notifications.pykümmert sich um Pushover.src/blogger_auto_poster.pyist nur noch der CLI-Einstieg für den Container und Kompatibilitäts-Exports.
Markdown-Queue
posts/queue/ enthält die aktiven Markdown-Dateien, die der Server verarbeiten darf. posts/queue/backlog/ enthält geparkte Entwürfe, die der Server ignoriert, die aber vom Management-Script bewusst ausgewählt werden können. posts/queue/ignore/ enthält Dateien, die erhalten bleiben, aber nicht automatisch gepostet werden.
Jede Markdown-Datei hat Frontmatter:
---
title: "PowerMgr"
labels:
- Smart Home
- Energie
- PV
---
Die Freigabe ist absichtlich einfach und erfolgt über Ordner:
posts/queue/: aktiv, darf vom Server verarbeitet werden.posts/queue/backlog/: geparkt, wird vom Server nicht automatisch verarbeitet, kann aber vom Management-Script ausgewählt werden.posts/queue/ignore/: ignoriert oder Rohmaterial.
Nach erfolgreichem Upload wandert die Datei nach posts/done/. Fehlerhafte Dateien, die nicht gelesen werden können, wandern nach posts/failed/. Der lokale Upload-Status wird zusätzlich in posts/state.json gespeichert.
Wichtig ist die Trennung zwischen lokaler Datei und Blogger-Post: posts/done/ bedeutet nur, dass die Markdown-Datei lokal bereits verarbeitet wurde. Der Eintrag kann mit einem Blogger-Post verknüpft sein, muss es aber nicht mehr sein, wenn der Post auf Blogger gelöscht wurde oder nicht mehr auffindbar ist.
Labels
Labels werden direkt in die Markdown-Dateien geschrieben. Dadurch ist jede Datei für sich vollständig. Das Upload-Script muss nicht raten, welcher Post welche Kategorien braucht.
Die Config enthält keine Label-Regeln. Bestehende Labels können über das Management-Script aus Blogger als Referenz gelesen werden. Vor echten Blogger-Schreibzugriffen gleicht das Tool die Schreibweise der lokalen Labels mit den vorhandenen Blogger-Labels ab. Neue Labels sind erlaubt, werden aber im Log als neu ausgewiesen.
Zusätzlich haben automatisch erzeugte Dateien das Label KI generiert. Damit bleibt im Blog nachvollziehbar, welche Artikel aus diesem Dokumentationsworkflow stammen.
Upload-Zyklus
Der Auto-Poster läuft im Container. In der Config steht das Intervall:
posting:
interval_seconds: 604800
604800 Sekunden sind eine Woche. Wenn ein Post fällig ist, nimmt das Script die nächste Datei direkt aus posts/queue, wandelt Markdown nach HTML, setzt Titel und Labels und legt den Post über die Blogger API an. Die Reihenfolge kommt aus posts/order.txt; Dateien, die dort nicht stehen, folgen alphabetisch nach Dateiname.
Dabei wird ein unsichtbarer Tracking-Kommentar in den Blogger-Post geschrieben. Dadurch kann das Tool einen vorhandenen Blogger-Post später wiederfinden und aktualisieren, statt versehentlich einen zweiten Post zu erzeugen.
Sicherheitsmodus
Initial ist der Auto-Poster auf Dry-Run gestellt:
posting:
dry_run: true
publish_mode: "draft"
So kann man prüfen, welcher Post als nächstes hochgeladen würde, ohne Blogger zu verändern. Für den echten Betrieb wird dry_run auf false gesetzt. publish_mode: draft ist die vorsichtige Variante, weil Blogger dann nur Entwürfe erzeugt.
Für geplante Veröffentlichung gibt es zusätzlich:
posting:
dry_run: false
due_mode: "weekly_schedule"
publish_mode: "scheduled"
schedule:
weekday: "friday"
time: "09:00"
timezone: "Europe/Berlin"
Damit prüft der Container regelmäßig die Queue, startet echte Uploads aber nur am eingestellten Wochentag zur eingestellten Uhrzeit.
Blogger OAuth
Der Auto-Poster loggt sich nicht mit Benutzername und Passwort bei Blogger ein. Er nutzt die offizielle Blogger API über Google OAuth 2.0.
Die lokale Einrichtung besteht aus drei Teilen:
credentials.json: OAuth-Client-Datei aus Google Cloud, bleibt lokal und wird nicht committed.config/config.yml: lokale Runtime-Config mit Blog-ID, Client-ID, Client-Secret und Refresh-Token.config/config.example.yml: versioniertes Beispiel ohne echte Secrets.
Der wichtigste Stolperstein war der Unterschied zwischen Authorization Code und Refresh Token. Die Callback-URL aus dem Browser enthält einen temporären code=... Wert. Dieser Code gehört nicht in die Config. Er muss erst gegen einen echten Refresh Token getauscht werden.
Dafür gibt es zwei Helper:
scripts/get_blogger_token.py
scripts/extract-refresh-key.py
get_blogger_token.py ist der normale Weg, wenn der Browser auf demselben System geöffnet werden kann. extract-refresh-key.py ist für den Server-Fall gedacht: Die Google-Login-URL kann auf einem anderen Rechner geöffnet werden, die komplette Callback-URL wird danach in das Script kopiert. Das Script tauscht den Code gegen einen Refresh Token und aktualisiert die lokale Config.
Zur Prüfung gibt es:
scripts/test-blogger-config.sh --software
scripts/test-blogger-config.sh --oauth
scripts/test-blogger-config.sh --blogger-draft
Der Software-Test prüft die Modulstruktur, Python-Syntax, CLI-Einstiegspunkte und den manuellen Update-Pfad ohne Blogger-Schreibzugriff.
Der Draft-Test erzeugt einen temporären Blogger-Entwurf, prüft die API-Antwort und löscht den Entwurf danach wieder. Er lädt keinen Markdown-Artikel aus der Queue hoch. Wenn das erfolgreich ist, funktionieren Token, Scope, Blog-ID und Schreibrechte.
Lokale Python-Umgebung
Für lokale Python-Scripte gibt es ein venv-Setup:
scripts/update-venv.sh
. scripts/load-venv.sh
update-venv.sh baut .venv neu auf, installiert requirements.txt und prüft die lokalen Python-Einstiegspunkte. load-venv.sh muss mit führendem Punkt geladen werden, weil ein normales Shell-Script die aufrufende Shell nicht dauerhaft aktivieren kann.
Pushover Benachrichtigungen
Der Auto-Poster kann vor echten Blogger-Schreibzugriffen und bei Fehlern Pushover-Nachrichten senden. Dabei wird nicht direkt die Pushover-API aus dem Container angesprochen, sondern der interne Pushover-Proxy aus dem eigenen Pushover-Server-Projekt.
Die Config sieht dafür vereinfacht so aus:
notifications:
pushover:
enabled: true
host: "pushover-app-server"
port: 8090
mode: "get"
token: "PUSHOVER_APP_TOKEN"
app_name: "Blogger Auto Poster"
dedupe_prefix: "blogger-auto-poster"
Das entspricht dem vorhandenen Pushover-Proxy-Vertrag: ein HTTP-Aufruf auf /send mit Token, Titel, Nachricht und optionalem dedupe_key. Der Dedupe-Key verhindert doppelte Nachrichten bei wiederholten Tests oder Retry-Situationen.
Benachrichtigt wird unter anderem bei:
- echtem Uploadversuch als Draft, Live-Post oder geplanter Post
- Update eines bestehenden Blogger-Posts
- Fehler im Posting-Zyklus
- fehlgeschlagenem Blogger-Draft-Test
- nicht lesbarer Markdown-Datei, die nach
failedverschoben wurde
Auch Pushover wird über das Testscript geprüft:
scripts/test-blogger-config.sh --pushover
Ohne Parameter führt das Testscript den kompletten Check aus: Container vorhanden, Dry-Run, OAuth, Pushover und temporärer Blogger-Draft.
Management-Script
Für den normalen Betrieb reicht der Container. Für manuelle Arbeit an der Queue gibt es zusätzlich ein interaktives Management-Script:
scripts/manage-posts.py --config config/config.yml
Das Script listet die verfügbaren Markdown-Dateien aus posts/queue und posts/done mit Titel und Labels. Dateien im Backlog bleiben absichtlich unsichtbar, damit geparkte Entwürfe nicht versehentlich hochgeladen werden.
Bei done Dateien zeigt das Script zusätzlich, ob der lokale Artikel linked oder not linked ist. linked bedeutet: In posts/state.json ist eine Blogger-Post-ID bekannt. not linked bedeutet: Die Markdown-Datei liegt zwar lokal in done, aber das Tool kennt keinen aktuellen Blogger-Post dazu.
Danach können die wichtigsten Wartungsaktionen direkt ausgeführt werden:
- Einen ausgewählten Queue-, Backlog- oder Done-Post mit dem konfigurierten
publish_modehochladen oder aktualisieren. - Einen Blogger-Post offline nehmen, also zurück auf Draft setzen, ohne ihn zu löschen.
- Einen Blogger-Draft direkt veröffentlichen.
- Einen bestehenden Blogger-Post jetzt aktualisieren.
- Blogger-Status und die Verknüpfung
lokale Datei -> Blogger post idanzeigen. - Die aktuell auf Blogger vorhandenen Labels anzeigen.
- Einen Backlog-Post nur aktivieren, aber noch nicht hochladen.
- Einen bereits erkannten Blogger-Post löschen.
Die Aktionen zum Offline-Schalten, Veröffentlichen, Aktualisieren, Statusanzeigen und Löschen brauchen eine bestehende Blogger-Verknüpfung. Ein not linked Artikel kann dafür nicht verwendet werden, weil keine Blogger-Post-ID vorhanden ist. Für einen neuen Upload eines not linked Artikels ist Aktion 1 zuständig.
Aktion 1 ist der normale Weg für neue Uploads, Reuploads und Updates. Das Script zeigt aktive Queue-Dateien, Done-Dateien mit oder ohne Blogger-Verknüpfung und Backlog-Dateien an. Eine verknüpfte Done-Datei wird direkt als bestehender Blogger-Post aktualisiert. Eine nicht verknüpfte Done-Datei wird als neuer Blogger-Post hochgeladen und danach neu in posts/state.json verknüpft. Eine Backlog-Datei wird zuerst auf Blogger geschrieben. Wenn es bereits eine lokale Blogger-Verknüpfung für diese Quelle gibt, wird der bestehende Blogger-Post aktualisiert. Erst nach erfolgreichem Blogger-Write wird eine gleichnamige lokale Datei aus posts/done/ nach posts/done/archive/ archiviert und die Backlog-Datei nach posts/done/ verschoben. Wenn die lokal gespeicherte Blogger-ID auf Blogger nicht mehr existiert und Blogger 404 zurückgibt, erstellt Aktion 1 den Post neu und speichert die neue Blogger-ID.
Aktion 7 ist nur noch für den Sonderfall gedacht, dass ein Backlog-Artikel zwar in die aktive Queue verschoben werden soll, aber der Upload später durch den Server oder einen separaten manuellen Lauf passieren soll.
Wenn derselbe Artikel lokal in mehreren Ordnern liegt, gruppiert Aktion 1 diese Kopien über die source_id und zeigt nur die aktive Kopie an. Die Reihenfolge ist posts/queue/, dann posts/queue/backlog/, dann verknüpfte Dateien aus posts/done/. Dadurch verdeckt eine ältere Done-Kopie nicht mehr eine neuere Backlog-Bearbeitung.
Beim lokalen Aufruf übersetzt das Management-Script die Docker-Pfade aus der Config automatisch auf das Repository: /data/queue wird zu posts/queue, /data/done zu posts/done und /data/state.json zu posts/state.json. Damit kann dieselbe config/config.yml für Container und Host-Wartung verwendet werden. Wenn die Config-Pfade bewusst unverändert genutzt werden sollen, gibt es dafür --use-config-paths.
Damit muss man für typische Betriebsfälle keinen API-Aufruf von Hand bauen und keine Markdown-Datei manuell zwischen Backlog, Queue und Done kopieren. Ein gelöschter oder not linked Artikel wird über Aktion 1 aus dem Backlog neu aktiviert und hochgeladen.
Build, Start und Test
Der Server-Betrieb läuft über docker-compose:
scripts/build-and-verify.sh
Das Script baut das Image, startet den Container und führt einen sicheren Dry-Run aus.
Wenn der Container läuft, prüft das Post-Start-Testscript die Installation:
scripts/test-blogger-config.sh --all
Die Ausgabe ist als Checkliste aufgebaut: Preflight, Software-Selbsttest, Dry-Run, OAuth, Pushover und temporärer Blogger-Draft. Am Ende gibt es eine kompakte PASS/SKIP/FAIL-Zusammenfassung.
Warum das nützlich ist
Der größte Vorteil ist nicht die Automatisierung an sich. Der Vorteil ist, dass viele alte Projekte wieder sichtbar werden. Statt in alten Ordnern zu verschwinden, bekommen sie eine einheitliche Struktur, passende Labels und eine klare Entscheidung: aktiv posten, im Backlog parken oder ignorieren.
So kann aus einem gewachsenen Entwicklungsordner schrittweise ein technisches Blogarchiv entstehen.







