Fügt die Kapiteldateien in Lesereihenfolge (manifest.json) zu einer Markdown-Datei mit dem Original-EPUB-Namen (.md) zusammen. Dabei werden: - Links zwischen Kapiteln zu Sprunglinks in der Gesamtdatei, - kollidierende Anker pro Kapitel umbenannt, - Medienpfade relativ zum Ziel umgeschrieben, - doppelte Fußnotendefinitionen entfernt, - Code nie verändert. Optionen -o, --toc, --no-frontmatter und --force; abschließender Linkcheck. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
73 lines
3.3 KiB
Python
73 lines
3.3 KiB
Python
import re
|
|
|
|
import yaml
|
|
|
|
from conftest import PNG, Book, Doc
|
|
from epub2md.linkcheck import anchors_in, check_links
|
|
from epub2md.merge import main as merge_main
|
|
|
|
A = ('<h1 id="sec">Kapitel A</h1><p>Siehe <a href="b.xhtml#sec">B</a>, <a href="b.xhtml">Kapitel B</a>, '
|
|
'<a href="#sec">hier</a> und Anmerkung<a epub:type="noteref" href="b.xhtml#n1">1</a>.</p>'
|
|
'<p><img src="img/a.png" alt="Bild"/></p>'
|
|
'<p><a href="b.xhtml"><img src="img/a.png" alt="Bildlink"/></a></p>'
|
|
'<pre>[kein](link.md) id="sec" `code`</pre>')
|
|
B = ('<h1 id="sec">Kapitel B</h1><p>Zurück zu <a href="a.xhtml#sec">A</a>, nochmal Anmerkung'
|
|
'<a epub:type="noteref" href="#n1">1</a>.</p>'
|
|
'<aside epub:type="footnote" id="n1"><p>Gemeinsame Anmerkung.</p></aside>')
|
|
|
|
|
|
def book() -> Book:
|
|
return Book(title="Merge-Test", docs=[Doc("a.xhtml", A), Doc("b.xhtml", B)], media={"img/a.png": PNG})
|
|
|
|
|
|
def test_merge_complete_book(convert, tmp_path):
|
|
run = convert(book())
|
|
assert merge_main([str(run.out)]) == 0
|
|
target = run.out / f"{run.report['input']['name'][:-5]}.md"
|
|
text = target.read_text(encoding="utf-8")
|
|
# one book-level frontmatter, no chapter frontmatter
|
|
fm = yaml.safe_load(text.split("---\n")[1])
|
|
assert fm["title"] == "Merge-Test" and fm["author"] == ["Erika Musterfrau"] and fm["lang"] == "de"
|
|
assert text.count("chapter_number") == 0
|
|
# reading order
|
|
assert text.index("# Kapitel A") < text.index("# Kapitel B")
|
|
# links between chapters point into the merged file; colliding id "sec" renamed in chapter B
|
|
assert '<a id="sec"></a>' in text and '<a id="c002-sec"></a>' in text
|
|
assert "[B](#c002-sec)" in text and "[A](#sec)" in text and "[hier](#sec)" in text
|
|
assert "[Kapitel B](#002-kapitel-b)" in text and '<a id="002-kapitel-b"></a>' in text
|
|
# media paths relative to the merged file, also inside image links
|
|
assert "" in text
|
|
assert "[](#002-kapitel-b)" in text
|
|
# code untouched
|
|
assert '[kein](link.md) id="sec" `code`' in text
|
|
# footnote defined in both chapters -> only once in the merged file
|
|
assert text.count("[^fn-001]:") == 1
|
|
assert check_links({target.as_posix(): text}, {p.as_posix() for p in run.out.rglob("*") if p.is_file()}) == []
|
|
prose = re.sub(r"^```.*?^```$", "", text, flags=re.M | re.S)
|
|
ids = re.findall(r'id="([^"]+)"', prose)
|
|
assert len(ids) == len(set(ids))
|
|
|
|
|
|
def test_merge_refuses_overwrite_without_force(convert):
|
|
run = convert(book())
|
|
assert merge_main([str(run.out)]) == 0
|
|
assert merge_main([str(run.out)]) == 1
|
|
assert merge_main([str(run.out), "--force"]) == 0
|
|
|
|
|
|
def test_merge_to_other_location_rewrites_media_paths(convert, tmp_path):
|
|
run = convert(book())
|
|
(tmp_path / "ziel").mkdir()
|
|
target = tmp_path / "ziel" / "buch.md"
|
|
assert merge_main([str(run.out), "-o", str(target), "--toc", "--no-frontmatter"]) == 0
|
|
text = target.read_text(encoding="utf-8")
|
|
assert not text.startswith("---")
|
|
assert f"" in text
|
|
assert "1. [Kapitel A](#001-kapitel-a)" in text
|
|
assert "001-kapitel-a" in anchors_in(text)
|
|
|
|
|
|
def test_merge_invalid_directory(tmp_path):
|
|
assert merge_main([str(tmp_path / "gibt-es-nicht")]) == 1
|
|
(tmp_path / "leer").mkdir()
|
|
assert merge_main([str(tmp_path / "leer")]) == 1
|