feat: Implement normalize chapter opening caps feature and update related settings

This commit is contained in:
JB
2025-10-27 15:58:34 -07:00
parent 9d35e39e89
commit 6e536c6e3b
11 changed files with 333 additions and 14 deletions
+88
View File
@@ -1,6 +1,70 @@
import sys
import types
if "soundfile" not in sys.modules:
soundfile_stub = types.ModuleType("soundfile")
class _SoundFileStub: # pragma: no cover - placeholder to satisfy imports
def __init__(self, *args: object, **kwargs: object) -> None:
raise RuntimeError("soundfile is not installed in the test environment")
soundfile_stub.SoundFile = _SoundFileStub # type: ignore[attr-defined]
sys.modules["soundfile"] = soundfile_stub
if "static_ffmpeg" not in sys.modules:
sys.modules["static_ffmpeg"] = types.ModuleType("static_ffmpeg")
if "ebooklib" not in sys.modules:
ebooklib_stub = types.ModuleType("ebooklib")
ebooklib_epub_stub = types.ModuleType("ebooklib.epub")
ebooklib_stub.epub = ebooklib_epub_stub # type: ignore[attr-defined]
sys.modules["ebooklib"] = ebooklib_stub
sys.modules["ebooklib.epub"] = ebooklib_epub_stub
if "fitz" not in sys.modules:
sys.modules["fitz"] = types.ModuleType("fitz")
if "markdown" not in sys.modules:
markdown_stub = types.ModuleType("markdown")
class _MarkdownStub:
def __init__(self, *args: object, **kwargs: object) -> None:
self.toc_tokens = []
def convert(self, text: str) -> str:
return text
markdown_stub.Markdown = _MarkdownStub # type: ignore[attr-defined]
sys.modules["markdown"] = markdown_stub
if "bs4" not in sys.modules:
bs4_stub = types.ModuleType("bs4")
class _BeautifulSoupStub:
def __init__(self, *args: object, **kwargs: object) -> None:
self._text = ""
def find(self, *args: object, **kwargs: object) -> None:
return None
def get_text(self) -> str:
return self._text
def decompose(self) -> None: # pragma: no cover - compatibility shim
return None
class _NavigableStringStub(str):
pass
bs4_stub.BeautifulSoup = _BeautifulSoupStub # type: ignore[attr-defined]
bs4_stub.NavigableString = _NavigableStringStub # type: ignore[attr-defined]
sys.modules["bs4"] = bs4_stub
from abogen.web.conversion_runner import (
_format_spoken_chapter_title,
_headings_equivalent,
_normalize_chapter_opening_caps,
_strip_duplicate_heading_line,
)
@@ -29,3 +93,27 @@ def test_strip_duplicate_heading_line_removes_first_match() -> None:
text, removed = _strip_duplicate_heading_line("Chapter 3: Intro\nBody text", "Chapter 3: Intro")
assert removed is True
assert text.strip() == "Body text"
def test_normalize_chapter_opening_caps_basic_title() -> None:
normalized, changed = _normalize_chapter_opening_caps("ALL CAPS TITLE")
assert normalized == "All Caps Title"
assert changed is True
def test_normalize_chapter_opening_caps_respects_acronyms() -> None:
normalized, changed = _normalize_chapter_opening_caps("NASA MISSION LOG")
assert normalized == "NASA Mission Log"
assert changed is True
def test_normalize_chapter_opening_caps_handles_roman_numerals() -> None:
normalized, changed = _normalize_chapter_opening_caps("IV. THE RETURN")
assert normalized == "IV. The Return"
assert changed is True
def test_normalize_chapter_opening_caps_keeps_mixed_case() -> None:
normalized, changed = _normalize_chapter_opening_caps("Already Mixed Case")
assert normalized == "Already Mixed Case"
assert changed is False
+1
View File
@@ -33,6 +33,7 @@ def _make_pending_job() -> PendingJob:
chapters=[],
created_at=0.0,
read_title_intro=False,
normalize_chapter_opening_caps=True,
)