mirror of
https://github.com/denizsafak/abogen.git
synced 2026-07-18 05:40:26 +02:00
extract apply_chapter_text_transforms to domain/chapter_titles.py
This commit is contained in:
@@ -170,3 +170,35 @@ def format_spoken_chapter_title(title: str, index: int, apply_prefix: bool) -> s
|
||||
return f"Chapter {number}. {cleaned_suffix}"
|
||||
return f"Chapter {number}"
|
||||
return base
|
||||
|
||||
|
||||
def apply_chapter_text_transforms(
|
||||
text: str,
|
||||
*,
|
||||
heading_text: str,
|
||||
raw_title: str,
|
||||
strip_heading: bool,
|
||||
normalize_caps: bool,
|
||||
) -> Tuple[str, bool, bool]:
|
||||
"""Strip duplicate heading and normalize opening caps.
|
||||
|
||||
Returns ``(text, heading_removed, caps_changed)``.
|
||||
The caller is responsible for state updates (pending flags, logging,
|
||||
dict mutation, ``continue``).
|
||||
"""
|
||||
heading_removed = False
|
||||
caps_changed = False
|
||||
|
||||
if strip_heading and heading_text:
|
||||
text, heading_removed = strip_duplicate_heading_line(text, heading_text)
|
||||
if not heading_removed and raw_title:
|
||||
match = _HEADING_NUMBER_PREFIX_RE.match(raw_title)
|
||||
if match:
|
||||
number = match.group("number")
|
||||
if number:
|
||||
text, heading_removed = strip_duplicate_heading_line(text, number)
|
||||
|
||||
if normalize_caps and text:
|
||||
text, caps_changed = normalize_chapter_opening_caps(text)
|
||||
|
||||
return text, heading_removed, caps_changed
|
||||
|
||||
@@ -48,6 +48,7 @@ from abogen.domain.chapter_titles import (
|
||||
normalize_caps_word as _normalize_caps_word,
|
||||
normalize_chapter_opening_caps as _normalize_chapter_opening_caps,
|
||||
format_spoken_chapter_title as _format_spoken_chapter_title,
|
||||
apply_chapter_text_transforms as _apply_chapter_text_transforms,
|
||||
_HEADING_NUMBER_PREFIX_RE,
|
||||
)
|
||||
from abogen.domain.metadata_helpers import (
|
||||
@@ -780,39 +781,32 @@ def run_conversion_job(job: Job) -> None:
|
||||
continue
|
||||
|
||||
mutated_entry = False
|
||||
if pending_heading_strip and heading_text:
|
||||
chunk_text, removed_heading = _strip_duplicate_heading_line(chunk_text, heading_text)
|
||||
if not removed_heading and raw_title:
|
||||
match = _HEADING_NUMBER_PREFIX_RE.match(raw_title)
|
||||
if match:
|
||||
number = match.group("number")
|
||||
if number:
|
||||
chunk_text, removed_heading = _strip_duplicate_heading_line(chunk_text, number)
|
||||
|
||||
if removed_heading:
|
||||
pending_heading_strip = False
|
||||
chunk_text, heading_removed, caps_changed = _apply_chapter_text_transforms(
|
||||
chunk_text,
|
||||
heading_text=heading_text,
|
||||
raw_title=raw_title,
|
||||
strip_heading=pending_heading_strip,
|
||||
normalize_caps=opening_caps_pending,
|
||||
)
|
||||
if heading_removed:
|
||||
pending_heading_strip = False
|
||||
chunk_entry = dict(chunk_entry)
|
||||
chunk_entry["normalized_text"] = chunk_text
|
||||
mutated_entry = True
|
||||
if not chunk_text.strip():
|
||||
continue
|
||||
if caps_changed:
|
||||
if not mutated_entry:
|
||||
chunk_entry = dict(chunk_entry)
|
||||
chunk_entry["normalized_text"] = chunk_text
|
||||
mutated_entry = True
|
||||
if not chunk_text.strip():
|
||||
continue
|
||||
|
||||
if opening_caps_pending and chunk_text:
|
||||
normalized_text, normalized_changed = _normalize_chapter_opening_caps(chunk_text)
|
||||
if normalized_changed:
|
||||
if not mutated_entry:
|
||||
chunk_entry = dict(chunk_entry)
|
||||
mutated_entry = True
|
||||
chunk_entry["normalized_text"] = normalized_text
|
||||
chunk_text = normalized_text
|
||||
if not opening_caps_logged:
|
||||
job.add_log(
|
||||
f"Normalized uppercase chapter opening for chapter {idx}.",
|
||||
level="debug",
|
||||
)
|
||||
opening_caps_logged = True
|
||||
if chunk_text.strip():
|
||||
opening_caps_pending = False
|
||||
chunk_entry["normalized_text"] = chunk_text
|
||||
if not opening_caps_logged:
|
||||
job.add_log(
|
||||
f"Normalized uppercase chapter opening for chapter {idx}.",
|
||||
level="debug",
|
||||
)
|
||||
opening_caps_logged = True
|
||||
if chunk_text.strip():
|
||||
opening_caps_pending = False
|
||||
|
||||
chunk_voice_spec = _chunk_voice_spec(
|
||||
job,
|
||||
@@ -878,29 +872,24 @@ def run_conversion_job(job: Job) -> None:
|
||||
if body_segments == 0:
|
||||
chapter_body_start = current_time
|
||||
chapter_text = str(chapter.text or "")
|
||||
if pending_heading_strip and heading_text:
|
||||
chapter_text, removed_heading = _strip_duplicate_heading_line(chapter_text, heading_text)
|
||||
if not removed_heading and raw_title:
|
||||
match = _HEADING_NUMBER_PREFIX_RE.match(raw_title)
|
||||
if match:
|
||||
number = match.group("number")
|
||||
if number:
|
||||
chapter_text, removed_heading = _strip_duplicate_heading_line(chapter_text, number)
|
||||
|
||||
if removed_heading:
|
||||
pending_heading_strip = False
|
||||
if opening_caps_pending and chapter_text:
|
||||
normalized_body, normalized_changed = _normalize_chapter_opening_caps(chapter_text)
|
||||
if normalized_changed:
|
||||
chapter_text = normalized_body
|
||||
if not opening_caps_logged:
|
||||
job.add_log(
|
||||
f"Normalized uppercase chapter opening for chapter {idx}.",
|
||||
level="debug",
|
||||
)
|
||||
opening_caps_logged = True
|
||||
if str(chapter_text or "").strip():
|
||||
opening_caps_pending = False
|
||||
chapter_text, heading_removed, caps_changed = _apply_chapter_text_transforms(
|
||||
chapter_text,
|
||||
heading_text=heading_text,
|
||||
raw_title=raw_title,
|
||||
strip_heading=pending_heading_strip,
|
||||
normalize_caps=opening_caps_pending,
|
||||
)
|
||||
if heading_removed:
|
||||
pending_heading_strip = False
|
||||
if caps_changed:
|
||||
if not opening_caps_logged:
|
||||
job.add_log(
|
||||
f"Normalized uppercase chapter opening for chapter {idx}.",
|
||||
level="debug",
|
||||
)
|
||||
opening_caps_logged = True
|
||||
if str(chapter_text or "").strip():
|
||||
opening_caps_pending = False
|
||||
emitted = emit_text(
|
||||
chapter_text,
|
||||
voice_choice=voice_choice,
|
||||
|
||||
@@ -124,3 +124,117 @@ 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
|
||||
|
||||
|
||||
class TestApplyChapterTextTransforms:
|
||||
"""Tests for the combined heading-strip + opening-caps helper."""
|
||||
|
||||
def test_both_enabled_heading_matches(self) -> None:
|
||||
from abogen.domain.chapter_titles import apply_chapter_text_transforms
|
||||
|
||||
text, heading_removed, caps_changed = apply_chapter_text_transforms(
|
||||
"Chapter 1: The Beginning\nBody text here",
|
||||
heading_text="Chapter 1: The Beginning",
|
||||
raw_title="Chapter 1: The Beginning",
|
||||
strip_heading=True,
|
||||
normalize_caps=True,
|
||||
)
|
||||
assert heading_removed is True
|
||||
assert "Body text here" in text
|
||||
assert "Chapter 1" not in text
|
||||
|
||||
def test_heading_fallback_to_number(self) -> None:
|
||||
from abogen.domain.chapter_titles import apply_chapter_text_transforms
|
||||
|
||||
text, heading_removed, caps_changed = apply_chapter_text_transforms(
|
||||
"1. The Beginning\nBody text",
|
||||
heading_text="Chapter 1: The Beginning",
|
||||
raw_title="1: The Beginning",
|
||||
strip_heading=True,
|
||||
normalize_caps=False,
|
||||
)
|
||||
assert heading_removed is True
|
||||
assert "Body text" in text
|
||||
|
||||
def test_only_heading_strip(self) -> None:
|
||||
from abogen.domain.chapter_titles import apply_chapter_text_transforms
|
||||
|
||||
text, heading_removed, caps_changed = apply_chapter_text_transforms(
|
||||
"Chapter 1: Title\nBody text",
|
||||
heading_text="Chapter 1: Title",
|
||||
raw_title="",
|
||||
strip_heading=True,
|
||||
normalize_caps=False,
|
||||
)
|
||||
assert heading_removed is True
|
||||
assert caps_changed is False
|
||||
|
||||
def test_only_opening_caps(self) -> None:
|
||||
from abogen.domain.chapter_titles import apply_chapter_text_transforms
|
||||
|
||||
text, heading_removed, caps_changed = apply_chapter_text_transforms(
|
||||
"ALL CAPS START OF CHAPTER",
|
||||
heading_text="Chapter 1",
|
||||
raw_title="",
|
||||
strip_heading=False,
|
||||
normalize_caps=True,
|
||||
)
|
||||
assert heading_removed is False
|
||||
assert caps_changed is True
|
||||
assert text == "All Caps Start Of Chapter"
|
||||
|
||||
def test_both_disabled_no_change(self) -> None:
|
||||
from abogen.domain.chapter_titles import apply_chapter_text_transforms
|
||||
|
||||
original = "Some text here"
|
||||
text, heading_removed, caps_changed = apply_chapter_text_transforms(
|
||||
original,
|
||||
heading_text="Chapter 1",
|
||||
raw_title="",
|
||||
strip_heading=False,
|
||||
normalize_caps=False,
|
||||
)
|
||||
assert text == original
|
||||
assert heading_removed is False
|
||||
assert caps_changed is False
|
||||
|
||||
def test_heading_not_matching(self) -> None:
|
||||
from abogen.domain.chapter_titles import apply_chapter_text_transforms
|
||||
|
||||
text, heading_removed, caps_changed = apply_chapter_text_transforms(
|
||||
"Completely different text",
|
||||
heading_text="Chapter 1: Title",
|
||||
raw_title="",
|
||||
strip_heading=True,
|
||||
normalize_caps=False,
|
||||
)
|
||||
assert heading_removed is False
|
||||
assert text == "Completely different text"
|
||||
|
||||
def test_empty_text(self) -> None:
|
||||
from abogen.domain.chapter_titles import apply_chapter_text_transforms
|
||||
|
||||
text, heading_removed, caps_changed = apply_chapter_text_transforms(
|
||||
"",
|
||||
heading_text="Chapter 1",
|
||||
raw_title="",
|
||||
strip_heading=True,
|
||||
normalize_caps=True,
|
||||
)
|
||||
assert text == ""
|
||||
assert heading_removed is False
|
||||
assert caps_changed is False
|
||||
|
||||
def test_both_enabled_text_only_has_caps(self) -> None:
|
||||
from abogen.domain.chapter_titles import apply_chapter_text_transforms
|
||||
|
||||
text, heading_removed, caps_changed = apply_chapter_text_transforms(
|
||||
"NASA MISSION LOG",
|
||||
heading_text="Chapter 1",
|
||||
raw_title="",
|
||||
strip_heading=True,
|
||||
normalize_caps=True,
|
||||
)
|
||||
assert heading_removed is False
|
||||
assert caps_changed is True
|
||||
assert text == "NASA Mission Log"
|
||||
|
||||
Reference in New Issue
Block a user