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, Gedacht für die Weiterverarbeitung mit Markdown-Renderern, Pandoc, Obsidian/Zettelkasten, Git,
RAG-/Embedding-Pipelines, Volltextsuche und lokale LLMs. 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 ## Grenzen
- **Kein DRM:** Verschlüsselte EPUBs (`META-INF/encryption.xml` mit verschlüsselten Inhalten) werden mit - **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 │ ├── 003-1-einleitung.md
│ ├── … │ ├── …
│ └── 999-anmerkungen.md # nur bei --footnotes end-of-book │ └── 999-anmerkungen.md # nur bei --footnotes end-of-book
└── diagnostics/ ├── diagnostics/
├── warnings.md # Warnungen/Hinweise gruppiert, für Menschen │ ├── warnings.md # Warnungen/Hinweise gruppiert, für Menschen
└── unsupported-elements.md │ └── unsupported-elements.md
└── mein-buch.md # Gesamtdatei, erst nach epub2md_merge.py
``` ```
- Dateinamen: fortlaufend dreistellig nummeriert (`001-…`) plus Slug aus dem Kapiteltitel. Gleiche Titel - 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 Einrückung, Tabs, `<`, `>`, `&`, `$`, `|`, Backslashes und Backticks bleiben exakt erhalten. Die Sprache
kommt aus Klassen/Attributen (`language-python`, `data-lang`, …) oder starken Inhaltssignalen kommt aus Klassen/Attributen (`language-python`, `data-lang`, …) oder starken Inhaltssignalen
(`#include`, `def …:`, Shebang, …). Ist sie unsicher, bleibt das Label leer. Bei einsprachigen (`#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. auch Programmausgaben und Shell-Befehle im Buch.
- **Gescannte Texte:** nur Bilder, kein Text (keine OCR). - **Gescannte Texte:** nur Bilder, kein Text (keine OCR).
- **DRM:** wird erkannt und abgelehnt. - **DRM:** wird erkannt und abgelehnt.
@ -219,14 +235,20 @@ python3 epub2md_merge.py output/programmierhandbuch
# → output/programmierhandbuch/<Original-Name>.md # → output/programmierhandbuch/<Original-Name>.md
python3 epub2md_merge.py output/programmierhandbuch -o buecher/handbuch.md --toc --force 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 | | Option | Wirkung |
| --- | --- | | --- | --- |
| `-o`, `--output DATEI.md` | anderer Zielort; Medienpfade werden relativ zum Ziel umgeschrieben | | `-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) | | `--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 | | `--toc` | Inhaltsverzeichnis mit Sprunglinks auf die Kapitel einfügen |
| `--force` | bestehende Zieldatei überschreiben (sonst Abbruch mit Exit 1) | | `--force` | bestehende Zieldatei überschreiben (sonst Abbruch mit Exit 1) |
| `--version` | Programmversion |
Beim Zusammenfügen passiert Folgendes: Beim Zusammenfügen passiert Folgendes:
@ -238,27 +260,48 @@ Beim Zusammenfügen passiert Folgendes:
- Medienpfade (`../media/…`) werden auf den Ort der Gesamtdatei umgeschrieben. - Medienpfade (`../media/…`) werden auf den Ort der Gesamtdatei umgeschrieben.
- Fußnotendefinitionen, die in mehreren Kapiteln stehen, erscheinen nur einmal. - Fußnotendefinitionen, die in mehreren Kapiteln stehen, erscheinen nur einmal.
- Codeblöcke und Inline-Code werden nie verändert. - 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 ## 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 ```bash
pandoc output/programmierbuch/chapters/*.md \ pandoc output/programmierbuch/chapters/*.md \
--metadata-file=output/programmierbuch/metadata.yaml \ --metadata-file=output/programmierbuch/metadata.yaml \
-o programmierbuch.html -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 - 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. 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`. - 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 - Das YAML-Frontmatter jeder Kapiteldatei wird von Pandoc als Metadaten gelesen. Wer die Kapiteldateien
ggf. `--no-frontmatter` verwenden. 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 ## 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), 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. 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 ## Architektur
```text ```text
@ -306,6 +361,7 @@ epub2md/
├── mathml.py konservative MathML→TeX-Konvertierung, TeX-Erkennung ├── mathml.py konservative MathML→TeX-Konvertierung, TeX-Erkennung
├── media.py Medienregistry mit stabilen Namen ├── media.py Medienregistry mit stabilen Namen
├── linkcheck.py Validierung aller relativen Links/Anker der Ausgabe ├── 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 ├── writer.py README, metadata.yaml, Frontmatter, Diagnose-Markdown
├── diagnostics.py zentrale Sammlung von Warnungen/Fehlern ├── diagnostics.py zentrale Sammlung von Warnungen/Fehlern
├── models.py Dataclasses (Kapitel, Medien, Noten, Metadaten …) ├── models.py Dataclasses (Kapitel, Medien, Noten, Metadaten …)
@ -319,12 +375,15 @@ Eingabe und Optionen ergeben identische Kapiteldateien.
## Tests ## Tests
```bash ```bash
pip install -r requirements-dev.txt
python3 -m pytest -q 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, 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 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 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 vorhanden. Dabei werden keine Buchtexte verglichen. `Beispiele/` ist per `.gitignore` vom Repository
ausgeschlossen. ausgeschlossen.