Files
dify/api/libs/epub.py

33 lines
1.4 KiB
Python

"""Read EPUB chapters in spine order without extracting archive members to disk."""
import posixpath
from io import BytesIO
from urllib.parse import unquote, urlsplit
from zipfile import ZipFile
from defusedxml import ElementTree
from unstructured.documents.elements import Element
from unstructured.partition.html import partition_html
def partition_epub(file_path: str) -> list[Element]:
with ZipFile(file_path) as archive:
container = ElementTree.fromstring(archive.read("META-INF/container.xml"))
rootfile = container.find(".//{*}rootfile")
package_path = rootfile.get("full-path") if rootfile is not None else None
if not package_path:
raise ValueError("EPUB package path is missing")
package_path = unquote(urlsplit(package_path).path).lstrip("/")
package = ElementTree.fromstring(archive.read(package_path))
manifest = {item.attrib["id"]: item.attrib["href"] for item in package.findall(".//{*}manifest/{*}item")}
elements: list[Element] = []
for itemref in package.findall(".//{*}spine/{*}itemref"):
href = manifest[itemref.attrib["idref"]]
chapter_path = posixpath.normpath(
posixpath.join(posixpath.dirname(package_path), unquote(urlsplit(href).path))
).lstrip("/")
with BytesIO(archive.read(chapter_path)) as chapter:
elements.extend(partition_html(file=chapter))
return elements