anited. publish 2.0

Der eine oder andere hat sich vielleicht schon mal gefragt, welche Software ich für das Schreiben und insbesondere das Erzeugen von EBooks verwende.

Diese Frage hatte ich mir vor einigen Jahren auch gestellt und mir ein paar Alternativen angeschaut – keine davon war zufriedenstellend. Deshalb verwende ich seit geraumer Zeit meine eigene Software, anited. publish, die in den letzten Monaten für die anstehende Rückkehr zu AUS ein paar Updates erhalten hat.

Diese Updates habe ich zum Anlass genommen, anited. publish in Version 2.0 als Open Source Software auf gitlab.com zu veröffentlichen: https://gitlab.com/anited/publish

Dort gibt es auch die Dokumentation & Installationsanleitung.

Ein kurzer Ausflug in die Geschichte

Die ersten Seiten von AUS habe ich in Microsoft Word geschrieben und mit dem eingebauten Werkzeug nach PDF gewandelt. Microsoft Word eignet sich zum kreativen Schreiben ungefähr so, wie die aufgeschnittene Innenseite einer Kartoffel und was E-Reader wie der Kindle mit PDF machen, brauche ich wohl kaum erläutern.

Den zweiten Versuch startete ich in LaTeX. Für das Schreiben kann man hier jeden Texteditor verwenden, LaTeX ist schließlich ein reines Text- und eben kein Dateiformat wie .doc – aber LaTex ist primär immer noch ein Werkzeug für vorgegebene Seitengrößen, nicht für EBooks und außerdem viel zu kompliziert, wenn ich doch mal einfache Formatierungen brauchte. Aber hey, wenigstens hatten die entstandenen PDFs nun ordentliches Kerning.

Der dritte Versuch war ein Hybride aus Open Office und Calibre. Calibre ist eine Software von Kovid Goyal, die aus Dokumenten EBooks erzeugen kann.

Damit war ich schon mal näher dran, aber auf der einen Seite hatte Open Office hatte dieselben, ablenkenden Schwächen wie Word und andererseits nervte es mich, jedes mal aufwendig über die Benutzeroberfläche von Calibre zwei EBook-Formate per Hand erzeugen zu müssen. Calibre bietet zwar auch eine Kommandozeilenschnittstelle an, die ist aber recht umständlich und unübersichtlich zu bedienen.

Für eine Lösung musste also zweierlei her: 1. ein Textformat, das ich in jedem einfachen Texteditor schreiben kann ohne an eine aufgeblähte Software wie Word gebunden zu sein und 2. ein Weg diese Textinhalte plus ein paar Informationen zum Buch automatisch an die Kommandozeile von Calibre, ebookconvert, reichen zu können.

Textformat: Markdown to the rescue

Auf das passende Textformat stieß ich während meiner Arbeit als Software-Entwickler: Markdown

Markdown ist ein auf das Wesentliche reduziertes, extrem simples Format für reine Textdateien. Das Format würde für das Verfassen von Dokumentation für Software entwickelt und hat drei Ziele:

  1. jeder Laie muss dazu in der Lage sein, eine in Markdown verfasste Textdatei zu lesen – oder zu schreiben
  2. eine in Markdown verfasste Textdatei lässt sich in jedem Texteditor bearbeiten
  3. eine in Markdown verfasste Textdatei lässt sich mit einfachen Mitteln nach HTML übersetzen – weil die Dokumentation von Software nun mal häufig im Internet zur Verfügung gestellt wird

Die ersten beiden Ziele bilden meine Anforderung an das Textformat ab. Markdown ist wirklich extrem einfach. Ein Beispiel gefällig?

# Dies ist eine Überschrift.

Ein Absatz ist einfach... ein Absatz, also Text der durch zwei Zeilenumbrüche vom nächsten Absatz abgetrennt ist.

In etwa so. Hervorhebungen geschehen durch das Einrahmen mit *Sternchen* oder, für starke Hervorhebungen, mit **noch mehr Sternchen**.

Wenn man diesen Text mit einem der vielen Markdown-Programme nach HTML übersetzt, kommt in etwa das hier aus:


Dies ist eine Überschrift

Ein Absatz ist einfach… ein Absatz, also Text der durch zwei Zeilenumbrüche vom nächsten Absatz abgetrennt ist.

In etwa so. Hervorhebungen geschehen durch das Einrahmen mit Sternchen oder, für starke Hervorhebungen, mit noch mehr Sternchen.


Der gesamte Text von AUS ist inzwischen in einfachen Textdateien in Markdown verfasst.

