When a Kobo device pushes a last-read-place bookmark, the server now converts the KEPUB CFI (with koboSpan wrappers) to a standard EPUB CFI and extracts surrounding text as context_text for use by other devices (KOReader, web reader) during their pull-side CFI conversions. Previously the raw KEPUB CFI was stored verbatim as epubcfi, which meant foliate and CREngine couldn't resolve it (wrong child indices due to koboSpan wrappers), and no context_text was available for the text-search fallback in ConvertStandardToCRE. Changes: - kepub_cfi_converter.go: Add ExtractedContext field to KEPUBConversionResult, populated from the already-computed searchText in both ConvertKEPUBCFIToStandard and ConvertStandardCFIToKEPUB (exact-match and percentage-fallback paths). - kobo.go: Add libraryService field and SetLibraryService setter (mirrors KOReaderHandler pattern). Add convertKoboCFIToStandard helper that resolves EPUB+KEPUB paths, instantiates the converter, and returns the converted CFI + extracted context. The last-read-place branch in Markup now calls this helper for reflowable formats, skipping fixed-layout/comic archives (page-index only). - router.go: Add LibraryService to router Config. - sync.go: Wire LibraryService to KoboHandler via SetLibraryService. - main.go: Pass libraryService through router config. The conversion is purely additive — if no KEPUB file exists on disk (e.g. side-loaded EPUB without kepubify conversion), the handler gracefully skips conversion and stores the raw CFI as before.
📚 Bookhoard
A modern self-hosted media library system built with Go, PostgreSQL, HTMX, and Tailwind CSS featuring universal cross-device sync, beautiful dark themes, and comprehensive media management.
✨ Why Bookhoard?
🔄 Universal Sync: Your reading progress, highlights, and notes sync automatically across all your devices - KOReader, Kobo, web, and mobile.
📱 Multi-Library: Organize your ebooks, comics, and manga with per-library folders and smart collections.
🎨 Beautiful UI: 11 gorgeous dark themes with responsive design that works on any device.
🔒 Secure: JWT authentication, bcrypt password hashing, rate limiting, and no passwords on devices.
🚀 Quick Start
Prerequisites
- Podman (recommended) or Docker
- 5 minutes of your time
Installation
# 1. Clone the repository
git clone https://github.com/yourusername/bookhoard.git
cd bookhoard
# 2. Set up environment
cp .env.example .env
# Generate secure passwords (no special characters):
# JWT_SECRET: openssl rand -hex 32
# DBPASS: openssl rand -hex 16
# Edit .env with your generated values
# 3. Start the server
podman-compose up --build -d # or: docker-compose up --build -d
# 4. Open your browser
open http://localhost:8765
The first user to register automatically becomes an admin.
📖 Key Features
Universal Cross-Platform Sync
- Real-Time Progress: Turn a page on your Kindle, see it on your phone
- Format-Aware: EPUB CFI, page numbers, percentages - all handled correctly
- Offline Queue: Changes sync when you reconnect, priority-processed
- Conflict Resolution: Smart handling when same book read on multiple devices
- Book Matching: Automatic matching using SHA-256, ISBN, UUID
- OPDS Catalog: Wireless book delivery to e-readers over Wi-Fi
- Format Conversion: On-the-fly EPUB→KEPUB for Kobo devices
Media Management
- Calibre Integration: Automatic metadata import from Calibre
metadata.opfsidecar files - Smart Search: Partial matching with fuzzy search fallback for typos
- Advanced Filtering: Filter by author, series, genre, language, year, cover images
- Dynamic Sorting: By title, author, date added, published date, page count, series
- Rich Metadata: Title, author, series, publisher, ISBN, language, edition, tags
- 5-Star Ratings: Half-star precision (1-10 scale)
- Notes & Highlights: Color-coded annotations with linked notes
- Usage Analytics: Reading statistics, device usage, popular books
Smart Collections
- Auto-Assign Rules: Automatically add books based on genre, author, series, tags, language, publisher, year
- Device Shelf Mappings: Sync collections to Kobo shelves and KOReader categories
- Test Before Creating: Preview which books match your rules
Library Organization
- Multi-Library Support: Ebooks, Comics, and Manga with type-specific file formats
- Multiple Folders: Add multiple scanning folders per library
- Visibility Control: Admins control which libraries each user can see
- Background Scanning: Auto-scan with per-user frequency settings
- Watch Mode: Real-time file system monitoring for instant updates
Security
- JWT Authentication: Short-lived access tokens (1 hour) with refresh tokens (7 days)
- Strong Passwords: Complexity requirements enforced (8+ chars, uppercase, lowercase, number, special)
- Account Lockout: 5 failed attempts = 15-minute lockout
- Rate Limiting: 10 requests/minute on auth endpoints
- Input Validation: Comprehensive validation on all inputs
- No Passwords on Devices: Web-based device approval with QR codes
📚 Documentation
For Users & Self-Hosters
- docs/user/calibre-integration.md - Calibre library integration
- docs/user/sync-guide.md - Understanding and using universal sync
- docs/user/devices/kobo-setup.md - Kobo e-reader configuration
- docs/user/devices/koreader-setup.md - KOReader configuration
- docs/user/user-guide.md - General user guide
- docs/user/admin-guide.md - Admin features and configuration
- docs/user/settings-guide.md - Settings and preferences
For Developers
- docs/developer/api/api-reference.md - Complete API documentation
- docs/contributing/DEVELOPMENT.md - Development workflow
🎯 Supported Devices
| Platform | Sync | OPDS | Status |
|---|---|---|---|
| Web Browser | ✅ | ✅ | Full support |
| KOReader | ✅ | ✅ | Kindle, Kobo, PocketBook |
| Kobo Devices | ✅ | ✅ | Clara, Libra, Sage, etc. |
| Mobile Apps | 🚧 | 🚧 | Coming Q2 2026 |
🛠 Tech Stack
- Backend: Go 1.25+ with Echo framework
- Database: PostgreSQL 15+ with pgx v5
- Frontend: HTMX + Tailwind CSS + Templ
- Auth: JWT tokens with bcrypt password hashing
- Container: Podman (Docker compatible)
🧪 Testing
# Run all tests
make test-all
# Run integration tests (with test mode)
make test-integration
# Run Bruno OpenCollection YAML API tests
npm install -g @usebruno/cli
bruno run
📊 Project Status
Version: 1.0
License: GPL-3.0
Status: Production-ready ✅
🤝 Contributing
We welcome contributions! Please see docs/DEVELOPMENT.md for guidelines.
📄 License
GPL-3.0 - See LICENSE file for details.
Built with ❤️ using Go, PostgreSQL, HTMX, and Tailwind CSS