Source repository: https://github.com/nowjon/epub-upgrade-docker
Watches a directory tree for .epub files, detects EPUB 2 from the OPF version inside the ZIP, and upgrades to EPUB 3 in place using Calibre ebook-convert.
After each push to the default branch, CI builds and pushes to GitHub Container Registry:
ghcr.io/nowjon/epub-upgrade-docker:latest
Pull:
docker pull ghcr.io/nowjon/epub-upgrade-docker:latestIf the package is private, log in first (use a GitHub personal access token with read:packages):
echo YOUR_GITHUB_TOKEN | docker login ghcr.io -u nowjon --password-stdindocker run -d \
--name epub-upgrade-watcher \
--restart unless-stopped \
-e WATCH_PATH=/data \
-e CONVERT_EXISTING=false \
-e USE_POLLING=true \
-v /mnt/user/Media/Audiobooks:/data \
ghcr.io/nowjon/epub-upgrade-docker:latestSet CONVERT_EXISTING=true once to scan the whole tree for EPUB 2 files at startup.
| Variable | Default | Description |
|---|---|---|
WATCH_PATH |
/data |
Root to watch |
CONVERT_EXISTING |
false |
Full recursive scan on startup |
USE_POLLING |
true |
Use polling (better on NAS / mergerfs) |
POLL_INTERVAL_SECONDS |
10 |
Polling interval |
EVENT_DEBOUNCE_SECONDS |
2 |
Debounce after file events |
FILE_STABLE_SECONDS |
5 |
Wait for file size to stabilize |
SKIP_STORYTELLER_BUNDLES |
true |
Skip large “storyteller”-style EPUBs that embed audio |
STORYTELLER_NAME_MARKER |
storyteller |
Case-insensitive substring in the filename (both required with size below) |
STORYTELLER_MAX_SIZE_MB |
50 |
Skip only if the filename contains the marker and size is greater than this many MiB |
See docker-compose.yml for a template. To use the published image instead of a local build, set:
image: ghcr.io/nowjon/epub-upgrade-docker:latest
and remove or comment out the build: section.
Calibre conversion may normalize HTML/CSS. Keep backups if you need bit-identical files.