Real-time audiobook sync from Audiobookshelf to BookWyrm.
Automatically sync your audiobook reading progress from Audiobookshelf to BookWyrm. When you update progress in Audiobookshelf, it's reflected in BookWyrm within minutes.
Key features:
- Real-time sync via polling (60s intervals)
- Auto-match books by ISBN, ASIN, or manual mapping
- Multi-user support with encrypted credentials
- Self-hosted, privacy-focused, no data sharing
- Includes bulk import tool for backfilling existing books
Status: Production ready (v1.0)
Audiobookshelf → Sync Service → BookWyrm
↓
SQLite DB
- Session-based auth to BookWyrm (not ActivityPub HTTP signatures)
- Multi-user from day one (database schema supports multiple accounts)
- Smart pause detection (inactivity, progress delta, explicit pause, completion)
- High confidence matching (90%+ required to prevent false positives)
- Built-in rate limiting (respects BookWyrm API limits)
See docs/ARCHITECTURE.md for detailed system design.
- Docker & Docker Compose 20.10+
- Audiobookshelf instance (HTTP/HTTPS accessible)
- BookWyrm instance (self-hosted or bookwyrm.social)
- Python 3.11+ (development only)
# Clone repo
git clone https://github.com/tcw3bb/Abs2Wyrm.git
cd Abs2Wyrm
# Setup config
cp .env.example .env
nano .env # See Configuration section below
# Create data directory with correct permissions (container runs as UID 1000)
mkdir -p data/logs
chown -R 1000:1000 data
# Start service
docker-compose up -d --build
# Check health
curl http://localhost:8000/health
# View logs
docker-compose logs -f audiobook-syncFor production deployment, see DEPLOYMENT.md.
Create .env from .env.example with these settings:
Minimal setup:
ABS_URL=http://your-abs-server:13378
BOOKWYRM_DOMAIN=bookwyrm.example.com
ENCRYPTION_KEY=<generated_key>
DATABASE_URL=sqlite+aiosqlite:////data/sync.db
DEFAULT_USER_USERNAME=myusername
DEFAULT_USER_ABS_API_KEY=<your_abs_token>
DEFAULT_USER_BOOKWYRM_USERNAME=myuser
DEFAULT_USER_BOOKWYRM_PASSWORD=<your_password>Generate ENCRYPTION_KEY:
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"Get Audiobookshelf API key: Settings → Account → Generate API Token
See docs/CONFIGURATION.md for complete reference with all options.
Sync flow:
- User plays audiobook in Audiobookshelf
- Poller detects progress changes (every 60s)
- Service matches book by ISBN/ASIN
- Updates progress in BookWyrm
- On completion: marks finished, moves to "read" shelf
Book matching strategy:
- ISBN match (highest confidence)
- ASIN match (high confidence)
- Manual mapping (user-defined)
- Future: fuzzy title+author match
See docs/ARCHITECTURE.md for detailed flow.
# Import finished books from Audiobookshelf
docker exec -it audiobook-sync python -m src.cli import-all-books
# Export mappings/history/stats
docker exec -it audiobook-sync python -m src.cli export --type mappings
# Backup database
docker exec -it audiobook-sync python -m src.cli backup
# Restore from backup
docker exec -it audiobook-sync python -m src.cli restore backup.dbSee docs/CLI.md for complete reference with examples.
# Validate Audiobookshelf metadata
./scripts/validate_abs_metadata.sh
# Backfill finished books to Bookwyrm
./scripts/sync_finished_books.shSee docs/BULK_OPERATIONS.md for details.
curl http://localhost:8000/health # Simple check
curl http://localhost:8000/status # Detailed status
curl http://localhost:8000/metrics # Prometheus metricsOptional: Get push notifications or send events to custom endpoints.
ENABLE_NTFY=true
NTFY_URL=https://ntfy.sh/your-topic
ENABLE_WEBHOOKS=true
WEBHOOK_URL=https://your-webhook.com/endpointSee docs/MONITORING.md for complete setup.
For books that don't auto-match (no ISBN/ASIN):
# Find book ID from logs
docker logs audiobook-sync | grep "No mapping found"
# Get BookWyrm book ID from URL: bookwyrm.example.com/book/1894739 → 1894739
# Create mapping
python3 manual_map_book.py <abs_id> <bookwyrm_id>users
├─ username, abs_api_key (encrypted), bookwyrm_username, bookwyrm_password (encrypted)
book_mappings
├─ abs_library_item_id, bookwyrm_book_id, bookwyrm_readthrough_id
sync_state
├─ last_progress (0-100%), last_synced_at, status (reading/paused/finished)
python3.11 -m venv venv && source venv/bin/activate
pip install -r requirements.txt -r requirements-dev.txt
pre-commit installpytest # Run tests
pytest --cov=src --cov-report=html # With coverage
black src/ tests/ && mypy src/ && flake8 src/ tests/ # LintingSee AGENTS.md for detailed development guidelines.
| Document | Content |
|---|---|
| ARCHITECTURE.md | System design, data flow, components |
| DEPLOYMENT.md | Production deployment guide |
| CLI.md | Command-line interface reference |
| BULK_OPERATIONS.md | Validation & backfill tools |
| MONITORING.md | Health checks, notifications, webhooks |
| CONFIGURATION.md | Complete config reference |
| AGENTS.md | Development guidelines & coding standards |
| TROUBLESHOOTING.md | Common issues & debugging |
✅ Encrypted credentials (Fernet/AES-128) ✅ No secrets in git ✅ CSRF protection on BookWyrm requests ✅ Rate limiting built-in ✅ Input validation (Pydantic) ✅ Pre-commit hooks detect secrets
Important: Keep ENCRYPTION_KEY secret and backed up. Credentials cannot be recovered without it.
See docs/SECURITY_IMPLEMENTATION_SUMMARY.md for details.
Authentication failures: Check credentials in .env. See TROUBLESHOOTING.md.
Books not syncing: Run validation script, verify ISBN/ASIN present, check rate limit. See TROUBLESHOOTING.md.
Progress not updating: Check MIN_PROGRESS_CHANGE threshold, pause detection timeout. See TROUBLESHOOTING.md.
MIT License - See LICENSE file
- Audiobookshelf - Self-hosted audiobook server
- BookWyrm - Federated social reading platform
- FastAPI - Web framework
- SQLAlchemy - Python ORM