diff options
| author | historia <historiavg@proton.me> | 2026-08-18 04:05:10 -0400 |
|---|---|---|
| committer | historia <historiavg@proton.me> | 2026-08-18 04:05:10 -0400 |
| commit | 50f1825f05972e3685c55beb10c288899959b2e5 (patch) | |
| tree | a5aa104d603ce9c710499184c133abe86497a16e /converter/extractors.py | |
| parent | 86d2eb8d789f82dd8e56dd0ff53933152ba94e6b (diff) | |
| download | tts-audiobook-generator-50f1825f05972e3685c55beb10c288899959b2e5.tar.gz | |
feat: add metadata to audio files including generated cover art
Diffstat (limited to 'converter/extractors.py')
| -rw-r--r-- | converter/extractors.py | 62 |
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 |