Markdown hat allerdings auch ein paar Schwächen: Es sieht gewisse strukturelle Bausteine, wie sie ein Buch braucht, nicht vor. Zum Beispiel bietet es keinen Baustein für einen Seitenumbruch – wozu auch, das Internet kennt keine Seitenumbrüche im Sinne eines Buchs, Text nimmt sich einfach so viel Platz, wie er braucht, notfalls mit Scrollbalken.

anited. publish ist meine Lösung dafür und für die zweite Hälfte des ursprünglichen Problems: Aus dem Markdown muss irgendwie ein EBook werden und ich würde das Markdown gerne um beliebige Bausteine und Funktionen ergänzen können.

anited. publish

anited. publish ist ein Python-Package, welches eine Bauanleitung für ein Buch + Markdown-Textdateien mit dem Inhalt des Buchs entgegen nimmt und diese mithilfe der Kommandozeile von Calibre in beliebige EBook-Formate umwandelt.

Die Bauanleitung ist denkbar einfach. Es handelt sich wieder um eine reine Textdatei, diesmal aber YAML-Format. YAML ist ein beliebtes Format für ein Konfigurationsdateien weil es, wie Markdown für längere Texte, von Laien gelesen und geschrieben werden kann.

Hier ist als Beispiel die Bauanleitung für AUS:

title: AUS
series: vom Auf- und Untergang der Sterne
authors: Christopher Knörndel
language: de
publisher: anited.
cover: ../Ressourcen/cover/cover_2014_v2.jpg

chapters:
  - src: titlecards/title.md
  - src: 1.00-1.md
  - src: 1.01-der-bauernhof-im-wald.md
  - src: 1.02-hunger.md
  - src: 1.03-erste-hilfe.md
  - src: 1.04-gehdlingen.md
  - src: 1.05-der-erste-sturm.md
  - src: 1.06-kinder-gegen-knochen.md
  - src: 1.07-der-ueberfall-im-nebel.md
  - src: 1.08-kraefte.md
    publish: False

substitutions:
  # taunts:
  - pattern: \+\+(?P<text>.*?)\+\+
    replace_with: <span class="taunt">\g<text></span>
  # storyboard remover
  - pattern: ^\#\#\#\#(.*?)$
    replace_with: 
  # section delimiters --> maybe integrate into storyboards?
  - old: ---
    new: <p class="centered">* * *</p>
  # page break
  - old: <page-break>
    new: <div class="page-break"></div>

stylesheet: stylesheet.css

ebookconvert_params:
  - level1-toc=//h:h1
  - level2-toc=//h:h2
  - level3-toc=//h:h3
  - change-justification=left
  - page-breaks-before=//*[(name()='h1' or name()='h2') or (name()='div' and @class='page-break')]

outputs:
  # html for verification
  - type: html
    output: ../Output/html/aus.htm
  # epub
  - type: ebookconvert
    output: ../Output/ebook/AUS-full.epub
    ebookconvert_params:
      - preserve-cover-aspect-ratio
  # mobi
  - type: ebookconvert
    output: ../Output/ebook/AUS-full.mobi
    ebookconvert_params:
      - mobi-file-type=both

Lasst mich das von oben nach unten durchgehen.

title: AUS
series: vom Auf- und Untergang der Sterne
authors: Christopher Knörndel
language: de
publisher: anited.
cover: ../Ressourcen/cover/cover_2014_v2.jpg

Der erste Block direkt auf der obersten Ebene des Dokuments dient den Metadaten des Buchs – also dem Titel, Autor, welches Cover das Buch verwenden soll.

anited. publish unterstützt alle Metadaten, die ebookconvert unterstützt. Die vollständige Liste gibt es entsprechend nicht bei mir, sondern in der Dokumentation von Calibre:
https://manual.calibre-ebook.com/generated/en/ebook-convert.html#metadata

chapters:
  - src: titlecards/title.md
  - src: 1.00-1.md
  - src: 1.01-der-bauernhof-im-wald.md
  - src: 1.02-hunger.md
  - src: 1.03-erste-hilfe.md
  - src: 1.04-gehdlingen.md
  - src: 1.05-der-erste-sturm.md
  - src: 1.06-kinder-gegen-knochen.md
  - src: 1.07-der-ueberfall-im-nebel.md
  - src: 1.08-kraefte.md
    publish: False

Der zweite Block ist die Liste von Kapiteln bzw. die Liste der tatsächlichen Textinhalte, die in das Buch eingefügt werden sollen.

