aboutsummaryrefslogtreecommitdiff
path: root/converter/extractors.py
diff options
context:
space:
mode:
Diffstat (limited to 'converter/extractors.py')
-rw-r--r--converter/extractors.py62
1 files changed, 62 insertions, 0 deletions
diff --git a/converter/extractors.py b/converter/extractors.py
index cd270a1..a564333 100644
--- a/converter/extractors.py
+++ b/converter/extractors.py
@@ -24,6 +24,14 @@ class Section(NamedTuple):
text: str
+class Book(NamedTuple):
+ """A book's metadata plus its titled sections."""
+
+ title: str
+ author: str
+ sections: List[Section]
+
+
def extract_text(file_path: Path) -> str:
"""Extract text from a book file based on its extension."""
extension = file_path.suffix.lower()
@@ -52,6 +60,60 @@ def extract_sections(file_path: Path) -> List[Section]:
return [Section(file_path.stem, extract_text(file_path))]
+def extract_book(file_path: Path) -> Book:
+ """Extract sections plus book-level metadata (title, author).
+
+ EPUB and PDF files carry embedded metadata; missing fields (and TXT
+ files, which have none) fall back to the file stem for the title and
+ an empty author.
+ """
+ title, author = "", ""
+ extension = file_path.suffix.lower()
+ if extension == ".epub":
+ title, author = _epub_metadata(file_path)
+ elif extension == ".pdf":
+ title, author = _pdf_metadata(file_path)
+ return Book(title or file_path.stem, author.strip(), extract_sections(file_path))
+
+
+def _epub_metadata(file_path: Path) -> tuple:
+ """Return (title, author) from an EPUB's Dublin Core metadata."""
+ try:
+ import ebooklib
+ from ebooklib import epub
+
+ book = epub.read_epub(str(file_path))
+ title = _first_dc_value(book.get_metadata("DC", "title"))
+ author = _first_dc_value(book.get_metadata("DC", "creator"))
+ return title, author
+ except Exception as exc:
+ logger.warning("Could not read EPUB metadata: %s", exc)
+ return "", ""
+
+
+def _pdf_metadata(file_path: Path) -> tuple:
+ """Return (title, author) from a PDF's document info dictionary."""
+ try:
+ from pypdf import PdfReader
+
+ reader = PdfReader(str(file_path))
+ info = reader.metadata or {}
+ title = str(info.get("/Title") or "")
+ author = str(info.get("/Author") or "")
+ return title, author
+ except Exception as exc:
+ logger.warning("Could not read PDF metadata: %s", exc)
+ return "", ""
+
+
+def _first_dc_value(entries) -> str:
+ """First value of an ebooklib DC metadata list: [(value, ...), ...]."""
+ if not entries:
+ return ""
+ value = entries[0][0]
+ return str(value).strip() if value else ""
+
+
def _extract_epub_chapters(file_path: Path) -> List[Section]:
"""Return one Section per EPUB spine document (chapter), in reading order."""
import ebooklib