Archived
- add uv configuration for the backend - update frontend to make auth work - add new auth endpoints - add bookmars feat - add reader feat
74 lines
2.6 KiB
Markdown
74 lines
2.6 KiB
Markdown
# 011 — Web reader (react-reader)
|
||
|
||
**Status:** Implemented
|
||
**Created:** 2026-06-03
|
||
|
||
## Objective
|
||
|
||
Replace the custom HTML chapter reader with [react-reader](https://github.com/gerhardsletten/react-reader) (epub.js) for paginated EPUB reading in the web app. Keep the existing toolbar and settings panel chrome. Block PDFs from the in-browser reader.
|
||
|
||
## Architecture
|
||
|
||
```
|
||
Library (EPUB only) → /read/:id → ReadingPage
|
||
→ GET /api/books/ebooks/{id}/ (metadata, format guard)
|
||
→ GET /api/books/ebooks/{id}/file/ (authenticated EPUB blob)
|
||
→ ReactReader (blob URL + CFI location)
|
||
→ PATCH /api/books/ebooks/{id}/progress/ (epub_location + percentage)
|
||
```
|
||
|
||
EPUB files are fetched with JWT via the API, converted to a blob URL client-side, and passed to react-reader. This avoids unauthenticated `/media/` URLs and CORS issues in dev.
|
||
|
||
## Backend changes
|
||
|
||
### `GET /api/books/ebooks/{id}/file/`
|
||
|
||
- Authenticated, owner-only
|
||
- Returns `FileResponse` with `Content-Type: application/epub+zip`
|
||
- Returns `400` if format is not `epub`
|
||
|
||
### `ReadingProgress.epub_location`
|
||
|
||
| Field | Type | Notes |
|
||
|-------|------|-------|
|
||
| `epub_location` | CharField(2048) | EPUB CFI string for resume position |
|
||
|
||
Exposed on `GET/PATCH /api/books/ebooks/{id}/progress/` and in `EBookDetail.progress`.
|
||
|
||
`current_position` stores whole-book percentage (0–100) derived from epub.js locations.
|
||
|
||
## Frontend changes
|
||
|
||
| File | Change |
|
||
|------|--------|
|
||
| `pages/ReadingPage.tsx` | `ReactReader` replaces chapter HTML rendering |
|
||
| `hooks/useEpubReader.ts` | Blob load, CFI state, debounced progress save |
|
||
| `utils/epubRendition.ts` | Theme/font application via `getRendition` |
|
||
| `api/books.ts` | `getEpubFile(id)` |
|
||
| `pages/Library.tsx` | Block PDF open with notice |
|
||
| `App.tsx` | Single route `/read/:id`; `/reader/:id` redirects |
|
||
|
||
### Removed (web-only)
|
||
|
||
- `useChapters.ts`, `TableOfContents.tsx`, `Reader.tsx`, `useReadingProgress.ts`
|
||
|
||
Backend `/toc/` and `/content/` endpoints remain for mobile/API consumers.
|
||
|
||
## EPUB-only policy
|
||
|
||
- Library: clicking a PDF shows a dismissible notice; no navigation to reader
|
||
- ReadingPage: deep-link guard if `format !== 'epub'`
|
||
- Upload still accepts PDF for storage; web reader is EPUB-only
|
||
|
||
## Dependencies
|
||
|
||
- Frontend: `react-reader` (^2.0.15)
|
||
|
||
## Verification
|
||
|
||
1. Open an EPUB from library → paginated reading, swipe/tap page turns, built-in TOC
|
||
2. Close and reopen → resumes at saved CFI
|
||
3. Change theme/font in settings → applies inside epub iframe
|
||
4. Click a PDF in library → notice shown, reader not opened
|
||
5. `GET /api/books/ebooks/{id}/file/` without auth → 401
|