[bug] Stdlib EPUB fallback skips encoded manifest hrefs

Author: Stamina9Created Sep 18, 2026Updated Sep 18, 2026
Labelsbug

What happened

The stdlib EPUB fallback reads each OPF manifest href as though it were the literal ZIP member name. OPF hrefs are references, so a fragment such as chapter.xhtml#section-2 is not part of the archive filename, and percent escapes such as Chapter%201.xhtml represent characters in that filename.

Both valid forms currently make ZipFile.read() look for a non-existent member. The per-document exception handler then silently skips the chapter; if every spine item uses one of these forms, extraction returns no text at all.

What you expected

The dependency-free EPUB fallback should resolve manifest references to their ZIP member names before reading them: decode XML entities and percent escapes, discard query/fragment components, and still resolve the resulting path relative to the OPF directory.

Source document

  • Format: EPUB (synthetic minimal fixtures)
  • Pages / size: one spine item per fixture
  • Language: English
  • Does python3 scripts/extract.py --check show the relevant extractor installed? not applicable; this is the stdlib fallback used without ebooklib

Repro

Create a minimal EPUB whose manifest contains either:

xml
<item id="c1" href="chapter.xhtml#section-2" media-type="application/xhtml+xml"/>

or an OPF in OEBPS/content.opf with:

xml
<item id="c1" href="Text/Chapter%201.xhtml" media-type="application/xhtml+xml"/>

while the corresponding ZIP members are chapter.xhtml and OEBPS/Text/Chapter 1.xhtml. On master (f08d343), both focused regressions return None instead of the chapter text.

Environment

  • OS: Windows 11 host / Linux clean-test environment
  • Python version: 3.12.10
  • book-to-skill version / commit: f08d343

Source: virgiliojr94/book-to-skill