sync_bookmarks.md documented a request shape the handler never accepted. - Document the real body: book_uuid/book_sha256 (either required, SHA-256 is format-aware), plus separate bookmarks/notes/highlights arrays using the shared KOReader annotation shape (pos0/pos1, page, text, type, per-annotation book_sha256, dedup_key, percentage) - Document color semantics from 178fb2e/dafcadd: KOReader palette names map to web hex swatches at the boundary, echoes carry no color so stored web colors survive round-trips, explicit colors are device edits - koreader-protocol.md: cross-link the bookmark shape/color/dedup rules from the progress-sync field table
102 lines
4.4 KiB
Markdown
102 lines
4.4 KiB
Markdown
# Sync Bookmarks
|
|
|
|
Sync bookmarks, notes, and highlights from a KOReader device (bidirectional — the response also returns the server's current state for the book so the device can reconcile).
|
|
|
|
**Endpoint**: `POST /api/sync/koreader/bookmarks`
|
|
**Auth**: Device token (Bearer)
|
|
|
|
## Request Body
|
|
|
|
| Field | Type | Required | Description |
|
|
| ------------ | ------ | --------------------- | ----------------------------------------------------------------- |
|
|
| book_uuid | string | one of uuid/sha | Book UUID (highest-confidence match) |
|
|
| book_sha256 | string | one of uuid/sha | Full-file SHA-256 (64 hex chars); format-aware (also matches `media_item_formats`, so a KEPUB/PDF download matches) |
|
|
| bookmarks | array | No | Bookmark objects |
|
|
| notes | array | No | Note objects |
|
|
| highlights | array | No | Highlight objects |
|
|
|
|
At least one of `book_uuid` or `book_sha256` is required; `book_sha256` resolves through the shared BookResolver.
|
|
|
|
### Bookmark / Note / Highlight Object
|
|
|
|
All three types share the same KOReader annotation shape:
|
|
|
|
| Field | Type | Required | Description |
|
|
| ------------ | ------- | -------- | ---------------------------------------------------- |
|
|
| chapter | int | No | Chapter index |
|
|
| datetime | string | No | ISO 8601 creation/edit timestamp |
|
|
| pos0 / pos1 | string | No | Start/end xpointer (or `page:N` / bare page) |
|
|
| page | int | No | Page number (fallback location when `pos0` is empty) |
|
|
| text | string | No | Highlighted text |
|
|
| notes | string | No | Note text attached to the annotation |
|
|
| type | string | No | Annotation type (`highlight`, `note`, `bookmark`) |
|
|
| color | string | No | Highlight color (highlights only) — KOReader palette name, see below |
|
|
| percentage | float | No | Position within the book (0-1) |
|
|
| book_sha256 | string | No | Per-annotation SHA-256; overrides the request-level book match |
|
|
| dedup_key | string | No | Stable echo key; an entry whose content is unchanged from what the server previously served is recognized as an echo rather than a new edit |
|
|
|
|
### Color Semantics
|
|
|
|
KOReader paints highlights from a fixed palette of color names; the web reader uses hex swatches. Colors are mapped at the boundary (unmappable values fall back to yellow on both sides):
|
|
|
|
| KOReader name | Web hex |
|
|
| ------------- | --------- |
|
|
| yellow, orange | `#ffd54f` |
|
|
| green, olive | `#a5d6a7` |
|
|
| cyan, blue | `#90caf9` |
|
|
| purple | `#ce93d8` |
|
|
| red | `#f48fb1` |
|
|
|
|
- An echo (device re-reporting an annotation it received from the server) carries **no color**, so the stored web color is never clobbered.
|
|
- A non-empty color means the user edited the highlight on the device; it is mapped to the nearest web swatch.
|
|
|
|
### Example Request
|
|
|
|
```json
|
|
{
|
|
"book_sha256": "64-hex-char-sha256",
|
|
"bookmarks": [
|
|
{
|
|
"chapter": 3,
|
|
"datetime": "2026-08-20T10:00:00Z",
|
|
"pos0": "/body/Doc[4]/Sec[2]",
|
|
"page": 25,
|
|
"text": "",
|
|
"type": "bookmark",
|
|
"percentage": 0.125
|
|
}
|
|
],
|
|
"highlights": [
|
|
{
|
|
"datetime": "2026-08-20T10:05:00Z",
|
|
"pos0": "/body/Doc[4]/Sec[2]/text()[3]:0",
|
|
"pos1": "/body/Doc[4]/Sec[2]/text()[3]:42",
|
|
"text": "Text to remember",
|
|
"notes": "Why this matters",
|
|
"type": "highlight",
|
|
"color": "blue",
|
|
"dedup_key": "echo-key-from-server"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
## Response (200 OK)
|
|
|
|
```json
|
|
{
|
|
"sync_status": "ok",
|
|
"bookmarks_synced": 1,
|
|
"notes_synced": 0,
|
|
"highlights_synced": 1
|
|
}
|
|
```
|
|
|
|
## Error Responses
|
|
|
|
| Code | Description |
|
|
| ---- | -------------------------------------------------- |
|
|
| 400 | Invalid request, or neither uuid nor SHA provided |
|
|
| 401 | Missing/invalid device token |
|
|
| 404 | Book not found by SHA-256 |
|