Implements first-class ebook requests with their own type, parent-child relationship to audiobook requests, and separate status flow. Updates database schema and migrations to support 'type' and 'parentRequestId' fields on requests. Adds processors and job types for ebook search and direct HTTP download from Anna's Archive, with FlareSolverr integration for Cloudflare bypass. Enhances admin UI tables and request actions to display and manage ebook requests, including orange badge and source links. Updates documentation to reflect new ebook support, configuration, and behavior.
5.9 KiB
E-book Support
Status: ✅ Implemented | First-class ebook requests with Anna's Archive integration
Overview
Ebooks are first-class citizens in RMAB, with their own request type, tracking, and UI representation. When an audiobook request completes, an ebook request is automatically created (if enabled). Ebooks are downloaded directly from Anna's Archive via HTTP.
Key Details
First-Class Ebook Requests
- Request Type:
type: 'ebook'(vs'audiobook') - Parent Relationship: Ebook requests are children of audiobook requests (
parentRequestId) - Terminal State:
downloaded(ebooks don't have "available" state like audiobooks) - UI Badge: Orange (#f16f19) ebook badge to distinguish from audiobooks
- Separate Tracking: Own progress, status, and error handling
Flow
- Audiobook organization completes
- Ebook request created automatically (if enabled)
search_ebookjob searches Anna's Archivestart_direct_downloaddownloads via HTTPorganize_filescopies to audiobook folder- Request marked as
downloaded(terminal) - "Available" notification sent
Configuration
Admin Settings → E-book Sidecar tab
| Key | Default | Options | Description |
|---|---|---|---|
ebook_sidecar_enabled |
false |
true/false |
Enable feature |
ebook_sidecar_preferred_format |
epub |
epub, pdf, mobi, azw3, any |
Preferred format |
ebook_sidecar_base_url |
https://annas-archive.li |
URL | Base URL |
ebook_sidecar_flaresolverr_url |
`` (empty) | URL | FlareSolverr proxy (optional) |
Database Schema
Request model additions:
type String @default("audiobook") // 'audiobook' | 'ebook'
parentRequestId String? @map("parent_request_id")
parentRequest Request? @relation("EbookParent", fields: [parentRequestId], references: [id])
childRequests Request[] @relation("EbookParent")
Indexes: type, parentRequestId
Job Processors
search_ebook
- Searches Anna's Archive by ASIN first, then title + author
- Creates download history record with
downloadClient: 'direct' - Triggers
start_direct_downloadjob
start_direct_download
- Downloads file via HTTP with progress tracking
- Tries multiple slow download links on failure
- Triggers
organize_fileson success
monitor_direct_download
- Future use for async download monitoring
- Currently, most tracking happens in start_direct_download
Ranking Algorithm
Ebook ranking (for future multi-source support):
- Format Score: 40 pts (exact match) to 10 pts (different format)
- Size Score: 30 pts (inverse - smaller files preferred)
- Source Score: 30 pts (Anna's Archive gets full score)
Delete Behavior
Ebook deletion is different from audiobook deletion:
- Only deletes ebook files (
.epub,.pdf,.mobi, etc.) - Does NOT delete the title folder (audiobook files remain)
- Does NOT delete from backend library (Plex/ABS)
- Does NOT clear audiobook availability linkage
- Soft-deletes the ebook request record
UI Representation
RequestCard
- Orange ebook badge displayed next to status badge
- Orange book icon for placeholder cover art
- Interactive search disabled (Anna's Archive only)
Status Flow
pending → searching → downloading → processing → downloaded (terminal)
↘ awaiting_search (retry) ↗
FlareSolverr Integration
Anna's Archive uses Cloudflare protection. FlareSolverr bypasses this using a headless browser.
Setup
docker run -d --name flaresolverr -p 8191:8191 ghcr.io/flaresolverr/flaresolverr:latest
Configure URL in Admin Settings → E-book Sidecar: http://localhost:8191
Performance
- First request: ~5-10 seconds
- Subsequent: ~2-5 seconds per page
- Total: ~15-30 seconds per ebook
Scraping Strategy
Method 1: ASIN Search (exact match)
Search: https://annas-archive.li/search?ext=epub&lang=en&q="asin:B09TWSRMCB"
↓
MD5 Page: https://annas-archive.li/md5/[md5]
↓
Slow Download: https://annas-archive.li/slow_download/[md5]/0/5
↓
File Server: http://[server]/path/to/file.epub
Method 2: Title + Author (fallback)
Search: https://annas-archive.li/search?q=Title+Author&ext=epub&lang=en
↓ (Same flow from MD5 page)
File Naming
Pattern: [Title] - [Author].[format]
Sanitization:
- Remove:
<>:"/\|?* - Collapse spaces, trim, limit to 200 chars
Error Handling
Non-blocking errors:
- No search results → Request goes to
awaiting_searchfor retry - All downloads fail → Same retry behavior
- Audiobook organization never affected
Technical Files
Processors:
src/lib/processors/search-ebook.processor.tssrc/lib/processors/direct-download.processor.tssrc/lib/processors/organize-files.processor.ts(ebook branch)
Services:
src/lib/services/ebook-scraper.tssrc/lib/services/job-queue.service.ts(ebook job types)
Utils:
src/lib/utils/file-organizer.ts(organizeEbookmethod)src/lib/utils/ranking-algorithm.ts(rankEbooksfunction)
UI:
src/components/requests/RequestCard.tsx(ebook badge)
Delete:
src/lib/services/request-delete.service.ts(ebook-specific logic)
Format Support
| Format | Extension | Recommended |
|---|---|---|
| EPUB | .epub |
✅ Yes |
.pdf |
⚠️ Sometimes | |
| MOBI | .mobi |
⚠️ Legacy |
| AZW3 | .azw3 |
⚠️ Sometimes |
Limitations
- Single source (Anna's Archive) - future Prowlarr support stubbed
- Title search may return wrong book for common titles
- Download speed depends on file server load
- English books only (title search filter)
Related
- File Organization - Ebook organization
- Settings Pages - Configuration UI
- Ranking Algorithm - Ebook ranking
- Request Deletion - Delete behavior