Die einzelnen Markdown-Dateien (*.md) werden in der angegebenen Reihenfolge ins Buch eingefügt. Kapitel, die noch nicht veröffentliche werden sollen, kann ich mithilfe von publish: false davon ausschließen. So kann ich auch unfertige Inhalte in das Projekt aufnehmen, ohne mit Gedanken über eine versehentliche Veröffentlichung machen zu müssen. (Das war damals insbesondere in Word ein Problem – was im Dokument war, das spuckte Word auch im PDF aus.)

Innerhalb der Markdown-Dateien verwende ich stinknormales Markdown für die Kapitelüberschriften, Formatierungen usw.

Aber was, wenn ich eine Formatierung oder ein Element brauche, das Markdown nicht vorsieht?

substitutions:
  # taunts:
  - pattern: \+\+(?P<text>.*?)\+\+
    replace_with: <span class="taunt">\g<text></span>
  # storyboard remover
  - pattern: ^\#\#\#\#(.*?)$
    replace_with: 
  # section delimiters --> maybe integrate into storyboards?
  - old: ---
    new: <p class="centered">* * *</p>
  # page break
  - old: <page-break>
    new: <div class="page-break"></div>

Die Verarbeitungsreihenfolge von anited. publish ist wie folgt:

  1. schreibe den Text in Markdown
  2. anited. publish übersetzt das Markdown nach HTML, im Markdown bereits enthaltenes HTML wird dabei erhalten (das ist eine fest definierte Eigenschaft von Markdown, das habe ich mir nicht selbst ausgedacht. :-))
  3. Calibre übersetzt das HTML in ein EBook und erhält dabei alle im HTML vorhandenen Formatierungen

Der dritte Block, substitutions, erlaubt es mir im Markdown vor der Übersetzung nach HTML beliebige Ersetzungen vorzunehmen.

Ein Beispiel: Wenn ihr AUS gelesen habt, ist euch sicher schon aufgefallen dass einzelne Abschnitte innerhalb der Kapitel durch drei zentrierte Sternchen voneinander abgetrennt sind, in etwa so:

* * *

Markdown sieht das nicht vor. Das höchste der Gefühle in Markdown ist eine hässliche schwarze Linie über die volle Breite der Seite. Versucht euch mal daran zu erinnern, wann ihr sowas das letzte Mal in einem Buch gesehen habt.

Also habe ich in der Bauanweisung für mein Buch die folgende ’substitutions‘, also Ersetzung definiert:

  - old: ---
    new: <p class="centered">* * *</p>

Wenn anited. publish auf drei aufeinanderfolgende Minus-Zeichen stößt (old), dann ersetzt es diese durch einen zentrierten Absatz mit drei Sternchen (new).

Jetzt kann ich in meinen Markdowndateien nach Herzenslust — platzieren und erhalte im fertigen EBook die gewünschten Trenner.

Hier ein Beispiel aus dem zweiten Kapitel:

Er gähnte. Die Prozedur würde den ganzen Tag dauern. Mangels Beschäftigung war ein Nickerchen also eine gar nicht so weit her geholte Option. Einen letzten Bissen von der Kartoffel abbeißend schloss er seine Augen. In einer gleichmäßigen Bewegung sanken sein Arm und die Kartoffel zu Boden. Nicht mehr von einer Hand gehalten rollte sie ein Stück weit über den staubigen Boden bis sie neben dem ruhenden Menschen ebenfalls zur Ruhe kam. 

---

Eine feuchte Haarsträhne klebte ihm im Gesicht. Haut und Kleidung waren immer noch – oder schon wieder? – durchnässt. Der Boden unter ihm hatte sich zu Matsch verformt und nachgegeben. Grunzend öffnete Gido die Augen, nur um fest zu stellen, dass das Wetter während seines Schlafs umgeschlagen hatte. Stumm setzte er sich senkrecht auf und blickte in eine dicke, graue Nebelsuppe die es sich zur Aufgabe gemacht hatte, ihr Wasser möglichst effektiv über die Welt zu verteilen.

Neben dieser einfachen Art der Übersetzung mit old und new, welches den exakten alten Wert durch einen exakten neuen Wert ersetzt, unterstützt anited. publish mit pattern und replace_with auch Reguläre Ausdrücke für komplexere Ersetzungen oder Umformungen.

  - pattern: \+\+(?P<text>.*?)\+\+
    replace_with: <span class="taunt">\g<text></span>

Diese substitution sucht beispielweise nach Text, der von ++-Zeichen eingerahmt ist und rahmt ihn stattdessen in den angegebenen HTML-Tag ein. Aus

++Freiheit? Was denkst du, wer du bist. Narr.++

wird so im fertigen EBook

<span class="taunt">Freiheit? Was denkst du, wer du bist. Narr.</span>

