docs: README um Schnellstart, Merge-Details, Pandoc-Workflow und Einschränkungen ergänzt

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-10-05 20:27:36 +02:00
commit 3e44a2d484

View file

@ -7,6 +7,21 @@ YAML-Metadaten, Inhaltsverzeichnis, maschinenlesbarem Manifest und einem Konvert
Gedacht für die Weiterverarbeitung mit Markdown-Renderern, Pandoc, Obsidian/Zettelkasten, Git,
RAG-/Embedding-Pipelines, Volltextsuche und lokale LLMs.
Das Projekt enthält zwei Programme:
| Programm | Zweck |
| --- | --- |
| `epub2md.py` | EPUB → Verzeichnis mit Kapitel-Markdown, Medien, Metadaten und Bericht |
| `epub2md_merge.py` | Ausgabeverzeichnis → **eine** vollständige Markdown-Datei des Buches |
## Schnellstart
```bash
pip install -r requirements.txt
python3 epub2md.py Beispiele/buch.epub output/buch # Kapitel-Dateien erzeugen
python3 epub2md_merge.py output/buch # → output/buch/buch.md (Gesamtdatei)
```
## Grenzen
- **Kein DRM:** Verschlüsselte EPUBs (`META-INF/encryption.xml` mit verschlüsselten Inhalten) werden mit
@ -115,9 +130,10 @@ output/mein-buch/
│ ├── 003-1-einleitung.md
│ ├── …
│ └── 999-anmerkungen.md # nur bei --footnotes end-of-book
└── diagnostics/
├── warnings.md # Warnungen/Hinweise gruppiert, für Menschen
└── unsupported-elements.md
├── diagnostics/
│ ├── warnings.md # Warnungen/Hinweise gruppiert, für Menschen
│ └── unsupported-elements.md
└── mein-buch.md # Gesamtdatei, erst nach epub2md_merge.py
```
- Dateinamen: fortlaufend dreistellig nummeriert (`001-…`) plus Slug aus dem Kapiteltitel. Gleiche Titel
@ -202,7 +218,7 @@ weil CommonMark keine `[^…]`-Syntax kennt.
Einrückung, Tabs, `<`, `>`, `&`, `$`, `|`, Backslashes und Backticks bleiben exakt erhalten. Die Sprache
kommt aus Klassen/Attributen (`language-python`, `data-lang`, …) oder starken Inhaltssignalen
(`#include`, `def …:`, Shebang, …). Ist sie unsicher, bleibt das Label leer. Bei einsprachigen
Büchern kann `--code-language python` (o. Ä.) alle übrigen Blöcke kennzeichnen. Achtung: Das betrifft
Büchern kann `--code-language python` (o. Ä.) alle übrigen Blöcke kennzeichnen. Achtung: Das betrifft
auch Programmausgaben und Shell-Befehle im Buch.
- **Gescannte Texte:** nur Bilder, kein Text (keine OCR).
- **DRM:** wird erkannt und abgelehnt.
@ -219,14 +235,20 @@ python3 epub2md_merge.py output/programmierhandbuch
# → output/programmierhandbuch/<Original-Name>.md
python3 epub2md_merge.py output/programmierhandbuch -o buecher/handbuch.md --toc --force
# alternativ: python3 -m epub2md.merge …
```
Eingabe ist ein von `epub2md.py` erzeugtes Verzeichnis. Die Reihenfolge stammt aus `manifest.json`,
der Dateiname aus `conversion-report.json`. Fehlen diese Dateien, werden `chapters/*.md` alphabetisch
verwendet und das Verzeichnis gibt den Namen vor.
| Option | Wirkung |
| --- | --- |
| `-o`, `--output DATEI.md` | anderer Zielort; Medienpfade werden relativ zum Ziel umgeschrieben |
| `--frontmatter` / `--no-frontmatter` | ein YAML-Kopf mit Buchmetadaten (`title`, `author`, `lang`, …) für Pandoc (Standard: an) |
| `--toc` | Inhaltsverzeichnis mit Sprunglinks auf die Kapitel einfügen |
| `--force` | bestehende Zieldatei überschreiben (sonst Abbruch mit Exit 1) |
| `--version` | Programmversion |
Beim Zusammenfügen passiert Folgendes:
@ -238,27 +260,48 @@ Beim Zusammenfügen passiert Folgendes:
- Medienpfade (`../media/…`) werden auf den Ort der Gesamtdatei umgeschrieben.
- Fußnotendefinitionen, die in mehreren Kapiteln stehen, erscheinen nur einmal.
- Codeblöcke und Inline-Code werden nie verändert.
- Kapitelüberschriften bleiben `#`, jedes Kapitel beginnt also mit einer H1. Pandoc behandelt sie als
Kapitel.
- Der Buch-Kopf enthält nur Felder, die im EPUB vorhanden sind (`title`, `subtitle`, `author`, `lang`,
`publisher`, `date`, `identifier`, `rights`, `description`).
Am Ende werden alle Links der Gesamtdatei geprüft.
Am Ende werden alle Links der Gesamtdatei geprüft. Ein Link auf einen nicht vorhandenen Anker zeigt auf
den Kapitelanfang und erzeugt eine Warnung auf stderr. Die Zusammenfassung nennt Kapitelanzahl,
umbenannte Anker, entfernte doppelte Fußnoten und ungültige Links.
Rückgabecodes: `0` Erfolg, `1` Verzeichnis ungültig/leer, Kapiteldatei fehlt oder Zieldatei existiert,
`4` unerwarteter interner Fehler.
## Weiterverarbeitung mit Pandoc
Am einfachsten geht das über die Gesamtdatei aus `epub2md_merge.py`. Sie hat einen Buch-Kopf und
konsistente Anker:
```bash
cd output/programmierbuch # Medienpfade sind relativ zur Gesamtdatei
pandoc programmierbuch.md --toc -s -o programmierbuch.html
pandoc programmierbuch.md --toc -o programmierbuch.epub
cd output/mathematikbuch
pandoc mathematikbuch.md --mathml -s -o mathematikbuch.html
pandoc mathematikbuch.md --pdf-engine=xelatex -o mathematikbuch.pdf
```
Alternativ direkt aus den Kapiteldateien:
```bash
pandoc output/programmierbuch/chapters/*.md \
--metadata-file=output/programmierbuch/metadata.yaml \
-o programmierbuch.html
pandoc output/mathematikbuch/chapters/*.md \
--metadata-file=output/mathematikbuch/metadata.yaml \
--pdf-engine=xelatex \
-o mathematikbuch.pdf
```
- Für HTML mit Formeln `--mathml`, `--mathjax` oder `--katex` verwenden. Pandocs Standard-HTML kann
Matrizen nicht in Unicode umsetzen, meldet „Could not convert TeX math“ und belässt das TeX.
- Ausgaben mit `--math tex` (`\(…\)`) brauchen `-f markdown+tex_math_single_backslash`.
- Das YAML-Frontmatter jeder Kapiteldatei wird von Pandoc als Metadaten gelesen. Für ein Gesamtdokument
ggf. `--no-frontmatter` verwenden.
- Das YAML-Frontmatter jeder Kapiteldatei wird von Pandoc als Metadaten gelesen. Wer die Kapiteldateien
direkt zusammen verarbeitet, sollte mit `--no-frontmatter` konvertieren oder die Gesamtdatei verwenden.
- Einzelne TeX-Befehle aus EPUBs (z. B. `\O` oder `@`-Konstrukte) kennt Pandocs Formelparser nicht. Er
belässt sie als TeX, mit der Warnung „Could not convert TeX math“.
## Bericht und Diagnose
@ -288,6 +331,18 @@ Verlustfreiheit behauptet (`lossless: false`).
es nur, wenn es eine frühere epub2md-Ausgabe ist (`conversion-report.json`/`manifest.json` vorhanden),
nicht das Arbeits- oder Home-Verzeichnis ist und die Eingabedatei nicht darin liegt.
## Bekannte Einschränkungen
- Überschriftslose Dokumente ohne NAV-Eintrag und ohne `<title>` werden nach dem Dateinamen benannt
(z. B. `cinnertitle`).
- Aneinanderstoßende Inline-Elemente, zwischen denen auch in der Quelle kein Leerraum steht, laufen
zusammen (z. B. Autor- und Titelzeilen in Springer-Kapitelköpfen).
- Druck-Fortsetzungszeichen (`↪`) in Listings und fehlerhafte Einrückungen der Vorlage werden
zeichengetreu übernommen.
- Formelbilder ohne TeX-Alternativtext bleiben Bilder.
- Audio/Video sind implementiert, aber nur mit synthetischen Daten geprüft. Für Bildbände gibt es
bislang keine Testbücher.
## Architektur
```text
@ -306,6 +361,7 @@ epub2md/
├── mathml.py konservative MathML→TeX-Konvertierung, TeX-Erkennung
├── media.py Medienregistry mit stabilen Namen
├── linkcheck.py Validierung aller relativen Links/Anker der Ausgabe
├── merge.py Gesamtdatei: Reihenfolge, Anker-Umbenennung, Pfade, Fußnoten-Deduplizierung
├── writer.py README, metadata.yaml, Frontmatter, Diagnose-Markdown
├── diagnostics.py zentrale Sammlung von Warnungen/Fehlern
├── models.py Dataclasses (Kapitel, Medien, Noten, Metadaten …)
@ -319,12 +375,15 @@ Eingabe und Optionen ergeben identische Kapiteldateien.
## Tests
```bash
pip install -r requirements-dev.txt
python3 -m pytest -q
ruff check epub2md tests && mypy epub2md --ignore-missing-imports # optional, falls installiert
```
Die Tests erzeugen synthetische Minimal-EPUBs (EPUB 2/3, NAV/NCX, Code, Tabellen, MathML, SVG,
Fußnoten, Glossar/Literatur/Register, unsichere ZIP-Pfade, DRM, XXE, defekte Container, Kodierung) und
prüfen die tatsächliche CLI-Ausgabe. Liegen EPUBs unter `Beispiele/`, werden sie zusätzlich auf
prüfen die tatsächliche CLI-Ausgabe. `tests/test_merge.py` prüft die Gesamtdatei: Reihenfolge,
Anker-Umbenennung, Pfade, Fußnoten, unveränderter Code und Überschreibschutz. Liegen EPUBs unter `Beispiele/`, werden sie zusätzlich auf
Struktur-Invarianten geprüft: keine kaputten Links, balancierte Code-Fences, gültiges YAML, alle Medien
vorhanden. Dabei werden keine Buchtexte verglichen. `Beispiele/` ist per `.gitignore` vom Repository
ausgeschlossen.