diff --git a/README.md b/README.md index 4c3a75e..43b60e8 100644 --- a/README.md +++ b/README.md @@ -1,77 +1,92 @@ # mediapreview -Low-level media preview converters plus an optional persistent worker pool -framework. All converters produce AVIF output. +Generate compact AVIF preview images from images, videos, PDFs and office documents. -## Layout +`mediapreview` is a small library of low-level converters. Give it a file path and +it returns AVIF bytes plus a response object telling you which backend handled it +and whether it succeeded. -| Module | Purpose | -|--------|---------| -| `mediapreview.backends.image` | Image → AVIF via pyvips (ffmpeg for HEIC/HEIF/AVIF) | -| `mediapreview.backends.video` | Video frame → AVIF via PyAV (HDR preserved) | -| `mediapreview.backends.pdf` | PDF/XPS/EPUB page → AVIF via PyMuPDF + pyvips | -| `mediapreview.backends` | `dispatch()` — pick a backend by path/mimetype | -| `mediapreview.formats` | Suffix sets, previewability and priority classification | -| `mediapreview.office` | OnlyOffice Document Server client + Docker bootstrap | -| `mediapreview.docker/` | Patched OnlyOffice image build context (ships in the wheel) | -| `mediapreview.pool` | Async persistent subprocess worker pool (optional) | -| `mediapreview.worker` | Worker subprocess entry point (framed stdin/stdout protocol) | -| `mediapreview.protocol` | msgspec wire structs (`PreviewRequest` / `PreviewResponse`) | -| `mediapreview.cache` | Thread-safe LRU cache for preview responses | +## Install -## Extras - -```bash -pip install mediapreview # image converter only (pyvips) -pip install mediapreview[pdf] # + PDF/XPS/EPUB (pymupdf) -pip install mediapreview[video] # + video (av, numpy) -pip install mediapreview[office] # + OnlyOffice client (httpx, pyjwt) -pip install mediapreview[worker] # + worker pool (blake3, tracerite) -pip install mediapreview[standard] # everything +```sh +uv add mediapreview[standard] ``` -## Usage +`[standard]` pulls in every backend and the optional worker pool. Use the feature-specific extras to avoid dependencies not needed for your application. -Low-level, in-process: +## Quick start ```python +from pathlib import Path from mediapreview import dispatch -avif_bytes, resp = dispatch(path, quality=60, maxsize=512, maxzoom=2.0) +avif_bytes, resp = dispatch( + Path("photo.jpg"), + quality=60, + maxsize=512, + maxzoom=2.0, +) + +if resp.ok: + Path("preview.avif").write_bytes(avif_bytes) +else: + print(resp.error) ``` -Worker pool (isolates heavy imports and native crashes from the async loop): +`dispatch` picks the backend from the file extension or mimetype. You can also +call the backend functions directly: ```python -from mediapreview.pool import start_preview_workers, shutdown_preview_workers +from mediapreview import process_image, process_pdf, process_video + +avif, resp = process_image(Path("photo.jpg"), maxsize=512, quality=60) +avif, resp = process_pdf(Path("doc.pdf"), maxsize=512, quality=60, page_number=0) +avif, resp = process_video(Path("clip.mp4"), maxsize=512, quality=60) ``` -One-shot CLI (works with the base install, no worker extra needed): +## Worker pool (optional) + +Heavy native dependencies and crashes stay out of your async loop by running +previews in a pool of persistent subprocess workers. + +```python +from mediapreview.pool import ( + start_preview_workers, + shutdown_preview_workers, + run_preview, +) + +await start_preview_workers() +try: + avif, resp = await run_preview(Path("doc.pdf")) +finally: + await shutdown_preview_workers() +``` + +Add the `worker` extra to use the pool. + +## CLI ```bash -mediapreview photo.jpg -o preview.avif # or: python -m mediapreview ... -mediapreview doc.pdf -q 70 --maxsize 1024 # needs the matching backend extra +mediapreview photo.jpg -o preview.avif +mediapreview doc.pdf -q 70 --maxsize 1024 +mediapreview oosetup # build + run the bundled OnlyOffice container ``` -## OnlyOffice Docker bootstrap +## OnlyOffice setup -A patched OnlyOffice image (configurable converter worker count) ships as -package data and can be built/started with: +Office previews need an OnlyOffice Document Server. A patched Docker image ships +inside the package and can be started with: ```bash -mediapreview oosetup # builds + runs "onlyoffice-mediapreview" on port 8988 +mediapreview oosetup [name] [port] ``` -Container name and port are optional positional args: -`mediapreview oosetup [name] [port]`. - -`oosetup` logs progress to stderr and prints exactly one line on stdout: +`oosetup` logs to stderr and prints one line on stdout: ``` ONLYOFFICE_JWT_SECRET= ``` -If `ONLYOFFICE_JWT_SECRET` is already set in the environment it is used as-is -(and echoed back); otherwise a random secret is generated. Persist the token -wherever your deployment keeps its configuration and export it for later runs -— the caller owns the secret, mediapreview does not store it. +Set `ONLYOFFICE_JWT_SECRET` yourself to reuse an existing secret; otherwise a +random one is generated. diff --git a/pyproject.toml b/pyproject.toml index e5d08e3..82c0df4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "hatchling.build" [project] name = "mediapreview" dynamic = ["version"] -description = "Low-level media preview converters and a worker pool framework" +description = "Fast media preview images of photos, videos, PDFs and office documents." readme = "README.md" requires-python = ">=3.11" dependencies = [