Der vierte Block dient dann der Formatierung des gesamten HTML:

stylesheet: stylesheet.css

Während der Erzeugung des EBooks wird das Stylesheet auf das HTML angewendet, bevor das fertige HTML Calibre vorgeworfen wird. Um beim obigen Beispiel zu bleiben, das Stylesheet von AUS enthält z.B.

.taunt {
    font-variant: small-caps;
    font-style: italic;
}

damit der Text mit der Klasse „Freiheit? Was denkst du, wer du bist. Narr.“ im EBook mit Kapitälchen und kursiv formatiert wird.

Der nächste Block dient dazu, die komplexen Parameter zu erfassen, die Calibre bzw. dessen Kommandozeile für die Arbeit braucht.

ebookconvert_params:
  - level1-toc=//h:h1
  - level2-toc=//h:h2
  - level3-toc=//h:h3
  - change-justification=left
  - page-breaks-before=//*[(name()='h1' or name()='h2') or (name()='div' and @class='page-break')]

Unterstützt werden hier alle Kommandozeilenparameter die Calibre anbietet, deshalb gibt’s die Dokumentation auch dieses Mal bei Calibre:
https://manual.calibre-ebook.com/generated/en/ebook-convert.html#ebook-convert

Insbesondere level1-toc usw. sind wichtig, wenn die im Markdown verfassten Überschriften auch im Inhaltsverzeichnis des EBook auftauchen sollen.

Der letzte Block definiert die zu erzeugenden Dokumente.

outputs:
  # html for verification
  - type: html
    output: ../Output/html/aus.htm
  # epub
  - type: ebookconvert
    output: ../Output/ebook/AUS-full.epub
    ebookconvert_params:
      - preserve-cover-aspect-ratio
  # mobi
  - type: ebookconvert
    output: ../Output/ebook/AUS-full.mobi
    ebookconvert_params:
      - mobi-file-type=both

anited. publish unterscheidet bei den Outputs zwischen zwei Typen:

  1. html kann von anited. publish selbst erzeugt werden und produziert eine einfache HTML-Datei
  2. ebookconvert erzeugt zunächst ein unsichtbares HTML-Dokument, um dieses dann mithilfe von Calibre in ein EBook umzuwandeln

Beide Typen wenden alle Substitutions und Stylesheets an, während die ebookconvert-params selbstverständlich nur beim Typen ebookconvert zum Tragen kommen.

Innerhalb eines Outputs können einzelne Kommandozeilenparameter sowie Stylesheets für Calibre ergänzt oder überschrieben werden.

Der Output

  - type: ebookconvert
    output: ../Output/ebook/AUS-full.epub
    ebookconvert_params:
      - preserve-cover-aspect-ratio

wendet sowohl die globalen Parameter

ebookconvert_params:
  - level1-toc=//h:h1
  - level2-toc=//h:h2
  - level3-toc=//h:h3
  - change-justification=left
  - page-breaks-before=//*[(name()='h1' or name()='h2') or (name()='div' and @class='page-break')]

als auch den Parameter

- preserve-cover-aspect-ratio

an.

Die gesamte Datei liegt als .publish.yml neben den Markdown-Dateien.

Alles, was ich jetzt noch tun muss, um die EBooks zu erzeugen, ist auf der Kommandozeile im Verzeichnis der Dateien den den Befehl ausführen:

publish

Das war’s.

Automate Everything

Meine Anforderungen an eine solche Software sind zugegebenermaßen speziell. Wenn es aber eines gibt, dass ich jedem Autor oder Software-Entwickler mitgeben möchte, ist es das folgende:

Automatisiert alles, was nicht bei drei auf dem Bäumen ist.

Euer Fokus sollte immer auf eurer Arbeit, auf eurem Werk, auf eurem Produkt sein. Je mehr Schritte, je mehr Arbeiten zwischen eurer kreativen Arbeit und ihrer Veröffentlichung stehen, desto größer ist der innere Schweinehund, der euch daran hindern kann und desto größer ist die Wahrscheinlichkeit, dass ihr lieber irgendwas anderes macht.

anited. publish ist auf mich und meinen Schweinehund zugeschnitten. Sie erlaubt es mir, mein Buch in einem Editor meiner Wahl im Format meiner Wahl zu schreiben und es jederzeit mit einem Kommandozeilenbefehl zu erzeugen.

anited. publish ist Open Source, ihr könnt es also gerne einsetzen, einsehen, weiterverbreiten oder abändern.

Wer weiß, vielleicht hilft es ja auch einem von euch dabei, EBooks zu erzeugen.