Metadata-Version: 2.5
Name: pro-ledin-ebook-import
Version: 0.4.0
Summary: Deterministic EPUB, FB2, and MOBI-family importer for AI-agent-readable Markdown corpora.
Project-URL: Homepage, https://github.com/ledin-pro/ebook-import
Project-URL: Repository, https://github.com/ledin-pro/ebook-import
Author: mxl
License-Expression: MIT
License-File: LICENSE
Keywords: ai-agents,azw3,ebooks,epub,fb2,markdown,mobi,obsidian
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Text Processing :: Markup :: Markdown
Requires-Python: >=3.10
Requires-Dist: defusedxml<1,>=0.7.1
Provides-Extra: dev
Requires-Dist: hypothesis>=6.0; extra == 'dev'
Requires-Dist: jsonschema<5,>=4.25; extra == 'dev'
Requires-Dist: pytest-cov>=6.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Description-Content-Type: text/markdown

# pro-ledin-ebook-import

[![skills.sh](https://skills.sh/b/ledin-pro/ebook-import)](https://skills.sh/ledin-pro/ebook-import)

Deterministic ebook-to-Markdown importing for Obsidian vaults and AI-agent
workflows. The importer preserves source order and text, copies each original
ebook into the generated book directory, extracts referenced media when chosen,
and records SHA-256 metadata for repeatable rebuilds.

- Input formats: EPUB, FB2, FB2.ZIP/FBZ, DRM-free MOBI, AZW, and AZW3
- Import name: `pro.ledin.ebook_import`
- Console script: `ebook-import`
- PyPI: `pro-ledin-ebook-import`
- Skill: [`skills/ebook-import/SKILL.md`](skills/ebook-import/SKILL.md)

## Install

```bash
pip install pro-ledin-ebook-import
```

EPUB and FB2 imports work after the Python package is installed. FB2 parsing
uses the small `defusedxml` dependency to reject XML entity and DTD attacks.

MOBI, AZW, and AZW3 require one separately installed converter. The importer
prefers `mobitool` and falls back to Calibre:

```bash
brew install libmobi                    # macOS, preferred
sudo apt install libmobi-tools          # Debian/Ubuntu, preferred when available
```

Calibre is available for macOS, Linux, and Windows from
https://calibre-ebook.com/download. The package invokes these tools as separate
processes and does not bundle or import their LGPL/GPL code.

Check the current machine:

```bash
ebook-import doctor --json
```

## Parser API

The package also exposes a filesystem-independent typed parsing API for other
renderers and document systems:

```python
from pro.ledin.ebook_import import Heading, Paragraph, parse_book

book = parse_book("/path/to/book.fb2")
for chapter in book.chapters:
    print(chapter.title, len(chapter.blocks))
    print(chapter.markdown)
```

`ParsedChapter.blocks` contains immutable headings, paragraphs, groups, quotes,
poems, tables, images, links, and footnotes. `chapter.markdown` is generated from
the same typed model for compatibility with the Obsidian corpus renderer.

## Import

Preview without writing to the vault:

```bash
ebook-import import \
  --vault-root "/path/to/vault" \
  --output-dir "05-sources/books" \
  --image-mode import \
  --dry-run \
  --input "/path/to/book.epub" "/path/to/book.fb2" "/path/to/book.mobi"
```

Run the import after reviewing the JSON result:

```bash
ebook-import import \
  --vault-root "/path/to/vault" \
  --output-dir "05-sources/books" \
  --image-mode import \
  --input "/path/to/book.epub" "/path/to/book.fb2" "/path/to/book.mobi"
```

Choose a MOBI backend explicitly when needed:

```bash
ebook-import import \
  --vault-root "/path/to/vault" \
  --mobi-backend mobitool \
  --input "/path/to/book.azw3"
```

`--mobi-backend` accepts `auto`, `mobitool`, or `calibre`. `auto` prefers
`mobitool`, then retries with Calibre for ordinary conversion failures. It does
not retry or bypass DRM/encryption failures.

## Image policy

Use `--image-mode import` to extract referenced images or `--image-mode skip`
to omit image files and Markdown image markers.

## Format behavior

### EPUB

EPUB spine order defines chapter order. OPF metadata, NCX chapter titles,
common XHTML formatting, links, and referenced images are converted using the
package's deterministic standard-library serializer.

### FB2

Each top-level content section becomes one chapter file. Nested sections remain
headings. The parser preserves common inline formatting, epigraphs, citations,
poem stanza/verse lines, localized notes bodies, links, tables, embedded binary
images, and cover metadata. Compressed `.fb2.zip` and `.fbz` inputs must contain
exactly one `.fb2` payload and pass archive safety limits.

### MOBI, AZW, and AZW3

The selected external converter creates a temporary EPUB, which is passed
through the native EPUB parser. The corpus keeps the original MOBI-family file,
hashes the original bytes, records converter/version provenance, and removes the
temporary EPUB.

DRM-protected books, KFX, AZW4 Print Replica, and PRC are unsupported. The tool
does not remove DRM and does not provide instructions for doing so.

## Output

```text
05-sources/books/
├── index.md
└── <book-slug>/
    ├── book.md
    ├── manifest.json
    ├── original/book.<source-extension>
    ├── chapters/*.md
    └── media/*
```

The manifest records input format, original path, source hash, image mode,
chapters, media, warnings, and MOBI converter provenance when applicable.
Repeated imports with the same source hash, importer version, and image mode are
no-ops. Changing image mode or importer output version rebuilds generated files.

Books with the same metadata title do not overwrite one another: later
collisions receive a deterministic format suffix.

## Docling integration

Use the separate [`docling-ebook`](https://github.com/ledin-pro/docling-ebook)
package and skill when an ebook request explicitly requires Docling output or
OCR/image-text extraction. `ebook-import` does not duplicate those behaviors.

```bash
pip install pro-ledin-docling-ebook
docling-ebook book.fb2 --images referenced --to md --output-dir ./out
```

The integration is kept separate so this parser and Obsidian importer remain
lightweight and deterministic.

## Development

```bash
uv sync --extra dev
uv run --extra dev pytest -q -m "not external"
uv run --extra dev pytest \
  --cov=pro.ledin.ebook_import --cov-branch --cov-report=json
uv run python scripts/check_coverage.py coverage.json
uv build
```

Real MOBI integration requires both converters:

```bash
EBOOK_IMPORT_EXTERNAL_TESTS=1 \
  uv run --extra dev pytest -q tests/test_real_mobi_tools.py
```

CI tests Python 3.10-3.14, enforces at least 90% statement and 85% branch
coverage, runs hostile-input and property tests, builds both distributions, and
runs a dedicated real-converter integration job.

## License

MIT
