CalibreSync
Automatically sync eBooks from a remote Linux host to your Calibre-Web library.
CalibreSync connects to a remote host over SFTP, downloads new zip archives, extracts the RAR files inside them, and uploads the resulting epub/pdf files to Calibre-Web — skipping anything already uploaded. A web dashboard lets you monitor runs, browse uploaded books, and configure everything including the sync schedule.
Features
- Incremental sync — tracks processed archives in SQLite, never re-downloads or re-uploads
- Duplicate prevention — SHA-256 hash check before every upload
- Automatic schedule — configure a run interval (e.g. every 60 minutes) from the dashboard
- SSH key auth — paste your private key directly in the UI, never written to disk
- Dark web dashboard — live stats, sync history, books table, settings
- Docker ready — single
docker compose upto get started
Screenshots
| Dashboard | Settings |
|---|---|
| Stats, recent runs, zip history | SSH, Calibre-Web, schedule |
Requirements
- Docker (recommended) or Python 3.12+ with
unrar-free/unrarinstalled - A running Calibre-Web instance with uploads enabled
- SSH access to the remote host holding the zip archives
Quick start with Docker
git clone https://git.skitnerdig.com/YOUR_USERNAME/calibresync.git
cd calibresync
docker compose up -d
Open http://localhost:8000 and go to Settings to configure:
- Remote host — hostname, port, username, SSH key or password, remote zip directory path
- Calibre-Web — URL, username, password
- Schedule — how often to run automatically (in minutes, 0 = manual only)
Then click Run Sync Now on the dashboard, or wait for the scheduler to fire.
The SQLite database is stored in ./data/ and survives container restarts.
Running without Docker
# Debian / Ubuntu
sudo apt install unrar-free
pip install -r requirements.txt
uvicorn main:app --reload
Open http://localhost:8000 and follow the same setup steps.
RAR5 archives:
unrar-freehandles RAR4. For RAR5 you need the non-freeunrarpackage. See the comment in the Dockerfile for instructions.
How it works
Remote host (SFTP, read-only)
└── *.zip
└── *.rar
├── book.epub
└── book.pdf
└── Calibre-Web (/upload)
- SFTP scan — recursively lists all
.zipfiles under the configured remote path - Filter — skips any zip already recorded in the local SQLite database
- Download — fetches new zips to a local work directory
- Extract — unzips, then unrars, collects all
.epuband.pdffiles - Upload — checks SHA-256 hash against the database; uploads new files to Calibre-Web
- Cleanup — removes local temporary files after each zip is processed
Remote files are never modified or deleted.
Project structure
calibresync/
├── main.py # FastAPI app — dashboard, settings, sync trigger
├── sync.py # Orchestration loop
├── sftp.py # SFTP connection and download
├── extractor.py # unzip + unrar
├── uploader.py # Calibre-Web API client
├── db.py # SQLite schema and helpers
├── config.py # Settings loader/saver
├── templates/ # Jinja2 HTML templates
├── static/ # CSS
├── Dockerfile
└── docker-compose.yml
Dashboard pages
| Page | URL | Description |
|---|---|---|
| Dashboard | / |
Stats, recent sync runs, recent zip archives |
| Books | /books |
All uploaded books with status and source |
| Settings | /settings |
All configuration |
| API status | /api/status |
JSON status endpoint |
| API docs | /docs |
Auto-generated FastAPI docs |
License
MIT