Fix clickable parent Part navigation in Calibre

This commit is contained in:
Kai Tan
2026-10-08 08:09:50 +08:00
parent a158b4e26c
commit 498b5d09ce
5 changed files with 86 additions and 2 deletions
+17 -1
View File
@@ -14,14 +14,30 @@ def parse_html(content):
return BeautifulSoup(re.sub(r'^\s*<\?xml[^>]*\?>', '', content), 'html5lib')
def normalize_navigation_markup(soup):
"""Remove only our generated wrappers around nested NAV labels.
Reader TOC parsers expect li > a + ol. A generated li > span > a
retains a valid href but is interpreted as an unlinked section by Calibre.
This also upgrades source structures cached by earlier versions.
"""
for wrapper in list(soup.find_all('span', attrs={'data-translation-unit': 'true'})):
parent = wrapper.parent
if (parent and parent.name == 'li' and wrapper.find_parent('nav')
and parent.find('ol', recursive=False)
and wrapper.find('a', href=True, recursive=False)):
wrapper.unwrap()
def translation_targets(soup):
"""Choose disjoint leaf blocks; wrap mixed direct text without renaming containers.
A li containing p must never be extracted twice. Text before a nested list or
inside an otherwise bare body still needs its own unit.
"""
normalize_navigation_markup(soup)
for container in list(soup.find_all(list(TARGET_TAGS | {'body'}))):
if container.find_parent(list(SKIP_TAGS)):
if container.find_parent(list(SKIP_TAGS)) or container.find_parent('nav'):
continue
has_blocks = container.find(list(BLOCK_TAGS)) is not None
if container.name != 'body' and not has_blocks:
+3 -1
View File
@@ -10,7 +10,7 @@ import zipfile
from urllib.parse import unquote, urlsplit
from bs4 import NavigableString
from lxml import etree
from src.common.html import parse_html
from src.common.html import parse_html, normalize_navigation_markup
from src.common.data_model import ManifestEntry
from src.preprocessing.format_extractor import FormatExtractor
from src.assembly.package_writer import package_path
@@ -134,6 +134,8 @@ def prepare_navigation(original, structure, entries):
"""Enrich the manifest with canonical heading entries, never translate TOC duplicates."""
soups={r.href:parse_html(r.content) for r in structure.resources.values()
if r.media_type=='application/xhtml+xml' and r.content}
for soup in soups.values():
normalize_navigation_markup(soup)
resources={posixpath.normpath(unquote(r.href)):r for r in structure.resources.values()}
labels={}
def collect(document, href, label):