Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7dc8189a1 | ||
|
|
a8641ab343 | ||
|
|
1ce66b2213 | ||
|
|
18f52d240b | ||
|
|
220d97cfe0 | ||
|
|
38efbff7e1 | ||
|
|
f4414aa5b6 | ||
|
|
3daa834a94 | ||
|
|
202a090811 | ||
|
|
ee98c0fb3b | ||
|
|
79ce5ab89d | ||
|
|
6216bd9bcf | ||
|
|
24228e7147 | ||
|
|
e1153b2c4b | ||
|
|
5b81e19f2f | ||
|
|
30ecdd4bf3 | ||
|
|
b2220756e2 | ||
|
|
d74db03cf3 | ||
|
|
9e831085ef | ||
|
|
327fc2c0f9 | ||
|
|
a31da89df5 | ||
|
|
a11b4a9cc4 | ||
|
|
040c10ac76 | ||
|
|
4a68fe7cab | ||
|
|
cb4e892b10 | ||
|
|
506a04b55d | ||
|
|
f1844591b4 | ||
|
|
1fdf306f2d | ||
|
|
b89eac22e3 | ||
|
|
d5bb874651 | ||
|
|
4f913da0b1 | ||
|
|
0799cca3e6 | ||
|
|
45b8542e25 | ||
|
|
8f05f1116e | ||
|
|
454938c31f | ||
|
|
8dbaa8f810 | ||
|
|
d2d92efd10 | ||
|
|
1d12a64915 | ||
|
|
29a546229d | ||
|
|
6b3bdef052 | ||
|
|
2ba1e0960b | ||
|
|
010c0cb287 | ||
|
|
c538efe722 | ||
|
|
87fc89a816 | ||
|
|
77cf0b827b | ||
|
|
18727fef93 | ||
|
|
b47a2b86a7 | ||
|
|
58fbe372e2 | ||
|
|
082a3e0c3c | ||
|
|
188ae076ab | ||
|
|
00305ffc7b | ||
|
|
edb4e60679 | ||
|
|
11609d13d1 | ||
|
|
7d698ea0d8 | ||
|
|
c579179fee | ||
|
|
ff029f1ad5 | ||
|
|
b2b89ba789 | ||
|
|
a13b268adc | ||
|
|
bdad40e211 | ||
|
|
8c56c9da55 | ||
|
|
0971e7debb | ||
|
|
5adfb459d7 | ||
|
|
2f9d5b8e45 | ||
|
|
c07dba4eff | ||
|
|
23765934ef | ||
|
|
1ce1b79489 | ||
|
|
de9e66636a | ||
|
|
14cdbe70eb | ||
|
|
09b6693505 | ||
|
|
63a20dcc95 | ||
|
|
a85bc8af9b | ||
|
|
6808c1babb | ||
|
|
d16ca4acbe | ||
|
|
721139dc16 | ||
|
|
8fc74c908a | ||
|
|
e83c00f869 | ||
|
|
28bd323505 | ||
|
|
a2ea34232c | ||
|
|
b4ae42326a | ||
|
|
ce366b1604 | ||
|
|
a222ef5c27 | ||
|
|
73ae1789c5 | ||
|
|
89665fb2bc | ||
|
|
2c714dcb60 | ||
|
|
5cf34102d6 | ||
|
|
86f0af632e | ||
|
|
902cbe5915 | ||
|
|
a093529b80 | ||
|
|
f2fd4db81c |
No files matched your search
@@ -82,3 +82,7 @@ session-*.md
|
||||
|
||||
# Local prod-export scratch: personal annotation/reading data, never commit
|
||||
/export/
|
||||
|
||||
# Binary media fixtures: never commit (generate with ffmpeg at test time,
|
||||
# see docs/contributing/development.md → Media fixtures)
|
||||
internal/services/testdata/
|
||||
@@ -4,6 +4,43 @@ Standing rules for any agent or developer working in this repo.
|
||||
Project-wide context lives in the sibling repos' AGENTS.md files
|
||||
(../bookhoard-app/AGENTS.md is the Android client's).
|
||||
|
||||
## Rendering ownership (templ vs TypeScript) — ALWAYS apply
|
||||
|
||||
The point of templ + htmx + Alpine is: the server renders the UI, and
|
||||
JavaScript is kept minimal. The rule that keeps it that way:
|
||||
|
||||
> **JavaScript decides what shows. templ decides what it looks like.**
|
||||
|
||||
- Content derived from **server data** (DB rows, search results, match
|
||||
lists, conflict cards, any list/card/badge/table) is rendered by
|
||||
templ. When it changes client-side, fetch a **templ partial** from an
|
||||
SSR route and swap it in (`htmx.ajax(...)`), never rebuild it from a
|
||||
JSON payload with `innerHTML` string templates.
|
||||
- **Pure functions of client-local state** (open/closed panels, tabs,
|
||||
password strength from a typed value, toasts) may render in
|
||||
TS/Alpine — no server round trip needed.
|
||||
- `web/src` is **TypeScript only** — no new `.js` source files.
|
||||
Vendored third-party and vite build output under `web/static` are
|
||||
exempt.
|
||||
- Inline `<script>` in a `.templ` file needs a reason a bundled module
|
||||
cannot do the job (pre-paint execution). Currently sanctioned:
|
||||
`theme_flash_guard.templ` only.
|
||||
|
||||
Sanctioned JS islands (engines, not UI renderers — exempt from the
|
||||
above): the reader (foliate-js + `web/src/reader/`), Chart.js graphs in
|
||||
stats, toasts, password validation. Anything else that renders app UI
|
||||
in TypeScript is a defect; if a templ twin of it exists, one of the two
|
||||
must be deleted.
|
||||
|
||||
**Documented exception — dashboard sections**: `renderDashboardCollections`
|
||||
/ `renderSectionHTML` in `web/src/dashboard.ts` re-render dashboard
|
||||
sections from `/api/dashboard/sections` JSON (library switch, settings
|
||||
save, refresh button) to preserve the switch fade/transition on a page
|
||||
with heavy interactivity. First-paint section markup is still templ
|
||||
(Dashboard handler in `internal/router/frontend.go`). This exception is
|
||||
deliberate; do not clone it to new pages, and do not "fix" the dashboard
|
||||
without restoring a templ-partial fade path first.
|
||||
|
||||
## Library visibility (family-lens rule) — ALWAYS apply
|
||||
|
||||
Per-user library visibility (`library_visibility` table, default-ALLOW:
|
||||
@@ -57,6 +94,24 @@ were name-only across ALL libraries. Fixed; do not regress.
|
||||
cleanups** — sync_integration's `DELETE FROM reading_history WHERE
|
||||
true` destroyed the live reader's stats data on every suite run
|
||||
until scoped to the test-sync users (cascade via user delete).
|
||||
- **RUN ONLY YOUR OWN TESTS while iterating**: integration tests
|
||||
require the containerized dev DB — a bare host `go test
|
||||
./cmd/server/tests` fails on auth on every machine not running the
|
||||
compose stack. Use the filtered container runner
|
||||
(`docker compose -f docker-compose.yml -f
|
||||
docker-compose.dev.yml --profile tests run --rm tests go test
|
||||
./cmd/server/tests -run 'TestYourPrefix' -v`) and save full-suite
|
||||
runs for pre-commit validation; several tests read live shared
|
||||
state (system_settings, real library folders, the periodic backup
|
||||
scan's websocket broadcasts) and flap on data/timing your change
|
||||
never touched. Full recipes: docs/contributing/development.md
|
||||
→ Testing.
|
||||
- **NEVER COMMIT BINARY MEDIA** (mp3/m4b/flac/... fixtures):
|
||||
`internal/services/testdata/` is gitignored by policy; generate
|
||||
media at test runtime with ffmpeg instead (test images ship it).
|
||||
ffmpeg cannot write Audible freeform atoms — those paths are unit-
|
||||
tested with synthetic ffprobeReport values. Recipes:
|
||||
docs/contributing/development.md → Media fixtures.
|
||||
|
||||
## Timezones
|
||||
|
||||
@@ -67,15 +122,40 @@ were name-only across ALL libraries. Fixed; do not regress.
|
||||
- Analytics day-buckets must bucket in the user's timezone
|
||||
(`CreatedAt.In(loc)`), and date-range end bounds must be end-of-day.
|
||||
|
||||
## Debug discipline (test-failure triage) — 2026-10-17
|
||||
|
||||
When a test or bruno request fails, suspect the TEST FIRST — most
|
||||
failures in this repo are harness/schema/environment drift, not server
|
||||
bugs (2026-10-17 bruno sweep: drifted body keys, bodies pre-truncated
|
||||
at their first `{{var}}`, missing `/api` prefixes; host runs hitting
|
||||
container-only paths/hostnames). Triage order: (1) read the
|
||||
test/fixture/payload schema and diff against a known-good sibling
|
||||
(bruno: the `NewDevDBSetup` files are the reference for `body.data`
|
||||
form); (2) check environment assumptions (host vs container,
|
||||
harness cleanup, live-DB traffic); (3) cheap probe (curl, one SQL
|
||||
query) before any deep dive.
|
||||
|
||||
But test changes are ASYMMETRIC with code changes: server code may be
|
||||
fixed freely when it is the bug; test/contract edits may only
|
||||
(a) fix harness plumbing, (b) WIDEN pins additively with a
|
||||
`docs/contract_pins.md` changelog entry, (c) delete tests of deleted
|
||||
behavior — never narrow an assertion or flip an expectation to match
|
||||
observed behavior. Contract pins were green at a known commit, so git
|
||||
history arbitrates "test stale vs code changed." If a test looks right
|
||||
but fails and no harness bug explains it, that is prima facie evidence
|
||||
of a server bug: stop and flag the user.
|
||||
|
||||
## Known gotchas (do not relearn)
|
||||
|
||||
1. **templ does NOT interpolate `{ expr }` inside quoted attribute
|
||||
values** — it emits the literal text. `x-init="f('{ col.ID }')"`
|
||||
shipped a request to `/api/collections/{ collection.ID }` found by
|
||||
the request logs; the whole attribute value must BE an expression:
|
||||
`x-init={ "f('" + col.ID + "')" }`. Note
|
||||
`class="theme-{ user.Theme }"` has always been literal (harmlessly
|
||||
masked by the JS theme engine).
|
||||
`x-init={ "f('" + col.ID + "')" }`. (Every occurrence of this bug —
|
||||
including `class="theme-{ user.Theme }"` on 22 page bodies and 26
|
||||
attribute interpolations — was swept and fixed in 2026-10; when
|
||||
adding attributes with dynamic values, the whole value is an
|
||||
expression, and free text goes through `templates.JSONArg`.)
|
||||
2. **SettingsRegistry caches**: writes must go through the settings
|
||||
API (Reload on save). Direct SQL writes to system_settings leave
|
||||
the cache stale until the next API-path write — never "preview"
|
||||
|
||||
+5
-2
@@ -59,7 +59,10 @@ RUN cp -r /go/pkg/mod /app/go-module-cache
|
||||
# This stage is ONLY used for running tests, never deployed to production
|
||||
FROM golang:1.26-alpine AS test-runner
|
||||
|
||||
RUN apk --no-cache add ca-certificates curl poppler-utils
|
||||
# ffmpeg/ffprobe match the runtime stage: the audio ingestion (tag
|
||||
# fallbacks, embedded covers, cue probing) must be exercised in tests
|
||||
# exactly as it runs in production.
|
||||
RUN apk --no-cache add ca-certificates curl poppler-utils ffmpeg
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -84,7 +87,7 @@ CMD ["go", "test", "./cmd/server/tests", "-v", "-timeout", "5m", "-parallel=1",
|
||||
# Final stage
|
||||
FROM alpine:latest
|
||||
|
||||
RUN apk --no-cache add ca-certificates curl poppler-utils
|
||||
RUN apk --no-cache add ca-certificates curl poppler-utils ffmpeg
|
||||
|
||||
# Install kepubify for EPUB→KEPUB conversion
|
||||
RUN wget -O /usr/bin/kepubify https://github.com/pgaskin/kepubify/releases/latest/download/kepubify-linux-64bit \
|
||||
|
||||
@@ -47,9 +47,34 @@ help:
|
||||
@echo " ./release v0.3.0 - Tag, push, and release (notes auto-generated from commits)"
|
||||
|
||||
# Run unit tests locally (fast, no containers)
|
||||
test:
|
||||
test: lint-rendering
|
||||
go test ./internal/... -v -short
|
||||
|
||||
# Rendering-ownership guard (AGENTS.md → Rendering ownership): templ renders
|
||||
# UI markup, JS orchestrates. Fails when a web/src file builds more HTML
|
||||
# template literals than its recorded baseline (web/src/rendering-allowlist.txt),
|
||||
# or when a .templ file gains an inline <script> block (theme_flash_guard.templ
|
||||
# is the only sanctioned one). Shrink baselines as fragments move to templ
|
||||
# partials; grow one only with a written reason.
|
||||
lint-rendering:
|
||||
@violations=""; \
|
||||
for f in $$(grep -rlE 'innerHTML[[:space:]]*=[[:space:]]*' web/src --include='*.ts' | grep -v 'web/src/reader/'); do \
|
||||
count=$$(grep -E 'innerHTML[[:space:]]*=[[:space:]]*' $$f | grep -cvE 'innerHTML[[:space:]]*=[[:space:]]*""[[:space:]]*$$'); \
|
||||
allowed=$$(grep -F "$$f:" web/src/rendering-allowlist.txt | cut -d: -f2); \
|
||||
allowed=$${allowed:-0}; \
|
||||
if [ $$count -gt $$allowed ]; then \
|
||||
violations="$$violations $$f ($$count > $$allowed)"; \
|
||||
fi; \
|
||||
done; \
|
||||
for f in $$(grep -rln '<script>' templates --include='*.templ'); do \
|
||||
case $$f in *theme_flash_guard*) continue;; esac; \
|
||||
violations="$$violations $$f (inline script)"; \
|
||||
done; \
|
||||
if [ -n "$$violations" ]; then \
|
||||
echo "rendering-ownership violations:$$violations"; exit 1; \
|
||||
fi; \
|
||||
echo "rendering ownership OK"
|
||||
|
||||
# Run integration tests in containers (matches production environment)
|
||||
test-integration:
|
||||
@echo "Building test containers..."
|
||||
|
||||
@@ -2,37 +2,36 @@ info:
|
||||
name: SetBaseUrl
|
||||
type: http
|
||||
seq: 3
|
||||
|
||||
http:
|
||||
method: PUT
|
||||
url: '{{base_url}}/api/system/config'
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: |-
|
||||
{
|
||||
"base_url": "http://localhost:8765"
|
||||
}
|
||||
data: "{\n \"base_url\": \"http://localhost:8765\"\n}"
|
||||
headers:
|
||||
- key: Authorization
|
||||
value: Bearer {{token}}
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
|
||||
settings:
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
followRedirects: true
|
||||
maxRedirects: 5
|
||||
docs: '## Set Base URL
|
||||
|
||||
docs: |-
|
||||
## Set Base URL
|
||||
|
||||
Configures the server's base_url during initial dev database setup.
|
||||
Configures the server''s base_url during initial dev database setup.
|
||||
|
||||
|
||||
Must be run after RegisterUser (which provides the auth token) and before
|
||||
|
||||
any library/device creation (which require setup to be complete).
|
||||
|
||||
|
||||
**Method:** PUT
|
||||
|
||||
**Endpoint:** /api/system/config
|
||||
**Auth:** Bearer token (from RegisterUser)
|
||||
|
||||
**Auth:** Bearer token (from RegisterUser)'
|
||||
@@ -1,39 +0,0 @@
|
||||
info:
|
||||
name: Get Admin Profile
|
||||
type: http
|
||||
seq: 4
|
||||
http:
|
||||
method: GET
|
||||
url: '{{base_url}}/admin/profile'
|
||||
auth: inherit
|
||||
body:
|
||||
type: none
|
||||
|
||||
docs: |-
|
||||
## Get Admin Profile
|
||||
|
||||
Retrieves the admin profile information for administrative access.
|
||||
|
||||
**Method:** GET
|
||||
|
||||
**Endpoint:** /admin/profile
|
||||
|
||||
**Authentication:** Required (Bearer token)
|
||||
|
||||
**Response:**
|
||||
- JSON object containing admin profile details
|
||||
- `id` (string): Admin user ID
|
||||
- `email` (string): Admin email
|
||||
- `username` (string): Admin username
|
||||
- `theme` (string): Theme preference
|
||||
- `first_name` (string): First name
|
||||
- `last_name` (string): Last name
|
||||
- `is_admin` (boolean): Admin status
|
||||
- `created_at` (string): Account creation timestamp
|
||||
- `updated_at` (string): Last update timestamp
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 401: Unauthorized
|
||||
- 403: Forbidden (non-admin users)
|
||||
- 404: Profile not found
|
||||
@@ -8,43 +8,8 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"media_item_ids\": [\n \"{{bookId1"
|
||||
data: "{\n \"media_item_ids\": [\n \"{{bookId1"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
|
||||
docs: |-
|
||||
## Bulk Delete Media Items
|
||||
|
||||
Deletes multiple media items in a single request.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/media-items/bulk-delete
|
||||
|
||||
**Authentication:** Required (Bearer token)
|
||||
|
||||
**Request Body:**
|
||||
- `media_item_ids` (array of strings): Array of media item UUIDs to delete
|
||||
|
||||
**Response:**
|
||||
- `results` (array): Results for each deletion attempt
|
||||
- `total` (number): Total number of media items processed
|
||||
- `deleted` (number): Number of successfully deleted media items
|
||||
- `failed` (number): Number of failed deletions
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success (with partial results if some failed)
|
||||
- 400: Invalid request data
|
||||
- 401: Unauthorized
|
||||
- 403: Forbidden
|
||||
- 500: Internal server error
|
||||
|
||||
**Example:**
|
||||
```json
|
||||
{
|
||||
"media_item_ids": [
|
||||
"uuid-1",
|
||||
"uuid-2",
|
||||
"uuid-3"
|
||||
]
|
||||
docs: "## Bulk Delete Media Items\n\n Deletes multiple media items in a single request.\n\n **Method:** POST\n\n **Endpoint:** /api/media-items/bulk-delete\n\n **Authentication:** Required (Bearer token)\n\n **Request Body:**\n - `media_item_ids` (array of strings): Array of media item UUIDs to delete\n\n **Response:**\n - `results` (array): Results for each deletion attempt\n - `total` (number): Total number of media items processed\n - `deleted` (number): Number of successfully deleted media items\n - `failed` (number): Number of failed deletions\n\n **Status Codes:**\n - 200: Success (with partial results if some failed)\n - 400: Invalid request data\n - 401: Unauthorized\n - 403: Forbidden\n - 500: Internal server error\n\n **Example:**\n ```json\n {\n \"media_item_ids\": [\n \"uuid-1\",\n \"uuid-2\",\n \"uuid-3\"\n ]"
|
||||
@@ -8,48 +8,9 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"media_item_updates\": [\n {\n \"media_item_id\"\
|
||||
: \"{{bookId1"
|
||||
data: "{\n \"media_item_updates\": [\n {\n \"media_item_id\": \"{{bookId1"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
|
||||
docs: |-
|
||||
## Bulk Update Media Items
|
||||
|
||||
Updates multiple media items in a single request with different fields for each item.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/media-items/bulk-update
|
||||
|
||||
**Authentication:** Required (Bearer token)
|
||||
|
||||
**Request Body:**
|
||||
- `media_item_updates` (array): Array of update objects
|
||||
- `media_item_id` (string): Media item UUID to update
|
||||
- `updates` (object): Fields to update (can include title, author, genre, tags, contributors, etc.)
|
||||
|
||||
**Response:**
|
||||
- `results` (array): Results for each update attempt
|
||||
- `total` (number): Total number of media items processed
|
||||
- `updated` (number): Number of successfully updated media items
|
||||
- `failed` (number): Number of failed updates
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success (with partial results if some failed)
|
||||
- 400: Invalid request data
|
||||
- 401: Unauthorized
|
||||
- 403: Forbidden
|
||||
- 500: Internal server error
|
||||
|
||||
**Example:**
|
||||
```json
|
||||
{
|
||||
"media_item_updates": [
|
||||
{
|
||||
"media_item_id": "uuid-1",
|
||||
"updates": {
|
||||
"title": "New Title",
|
||||
"genre": "Fiction",
|
||||
"tags": ["fiction", "adventure"]
|
||||
docs: "## Bulk Update Media Items\n\n Updates multiple media items in a single request with different fields for each item.\n\n **Method:** POST\n\n **Endpoint:** /api/media-items/bulk-update\n\n **Authentication:** Required (Bearer token)\n\n **Request Body:**\n - `media_item_updates` (array): Array of update objects\n - `media_item_id` (string): Media item UUID to update\n - `updates` (object): Fields to update (can include title, author, genre, tags, contributors, etc.)\n\n **Response:**\n - `results` (array): Results for each update attempt\n - `total` (number): Total number of media items processed\n - `updated` (number): Number of successfully updated media items\n - `failed` (number): Number of failed updates\n\n **Status Codes:**\n - 200: Success (with partial results if some failed)\n - 400: Invalid request data\n - 401: Unauthorized\n - 403: Forbidden\n - 500: Internal server error\n\n **Example:**\n ```json\n {\n \"media_item_updates\": [\n {\n\
|
||||
\ \"media_item_id\": \"uuid-1\",\n \"updates\": {\n \"title\": \"New Title\",\n \"genre\": \"Fiction\",\n \"tags\": [\"fiction\", \"adventure\"]"
|
||||
@@ -8,31 +8,5 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"book_ids\": [\n \"{{book_id_1}}"
|
||||
|
||||
docs: |-
|
||||
## Add Books to Collection
|
||||
|
||||
Adds multiple books to an existing collection.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/collections/{collection_id}/books
|
||||
|
||||
**Authentication:** Required (Bearer token)
|
||||
|
||||
**Path Parameters:**
|
||||
- `collection_id` (string): Collection ID
|
||||
|
||||
**Request Body:**
|
||||
- `book_ids` (array of strings, required): List of book IDs to add
|
||||
|
||||
**Response:**
|
||||
- `message` (string): Success message
|
||||
- `added_count` (integer): Number of books added
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 400: Invalid request
|
||||
- 401: Unauthorized
|
||||
- 404: Collection not found
|
||||
data: "{\n \"book_ids\": [\n \"{{book_id_1}}"
|
||||
docs: "## Add Books to Collection\n\n Adds multiple books to an existing collection.\n \n **Method:** POST\n \n **Endpoint:** /api/collections/{collection_id}/books\n \n **Authentication:** Required (Bearer token)\n \n **Path Parameters:**\n - `collection_id` (string): Collection ID\n \n **Request Body:**\n - `book_ids` (array of strings, required): List of book IDs to add\n \n **Response:**\n - `message` (string): Success message\n - `added_count` (integer): Number of books added\n \n **Status Codes:**\n - 200: Success\n - 400: Invalid request\n - 401: Unauthorized\n - 404: Collection not found"
|
||||
@@ -8,40 +8,6 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"name\": \"Science Fiction\",\n \"description\": \"My favorite\
|
||||
\ sci-fi books\",\n \"color\": \"#ff0000\",\n \"icon\": \"\U0001F680\"\
|
||||
,\n \"auto_assign_rules\": [\n {\n \"id\": \"rule-1\",\n \
|
||||
\ \"field\": \"genre\",\n \"operator\": \"equals\",\n \"value\"\
|
||||
: \"Science Fiction\",\n \"priority\": 8"
|
||||
|
||||
docs: |-
|
||||
## Create Collection
|
||||
|
||||
Creates a new collection for organizing books.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/collections
|
||||
|
||||
**Authentication:** Required (Bearer token)
|
||||
|
||||
**Request Body:**
|
||||
- `name` (string, required): Collection name (max 100 chars)
|
||||
- `description` (string, optional): Collection description (max 500 chars)
|
||||
- `color` (string, optional): Hex color code (default #3498db)
|
||||
- `icon` (string, optional): Emoji icon (default 📚)
|
||||
- `auto_assign_rules` (array, optional): Auto-assignment rules
|
||||
- `id` (string): Rule ID
|
||||
- `field` (string): Field to match (genre, author, series, etc.)
|
||||
- `operator` (string): Comparison operator (equals, contains, startsWith)
|
||||
- `value` (string): Value to match
|
||||
- `priority` (integer): Rule priority (1-10)
|
||||
|
||||
**Response:**
|
||||
- Collection object with generated ID
|
||||
|
||||
**Status Codes:**
|
||||
- 201: Created
|
||||
- 400: Invalid request
|
||||
- 401: Unauthorized
|
||||
- 409: Collection name already exists
|
||||
data: "{\n \"name\": \"Science Fiction\",\n \"description\": \"My favorite sci-fi books\",\n \"color\": \"#ff0000\",\n \"icon\": \"\U0001F680\",\n \"auto_assign_rules\": [\n {\n \"id\": \"rule-1\",\n \"field\": \"genre\",\n \"operator\": \"equals\",\n \"value\": \"Science Fiction\",\n \"priority\": 8"
|
||||
docs: "## Create Collection\n\n Creates a new collection for organizing books.\n \n **Method:** POST\n \n **Endpoint:** /api/collections\n \n **Authentication:** Required (Bearer token)\n \n **Request Body:**\n - `name` (string, required): Collection name (max 100 chars)\n - `description` (string, optional): Collection description (max 500 chars)\n - `color` (string, optional): Hex color code (default #3498db)\n - `icon` (string, optional): Emoji icon (default \U0001F4DA)\n - `auto_assign_rules` (array, optional): Auto-assignment rules\n - `id` (string): Rule ID\n - `field` (string): Field to match (genre, author, series, etc.)\n - `operator` (string): Comparison operator (equals, contains, startsWith)\n - `value` (string): Value to match\n - `priority` (integer): Rule priority (1-10)\n \n **Response:**\n - Collection object with generated ID\n \n **Status Codes:**\n - 201: Created\n - 400: Invalid request\n - 401: Unauthorized\n - 409: Collection name\
|
||||
\ already exists"
|
||||
@@ -8,32 +8,5 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"collection_id\": \"{{collection_id}}"
|
||||
|
||||
docs: |-
|
||||
## Create Device Mapping
|
||||
|
||||
Maps a collection to a device shelf for synchronization.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/devices/{device_id}/collections
|
||||
|
||||
**Authentication:** Required (Bearer token)
|
||||
|
||||
**Path Parameters:**
|
||||
- `device_id` (string): Device ID
|
||||
|
||||
**Request Body:**
|
||||
- `collection_id` (string, required): Collection ID to map
|
||||
- `device_shelf_name` (string, optional): Custom shelf name on device
|
||||
- `sync_direction` (string, optional): sync direction (book_to_device, device_to_book, bidirectional)
|
||||
|
||||
**Response:**
|
||||
- Mapping object with generated ID
|
||||
|
||||
**Status Codes:**
|
||||
- 201: Created
|
||||
- 400: Invalid request
|
||||
- 401: Unauthorized
|
||||
- 404: Device or collection not found
|
||||
data: "{\n \"collection_id\": \"{{collection_id}}"
|
||||
docs: "## Create Device Mapping\n\n Maps a collection to a device shelf for synchronization.\n \n **Method:** POST\n \n **Endpoint:** /api/devices/{device_id}/collections\n \n **Authentication:** Required (Bearer token)\n \n **Path Parameters:**\n - `device_id` (string): Device ID\n \n **Request Body:**\n - `collection_id` (string, required): Collection ID to map\n - `device_shelf_name` (string, optional): Custom shelf name on device\n - `sync_direction` (string, optional): sync direction (book_to_device, device_to_book, bidirectional)\n \n **Response:**\n - Mapping object with generated ID\n \n **Status Codes:**\n - 201: Created\n - 400: Invalid request\n - 401: Unauthorized\n - 404: Device or collection not found"
|
||||
@@ -8,39 +8,5 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"name\": \"Sci-Fi Favorites\",\n \"description\": \"Updated\
|
||||
\ description\",\n \"color\": \"#00ff00\",\n \"icon\": \"⭐\",\n \"\
|
||||
auto_assign_rules\": [\n {\n \"id\": \"rule-2\",\n \"field\"\
|
||||
: \"series\",\n \"operator\": \"equals\",\n \"value\": \"Foundation\"\
|
||||
,\n \"priority\": 9"
|
||||
|
||||
docs: |-
|
||||
## Update Collection
|
||||
|
||||
Updates an existing collection's properties.
|
||||
|
||||
**Method:** PUT
|
||||
|
||||
**Endpoint:** /api/collections/{collection_id}
|
||||
|
||||
**Authentication:** Required (Bearer token)
|
||||
|
||||
**Path Parameters:**
|
||||
- `collection_id` (string): Collection ID
|
||||
|
||||
**Request Body:**
|
||||
- `name` (string, optional): New collection name
|
||||
- `description` (string, optional): New description
|
||||
- `color` (string, optional): New hex color code
|
||||
- `icon` (string, optional): New emoji icon
|
||||
- `auto_assign_rules` (array, optional): Updated auto-assignment rules
|
||||
|
||||
**Response:**
|
||||
- Updated collection object
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 400: Invalid request
|
||||
- 401: Unauthorized
|
||||
- 404: Collection not found
|
||||
- 409: Collection name already exists
|
||||
data: "{\n \"name\": \"Sci-Fi Favorites\",\n \"description\": \"Updated description\",\n \"color\": \"#00ff00\",\n \"icon\": \"⭐\",\n \"auto_assign_rules\": [\n {\n \"id\": \"rule-2\",\n \"field\": \"series\",\n \"operator\": \"equals\",\n \"value\": \"Foundation\",\n \"priority\": 9"
|
||||
docs: "## Update Collection\n\n Updates an existing collection's properties.\n \n **Method:** PUT\n \n **Endpoint:** /api/collections/{collection_id}\n \n **Authentication:** Required (Bearer token)\n \n **Path Parameters:**\n - `collection_id` (string): Collection ID\n \n **Request Body:**\n - `name` (string, optional): New collection name\n - `description` (string, optional): New description\n - `color` (string, optional): New hex color code\n - `icon` (string, optional): New emoji icon\n - `auto_assign_rules` (array, optional): Updated auto-assignment rules\n \n **Response:**\n - Updated collection object\n \n **Status Codes:**\n - 200: Success\n - 400: Invalid request\n - 401: Unauthorized\n - 404: Collection not found\n - 409: Collection name already exists"
|
||||
@@ -8,33 +8,5 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"device_shelf_name\": \"Science Fiction\",\n \"sync_direction\"\
|
||||
: \"book_to_device\""
|
||||
|
||||
docs: |-
|
||||
## Update Device Mapping
|
||||
|
||||
Updates settings for a collection-to-device mapping.
|
||||
|
||||
**Method:** PUT
|
||||
|
||||
**Endpoint:** /api/devices/{device_id}/collections/{mapping_id}
|
||||
|
||||
**Authentication:** Required (Bearer token)
|
||||
|
||||
**Path Parameters:**
|
||||
- `device_id` (string): Device ID
|
||||
- `mapping_id` (string): Mapping ID
|
||||
|
||||
**Request Body:**
|
||||
- `device_shelf_name` (string, optional): Custom shelf name on device
|
||||
- `sync_direction` (string, optional): Sync direction (book_to_device, device_to_book, bidirectional)
|
||||
|
||||
**Response:**
|
||||
- Updated mapping object
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 400: Invalid request
|
||||
- 401: Unauthorized
|
||||
- 404: Device or mapping not found
|
||||
data: "{\n \"device_shelf_name\": \"Science Fiction\",\n \"sync_direction\": \"book_to_device\""
|
||||
docs: "## Update Device Mapping\n\n Updates settings for a collection-to-device mapping.\n \n **Method:** PUT\n \n **Endpoint:** /api/devices/{device_id}/collections/{mapping_id}\n \n **Authentication:** Required (Bearer token)\n \n **Path Parameters:**\n - `device_id` (string): Device ID\n - `mapping_id` (string): Mapping ID\n \n **Request Body:**\n - `device_shelf_name` (string, optional): Custom shelf name on device\n - `sync_direction` (string, optional): Sync direction (book_to_device, device_to_book, bidirectional)\n \n **Response:**\n - Updated mapping object\n \n **Status Codes:**\n - 200: Success\n - 400: Invalid request\n - 401: Unauthorized\n - 404: Device or mapping not found"
|
||||
@@ -8,40 +8,9 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"library_id\": \"{{library_id}}\",\n \"name\": \"My Favorites\"\
|
||||
,\n \"icon\": \"⭐\",\n \"description\": \"My favorite books\",\n \"show_on_dashboard\"\
|
||||
: true,\n \"auto_assign_rules\": \"\",\n \"manual_book_ids\": [\"{{media_item_id}}\"\
|
||||
],\n \"match_type\": \"all\"\n}"
|
||||
data: "{\n \"library_id\": \"{{library_id}}\",\n \"name\": \"My Favorites\",\n \"icon\": \"⭐\",\n \"description\": \"My favorite books\",\n \"show_on_dashboard\": true,\n \"auto_assign_rules\": \"\",\n \"manual_book_ids\": [\"{{media_item_id}}\"],\n \"match_type\": \"all\"\n}"
|
||||
runtime:
|
||||
scripts:
|
||||
- type: tests
|
||||
code: "test(\"status must be 201 with valid request\", function() {\n expect(res.status).to.eql(201);\n\
|
||||
});\n\ntest(\"response contains collection id\", function() {\n expect(res.body.id).to.exist;\n\
|
||||
expect(res.body.id).to.be.a('string');\n });\n\ntest(\"response contains\
|
||||
\ collection name\", function() {\n expect(res.body.name).to.eql(\"My Favorites\"\
|
||||
);\n });"
|
||||
|
||||
docs: |-
|
||||
Create a custom collection with manually selected books.
|
||||
|
||||
**Endpoint**: POST /api/collections
|
||||
**Auth**: Required (Bearer token)
|
||||
|
||||
## Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"library_id": "cc23c3a7-f8fb-451a-a78d-2a16df1b725a",
|
||||
"name": "My Favorites",
|
||||
"icon": "⭐",
|
||||
"description": "My favorite books",
|
||||
"show_on_dashboard": true,
|
||||
"auto_assign_rules": "",
|
||||
"manual_book_ids": ["book-id-1", "book-id-2"],
|
||||
"match_type": "all"
|
||||
}
|
||||
```
|
||||
|
||||
## Response
|
||||
|
||||
Returns the created collection with generated ID.
|
||||
- type: after-response
|
||||
code: "function onResponse(res) {\ntest(\"status must be 201 with valid request\", function() {\n expect(res.status).to.eql(201);\n});\n\ntest(\"response contains collection id\", function() {\n expect(res.body.id).to.exist;\nexpect(res.body.id).to.be.a('string');\n });\n\ntest(\"response contains collection name\", function() {\n expect(res.body.name).to.eql(\"My Favorites\");\n });\n}"
|
||||
docs: "Create a custom collection with manually selected books.\n\n**Endpoint**: POST /api/collections\n**Auth**: Required (Bearer token)\n\n## Example Request\n\n```json\n{\n \"library_id\": \"cc23c3a7-f8fb-451a-a78d-2a16df1b725a\",\n \"name\": \"My Favorites\",\n \"icon\": \"⭐\",\n \"description\": \"My favorite books\",\n \"show_on_dashboard\": true,\n \"auto_assign_rules\": \"\",\n \"manual_book_ids\": [\"book-id-1\", \"book-id-2\"],\n \"match_type\": \"all\"\n}\n```\n\n## Response\n\nReturns the created collection with generated ID."
|
||||
@@ -8,16 +8,12 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"library_id\": \"{{library_id}}\",\n \"icon\": \"📚\"\
|
||||
\n}"
|
||||
data: "{\n \"library_id\": \"{{library_id}}\",\n \"icon\": \"\U0001F4DA\"\n}"
|
||||
runtime:
|
||||
scripts:
|
||||
- type: tests
|
||||
code: "test(\"status must be 400 with missing name\", function() {\n expect(res.status).to.eql(400);\n\
|
||||
});\n\ntest(\"response contains error message\", function() {\n expect(res.body.error).to.exist;\n\
|
||||
\ });"
|
||||
- type: after-response
|
||||
code: "function onResponse(res) {\ntest(\"status must be 400 with missing name\", function() {\n expect(res.status).to.eql(400);\n});\n\ntest(\"response contains error message\", function() {\n expect(res.body.error).to.exist;\n });\n}"
|
||||
docs: 'Test error handling when creating a collection without required fields.
|
||||
|
||||
docs: |-
|
||||
Test error handling when creating a collection without required fields.
|
||||
|
||||
**Expected Response**: 400 Bad Request with error message.
|
||||
**Expected Response**: 400 Bad Request with error message.'
|
||||
@@ -8,57 +8,10 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"library_id\": \"{{library_id}}\",\n \"name\": \"Science Fiction\
|
||||
\ Books\",\n \"icon\": \"🚀\",\n \"description\": \"All my sci-fi books\",\n\
|
||||
\ \"show_on_dashboard\": true,\n \"auto_assign_rules\": \"{\\\"rules\\\":[{\\\
|
||||
\"id\\\":\\\"rule1\\\",\\\"field\\\":\\\"genre\\\",\\\"operator\\\":\\\"equals\\\"\
|
||||
,\\\"value\\\":\\\"Sci-Fi\\\",\\\"priority\\\":1}]}\",\n \"manual_book_ids\"\
|
||||
: [],\n \"match_type\": \"all\"\n}"
|
||||
data: "{\n \"library_id\": \"{{library_id}}\",\n \"name\": \"Science Fiction Books\",\n \"icon\": \"\U0001F680\",\n \"description\": \"All my sci-fi books\",\n \"show_on_dashboard\": true,\n \"auto_assign_rules\": \"{\\\"rules\\\":[{\\\"id\\\":\\\"rule1\\\",\\\"field\\\":\\\"genre\\\",\\\"operator\\\":\\\"equals\\\",\\\"value\\\":\\\"Sci-Fi\\\",\\\"priority\\\":1}]}\",\n \"manual_book_ids\": [],\n \"match_type\": \"all\"\n}"
|
||||
runtime:
|
||||
scripts:
|
||||
- type: tests
|
||||
code: "test(\"status must be 201 with valid request\", function() {\n expect(res.status).to.eql(201);\n\
|
||||
});\n\ntest(\"response contains collection id\", function() {\n expect(res.body.id).to.exist;\n\
|
||||
expect(res.body.id).to.be.a('string');\n });\n\ntest(\"response contains\
|
||||
\ collection name\", function() {\n expect(res.body.name).to.eql(\"Science\
|
||||
\ Fiction Books\");\n });\n\ntest(\"response contains is_system false\", function()\
|
||||
\ {\n expect(res.body.is_system).to.exist;\n expect(res.body.is_system).to.eql(false);\n\
|
||||
\ });"
|
||||
|
||||
docs: |-
|
||||
Create a custom collection with filter rules.
|
||||
|
||||
**Endpoint**: POST /api/collections
|
||||
**Auth**: Required (Bearer token)
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| library_id | string | Yes | Library UUID |
|
||||
| name | string | Yes | Collection name |
|
||||
| icon | string | No | Emoji icon |
|
||||
| description | string | No | Collection description |
|
||||
| show_on_dashboard | boolean | No | Show on dashboard (default: true) |
|
||||
| auto_assign_rules | string | No | JSON string of filter rules |
|
||||
| manual_book_ids | array | No | Array of book IDs |
|
||||
| match_type | string | No | "all" (AND) or "any" (OR) |
|
||||
|
||||
## Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"library_id": "cc23c3a7-f8fb-451a-a78d-2a16df1b725a",
|
||||
"name": "Science Fiction Books",
|
||||
"icon": "🚀",
|
||||
"description": "All my sci-fi books",
|
||||
"show_on_dashboard": true,
|
||||
"auto_assign_rules": "{\"rules\":[{\"id\":\"rule1\",\"field\":\"genre\",\"operator\":\"equals\",\"value\":\"Sci-Fi\",\"priority\":1}]}",
|
||||
"manual_book_ids": [],
|
||||
"match_type": "all"
|
||||
}
|
||||
```
|
||||
|
||||
## Response
|
||||
|
||||
Returns the created collection with generated ID.
|
||||
- type: after-response
|
||||
code: "function onResponse(res) {\ntest(\"status must be 201 with valid request\", function() {\n expect(res.status).to.eql(201);\n});\n\ntest(\"response contains collection id\", function() {\n expect(res.body.id).to.exist;\nexpect(res.body.id).to.be.a('string');\n });\n\ntest(\"response contains collection name\", function() {\n expect(res.body.name).to.eql(\"Science Fiction Books\");\n });\n\ntest(\"response contains is_system false\", function() {\n expect(res.body.is_system).to.exist;\n expect(res.body.is_system).to.eql(false);\n });\n}"
|
||||
docs: "Create a custom collection with filter rules.\n\n**Endpoint**: POST /api/collections\n**Auth**: Required (Bearer token)\n\n## Request Body\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| library_id | string | Yes | Library UUID |\n| name | string | Yes | Collection name |\n| icon | string | No | Emoji icon |\n| description | string | No | Collection description |\n| show_on_dashboard | boolean | No | Show on dashboard (default: true) |\n| auto_assign_rules | string | No | JSON string of filter rules |\n| manual_book_ids | array | No | Array of book IDs |\n| match_type | string | No | \"all\" (AND) or \"any\" (OR) |\n\n## Example Request\n\n```json\n{\n \"library_id\": \"cc23c3a7-f8fb-451a-a78d-2a16df1b725a\",\n \"name\": \"Science Fiction Books\",\n \"icon\": \"\U0001F680\",\n \"description\": \"All my sci-fi books\",\n \"show_on_dashboard\": true,\n \"auto_assign_rules\": \"{\\\"rules\\\":[{\\\"id\\\":\\\"rule1\\\",\\\"field\\\":\\\
|
||||
\"genre\\\",\\\"operator\\\":\\\"equals\\\",\\\"value\\\":\\\"Sci-Fi\\\",\\\"priority\\\":1}]}\",\n \"manual_book_ids\": [],\n \"match_type\": \"all\"\n}\n```\n\n## Response\n\nReturns the created collection with generated ID."
|
||||
@@ -8,53 +8,9 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"library_id\": \"{{library_id}}\",\n \"rules\": [\n\
|
||||
{\n \"id\": \"rule1\",\n \"field\": \"genre\",\n\
|
||||
\"operator\": \"equals\",\n \"value\": \"Fiction\",\n\
|
||||
\"priority\": 1\n }\n ],\n \"manual_book_ids\": [],\n \"limit\": 20\n}"
|
||||
data: "{\n \"library_id\": \"{{library_id}}\",\n \"rules\": [\n{\n \"id\": \"rule1\",\n \"field\": \"genre\",\n\"operator\": \"equals\",\n \"value\": \"Fiction\",\n\"priority\": 1\n }\n ],\n \"manual_book_ids\": [],\n \"limit\": 20\n}"
|
||||
runtime:
|
||||
scripts:
|
||||
- type: tests
|
||||
code: "test(\"status must be 200 with valid request\", function() {\n expect(res.status).to.eql(200);\n\
|
||||
});\n\ntest(\"response contains items array\", function() {\n expect(res.body.items).to.exist;\n\
|
||||
expect(res.body.items).to.be.an('array');\n });"
|
||||
|
||||
docs: |-
|
||||
Preview collection with filter rules before saving.
|
||||
|
||||
**Endpoint**: POST /api/collections/preview
|
||||
**Auth**: Required (Bearer token)
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| library_id | string | Yes | Library UUID |
|
||||
| rules | array | No | Filter rules to evaluate |
|
||||
| manual_book_ids | array | No | Manually selected book IDs |
|
||||
| limit | int | No | Max items to return (default: 20, max: 100) |
|
||||
|
||||
## Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"library_id": "cc23c3a7-f8fb-451a-a78d-2a16df1b725a",
|
||||
"rules": [
|
||||
{
|
||||
"id": "rule1",
|
||||
"field": "genre",
|
||||
"operator": "equals",
|
||||
"value": "Fiction",
|
||||
"priority": 1
|
||||
}
|
||||
],
|
||||
"manual_book_ids": [],
|
||||
"limit": 20
|
||||
}
|
||||
```
|
||||
|
||||
## Response
|
||||
|
||||
Returns array of matching book items.
|
||||
|
||||
This endpoint is used by the Custom Section Builder to show users what books will match their filter rules before they save the collection.
|
||||
- type: after-response
|
||||
code: "function onResponse(res) {\ntest(\"status must be 200 with valid request\", function() {\n expect(res.status).to.eql(200);\n});\n\ntest(\"response contains items array\", function() {\n expect(res.body.items).to.exist;\nexpect(res.body.items).to.be.an('array');\n });\n}"
|
||||
docs: "Preview collection with filter rules before saving.\n\n**Endpoint**: POST /api/collections/preview\n**Auth**: Required (Bearer token)\n\n## Request Body\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| library_id | string | Yes | Library UUID |\n| rules | array | No | Filter rules to evaluate |\n| manual_book_ids | array | No | Manually selected book IDs |\n| limit | int | No | Max items to return (default: 20, max: 100) |\n\n## Example Request\n\n```json\n{\n \"library_id\": \"cc23c3a7-f8fb-451a-a78d-2a16df1b725a\",\n \"rules\": [\n {\n \"id\": \"rule1\",\n \"field\": \"genre\",\n \"operator\": \"equals\",\n \"value\": \"Fiction\",\n \"priority\": 1\n }\n ],\n \"manual_book_ids\": [],\n \"limit\": 20\n}\n```\n\n## Response\n\nReturns array of matching book items.\n\nThis endpoint is used by the Custom Section Builder to show users what books will match their filter rules before they save the collection."
|
||||
@@ -8,46 +8,11 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"operations\": [\n {\n \"collection_id\": \"{{collectionId1"
|
||||
data: "{\n \"operations\": [\n {\n \"collection_id\": \"{{collectionId1"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Authorization
|
||||
value: Bearer {{authToken
|
||||
|
||||
docs: |-
|
||||
## Bulk Add Books to Collections
|
||||
|
||||
Adds multiple books to multiple collections in a single request. Each operation specifies a collection and a list of books to add.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/collections/bulk-add-books
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Request Body:**
|
||||
- `operations` (array): Array of collection-book operations
|
||||
- `collection_id` (string): Collection UUID
|
||||
- `book_ids` (array): Array of book UUIDs to add to the collection
|
||||
|
||||
**Response:**
|
||||
- `results` (array): Results for each operation
|
||||
- `total` (number): Total number of operations
|
||||
- `success` (number): Number of successful operations
|
||||
- `failed` (number): Number of failed operations
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success (with partial results if some failed)
|
||||
- 400: Invalid request data
|
||||
- 401: Unauthorized
|
||||
- 403: Forbidden
|
||||
- 500: Internal server error
|
||||
|
||||
**Example:**
|
||||
```json
|
||||
{
|
||||
"operations": [
|
||||
{
|
||||
"collection_id": "collection-uuid-1",
|
||||
"book_ids": ["book-1", "book-2"]
|
||||
docs: "## Bulk Add Books to Collections\n\n Adds multiple books to multiple collections in a single request. Each operation specifies a collection and a list of books to add.\n\n **Method:** POST\n\n **Endpoint:** /api/collections/bulk-add-books\n\n **Authentication:** Bearer token\n\n **Request Body:**\n - `operations` (array): Array of collection-book operations\n - `collection_id` (string): Collection UUID\n - `book_ids` (array): Array of book UUIDs to add to the collection\n\n **Response:**\n - `results` (array): Results for each operation\n - `total` (number): Total number of operations\n - `success` (number): Number of successful operations\n - `failed` (number): Number of failed operations\n\n **Status Codes:**\n - 200: Success (with partial results if some failed)\n - 400: Invalid request data\n - 401: Unauthorized\n - 403: Forbidden\n - 500: Internal server error\n\n **Example:**\n ```json\n {\n \"operations\": [\n {\n \"collection_id\":\
|
||||
\ \"collection-uuid-1\",\n \"book_ids\": [\"book-1\", \"book-2\"]"
|
||||
@@ -8,16 +8,8 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"book_ids\": [\n \"{{bookId1"
|
||||
data: "{\n \"book_ids\": [\n \"{{bookId1"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
|
||||
docs: |-
|
||||
## Bulk Remove Books from Collection
|
||||
|
||||
Removes multiple books from a collection in a single request.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/collections/{collection_id
|
||||
docs: "## Bulk Remove Books from Collection\n\n Removes multiple books from a collection in a single request.\n\n **Method:** POST\n\n **Endpoint:** /api/collections/{collection_id"
|
||||
@@ -8,20 +8,10 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"book_ids\": []"
|
||||
data: "{\n \"book_ids\": []"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Authorization
|
||||
value: Bearer {{authToken
|
||||
|
||||
docs: |-
|
||||
## Bulk Remove Books - Empty List Validation
|
||||
|
||||
Tests validation behavior when providing an empty book_ids array.
|
||||
|
||||
**Expected Result:** 400 Bad Request
|
||||
|
||||
**Validation Rule:** book_ids array must contain at least one book UUID.
|
||||
|
||||
**Purpose:** Ensures the API properly validates input and rejects empty removal requests.
|
||||
docs: "## Bulk Remove Books - Empty List Validation\n\n Tests validation behavior when providing an empty book_ids array.\n\n **Expected Result:** 400 Bad Request\n\n **Validation Rule:** book_ids array must contain at least one book UUID.\n\n **Purpose:** Ensures the API properly validates input and rejects empty removal requests."
|
||||
@@ -8,24 +8,10 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"book_ids\": [\n \"{{bookId1"
|
||||
data: "{\n \"book_ids\": [\n \"{{bookId1"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Authorization
|
||||
value: Bearer {{authToken
|
||||
|
||||
docs: |-
|
||||
## Bulk Remove Books - Invalid IDs
|
||||
|
||||
Tests behavior when the book_ids array contains invalid UUID formats or non-existent books.
|
||||
|
||||
**Expected Result:** 200 OK with partial success
|
||||
|
||||
**Purpose:** Verifies that:
|
||||
- Invalid UUID formats don't crash the endpoint
|
||||
- Non-existent book IDs are handled gracefully
|
||||
- Valid IDs in the same request are still processed
|
||||
- Response includes detailed results showing which succeeded/failed
|
||||
|
||||
**Note:** The endpoint should process all valid IDs and report failures for invalid ones, allowing clients to handle partial failures appropriately.
|
||||
docs: "## Bulk Remove Books - Invalid IDs\n\n Tests behavior when the book_ids array contains invalid UUID formats or non-existent books.\n\n **Expected Result:** 200 OK with partial success\n\n **Purpose:** Verifies that:\n - Invalid UUID formats don't crash the endpoint\n - Non-existent book IDs are handled gracefully\n - Valid IDs in the same request are still processed\n - Response includes detailed results showing which succeeded/failed\n\n **Note:** The endpoint should process all valid IDs and report failures for invalid ones, allowing clients to handle partial failures appropriately."
|
||||
@@ -8,20 +8,10 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"book_ids\": [\n \"{{bookId1"
|
||||
data: "{\n \"book_ids\": [\n \"{{bookId1"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Authorization
|
||||
value: Bearer {{authToken
|
||||
|
||||
docs: |-
|
||||
## Bulk Remove Books - Single Book
|
||||
|
||||
Tests that bulk remove endpoint works correctly with a single book.
|
||||
|
||||
**Expected Result:** 200 OK with removed: 1, total: 1
|
||||
|
||||
**Purpose:** Verifies the bulk remove endpoint handles single-item arrays correctly, providing flexibility for clients to use the same endpoint for both single and multiple removals.
|
||||
|
||||
**Note:** Using bulk remove for a single book is functionally equivalent to the single remove endpoint but allows for consistent error handling and response format.
|
||||
docs: "## Bulk Remove Books - Single Book\n\n Tests that bulk remove endpoint works correctly with a single book.\n\n **Expected Result:** 200 OK with removed: 1, total: 1\n\n **Purpose:** Verifies the bulk remove endpoint handles single-item arrays correctly, providing flexibility for clients to use the same endpoint for both single and multiple removals.\n\n **Note:** Using bulk remove for a single book is functionally equivalent to the single remove endpoint but allows for consistent error handling and response format."
|
||||
@@ -8,23 +8,10 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"rules\": [\n {\n \"field\": \"author\",\n \
|
||||
\ \"operator\": \"contains\",\n \"value\": \"Asimov\""
|
||||
data: "{\n \"rules\": [\n {\n \"field\": \"author\",\n \"operator\": \"contains\",\n \"value\": \"Asimov\""
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Authorization
|
||||
value: Bearer {{authToken
|
||||
|
||||
docs: |-
|
||||
## Test Collection Rules - Author Contains
|
||||
|
||||
Tests the "contains" operator on the author field to find books by a specific author (partial match).
|
||||
|
||||
**Example Use Case:** Finding all books by an author whose name contains "Asimov" (e.g., "Isaac Asimov").
|
||||
|
||||
**Operator:** `contains` - Matches if the field contains the specified value as a substring (case-insensitive typically).
|
||||
|
||||
**Expected Result:** Returns all books where the author field contains "Asimov".
|
||||
|
||||
**Purpose:** Demonstrates text-based partial matching for author searches, useful when you don't need the exact author name or want to find books by authors with similar names.
|
||||
docs: "## Test Collection Rules - Author Contains\n\n Tests the \"contains\" operator on the author field to find books by a specific author (partial match).\n\n **Example Use Case:** Finding all books by an author whose name contains \"Asimov\" (e.g., \"Isaac Asimov\").\n\n **Operator:** `contains` - Matches if the field contains the specified value as a substring (case-insensitive typically).\n\n **Expected Result:** Returns all books where the author field contains \"Asimov\".\n\n **Purpose:** Demonstrates text-based partial matching for author searches, useful when you don't need the exact author name or want to find books by authors with similar names."
|
||||
+2
-17
@@ -8,25 +8,10 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"rules\": [\n {\n \"field\": \"copyright_year\"\
|
||||
,\n \"operator\": \"greater_than\",\n \"value\": \"2000\""
|
||||
data: "{\n \"rules\": [\n {\n \"field\": \"copyright_year\",\n \"operator\": \"greater_than\",\n \"value\": \"2000\""
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Authorization
|
||||
value: Bearer {{authToken
|
||||
|
||||
docs: |-
|
||||
## Test Collection Rules - Copyright Year Greater Than
|
||||
|
||||
Tests the "greater_than" operator on the copyright_year field to find books published after a specific year.
|
||||
|
||||
**Example Use Case:** Creating a "Modern Books" collection with books published after 2000.
|
||||
|
||||
**Operator:** `greater_than` - Matches if the field value is greater than the specified value (numeric comparison).
|
||||
|
||||
**Field:** `copyright_year` - The year the book was copyrighted/published.
|
||||
|
||||
**Expected Result:** Returns all books with copyright_year greater than 2000 (i.e., published in 2001 or later).
|
||||
|
||||
**Purpose:** Demonstrates numeric comparison operators for creating date-based collections, useful for organizing books by publication era.
|
||||
docs: "## Test Collection Rules - Copyright Year Greater Than\n\n Tests the \"greater_than\" operator on the copyright_year field to find books published after a specific year.\n\n **Example Use Case:** Creating a \"Modern Books\" collection with books published after 2000.\n\n **Operator:** `greater_than` - Matches if the field value is greater than the specified value (numeric comparison).\n\n **Field:** `copyright_year` - The year the book was copyrighted/published.\n\n **Expected Result:** Returns all books with copyright_year greater than 2000 (i.e., published in 2001 or later).\n\n **Purpose:** Demonstrates numeric comparison operators for creating date-based collections, useful for organizing books by publication era."
|
||||
@@ -8,22 +8,10 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"rules\": []"
|
||||
data: "{\n \"rules\": []"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Authorization
|
||||
value: Bearer {{authToken
|
||||
|
||||
docs: |-
|
||||
## Test Collection Rules - Empty Rules Array
|
||||
|
||||
Tests validation behavior when providing an empty rules array.
|
||||
|
||||
**Expected Result:** 400 Bad Request
|
||||
|
||||
**Validation Rule:** rules array must contain at least one rule object.
|
||||
|
||||
**Purpose:** Ensures the API properly validates input and rejects empty rule sets, preventing accidental queries that would return all books or cause performance issues.
|
||||
|
||||
**Use Case:** Client-side validation should prevent sending empty rules, but the API should also validate to catch malformed requests.
|
||||
docs: "## Test Collection Rules - Empty Rules Array\n\n Tests validation behavior when providing an empty rules array.\n\n **Expected Result:** 400 Bad Request\n\n **Validation Rule:** rules array must contain at least one rule object.\n\n **Purpose:** Ensures the API properly validates input and rejects empty rule sets, preventing accidental queries that would return all books or cause performance issues.\n\n **Use Case:** Client-side validation should prevent sending empty rules, but the API should also validate to catch malformed requests."
|
||||
@@ -8,27 +8,10 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"rules\": [\n {\n \"field\": \"genre\",\n \
|
||||
\ \"operator\": \"equals\",\n \"value\": \"NonExistentGenre123456\""
|
||||
data: "{\n \"rules\": [\n {\n \"field\": \"genre\",\n \"operator\": \"equals\",\n \"value\": \"NonExistentGenre123456\""
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Authorization
|
||||
value: Bearer {{authToken
|
||||
|
||||
docs: |-
|
||||
## Test Collection Rules - No Matches
|
||||
|
||||
Tests behavior when collection rules don't match any books in the library.
|
||||
|
||||
**Example Use Case:** Validating that a new genre name doesn't exist before creating a collection for it, or testing edge cases.
|
||||
|
||||
**Expected Result:** 200 OK with empty matches array and total: 0
|
||||
|
||||
**Purpose:** Verifies that the API handles zero-match scenarios gracefully:
|
||||
- Returns 200 (success) not 404
|
||||
- Returns empty array, not null
|
||||
- Returns total: 0 for clarity
|
||||
- No errors thrown for no results
|
||||
|
||||
**Note:** An empty result set is a valid response and doesn't indicate an error. This allows users to test rules confidently before creating collections.
|
||||
docs: "## Test Collection Rules - No Matches\n\n Tests behavior when collection rules don't match any books in the library.\n\n **Example Use Case:** Validating that a new genre name doesn't exist before creating a collection for it, or testing edge cases.\n\n **Expected Result:** 200 OK with empty matches array and total: 0\n\n **Purpose:** Verifies that the API handles zero-match scenarios gracefully:\n - Returns 200 (success) not 404\n - Returns empty array, not null\n - Returns total: 0 for clarity\n - No errors thrown for no results\n\n **Note:** An empty result set is a valid response and doesn't indicate an error. This allows users to test rules confidently before creating collections."
|
||||
@@ -8,60 +8,11 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"rules\": [\n {\n \"field\": \"genre\",\n \
|
||||
\ \"operator\": \"equals\",\n \"value\": \"Science Fiction\""
|
||||
data: "{\n \"rules\": [\n {\n \"field\": \"genre\",\n \"operator\": \"equals\",\n \"value\": \"Science Fiction\""
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Authorization
|
||||
value: Bearer {{authToken
|
||||
|
||||
docs: |-
|
||||
## Test Collection Rules
|
||||
|
||||
Tests collection rules against the library to see which books match, without creating a collection. Useful for previewing what books would be included in a collection with specific rules.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/collections/test-rules
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Request Body:**
|
||||
- `rules` (array): Array of rule objects to test
|
||||
- `field` (string): Field to test (genre, author, copyright_year, tags, etc.)
|
||||
- `operator` (string): Comparison operator
|
||||
- `equals`: Exact match
|
||||
- `contains`: Contains substring (for text fields)
|
||||
- `greater_than`: Greater than (for numeric fields)
|
||||
- `less_than`: Less than (for numeric fields)
|
||||
- `not_equals`: Not equal to
|
||||
- `starts_with`: Starts with
|
||||
- `ends_with`: Ends with
|
||||
- `is_empty`: Field is empty or null
|
||||
- `is_not_empty`: Field is not empty and not null
|
||||
- `value` (string): Value to compare against (not required for is_empty/is_not_empty)
|
||||
|
||||
**Response:**
|
||||
- `matches` (array): Array of matching books
|
||||
- `id` (string): Book UUID
|
||||
- `title` (string): Book title
|
||||
- `author` (string): Book author
|
||||
- `genre` (string): Book genre
|
||||
- Additional book metadata
|
||||
- `total` (number): Total number of matching books
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success - returns matching books
|
||||
- 400: Invalid request (empty rules array, invalid field/operator)
|
||||
- 401: Unauthorized
|
||||
- 500: Internal server error
|
||||
|
||||
**Example Request:**
|
||||
```json
|
||||
{
|
||||
"rules": [
|
||||
{
|
||||
"field": "genre",
|
||||
"operator": "equals",
|
||||
"value": "Science Fiction"
|
||||
docs: "## Test Collection Rules\n\n Tests collection rules against the library to see which books match, without creating a collection. Useful for previewing what books would be included in a collection with specific rules.\n\n **Method:** POST\n\n **Endpoint:** /api/collections/test-rules\n\n **Authentication:** Bearer token\n\n **Request Body:**\n - `rules` (array): Array of rule objects to test\n - `field` (string): Field to test (genre, author, copyright_year, tags, etc.)\n - `operator` (string): Comparison operator\n - `equals`: Exact match\n - `contains`: Contains substring (for text fields)\n - `greater_than`: Greater than (for numeric fields)\n - `less_than`: Less than (for numeric fields)\n - `not_equals`: Not equal to\n - `starts_with`: Starts with\n - `ends_with`: Ends with\n - `is_empty`: Field is empty or null\n - `is_not_empty`: Field is not empty and not null\n - `value` (string): Value to compare against (not required\
|
||||
\ for is_empty/is_not_empty)\n\n **Response:**\n - `matches` (array): Array of matching books\n - `id` (string): Book UUID\n - `title` (string): Book title\n - `author` (string): Book author\n - `genre` (string): Book genre\n - Additional book metadata\n - `total` (number): Total number of matching books\n\n **Status Codes:**\n - 200: Success - returns matching books\n - 400: Invalid request (empty rules array, invalid field/operator)\n - 401: Unauthorized\n - 500: Internal server error\n\n **Example Request:**\n ```json\n {\n \"rules\": [\n {\n \"field\": \"genre\",\n \"operator\": \"equals\",\n \"value\": \"Science Fiction\""
|
||||
@@ -8,18 +8,8 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"winner\": \"koreader\",\n \"manual_data\": null,\n \"\
|
||||
apply_to_all_future_conflicts\": false,\n \"reason\": \"User chose more recent\
|
||||
\ progress\""
|
||||
data: "{\n \"winner\": \"koreader\",\n \"manual_data\": null,\n \"apply_to_all_future_conflicts\": false,\n \"reason\": \"User chose more recent progress\""
|
||||
headers:
|
||||
- key: Authorization
|
||||
value: Bearer {{token
|
||||
|
||||
docs: |-
|
||||
## Resolve Conflict
|
||||
|
||||
Resolves a sync conflict by choosing which source to use for the conflicting data.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/conflicts/{conflict_id
|
||||
docs: "## Resolve Conflict\n\n Resolves a sync conflict by choosing which source to use for the conflicting data.\n\n **Method:** POST\n\n **Endpoint:** /api/conflicts/{conflict_id"
|
||||
@@ -8,42 +8,10 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"conflict_ids\": [\n \"{{conflictId1"
|
||||
data: "{\n \"conflict_ids\": [\n \"{{conflictId1"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Authorization
|
||||
value: Bearer {{authToken
|
||||
|
||||
docs: |-
|
||||
## Bulk Dismiss Conflicts
|
||||
|
||||
Dismisses multiple sync conflicts without resolving them. This removes them from the conflict list while leaving the data unchanged.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/conflicts/bulk-dismiss
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Request Body:**
|
||||
- `conflict_ids` (array): Array of conflict UUIDs to dismiss
|
||||
|
||||
**Response:**
|
||||
- `results` (array): Results for each dismissal
|
||||
- `total` (number): Total number of conflicts processed
|
||||
- `success` (number): Number of successfully dismissed conflicts
|
||||
- `failed` (number): Number of failed dismissals
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 400: Invalid request data
|
||||
- 401: Unauthorized
|
||||
- 403: Forbidden
|
||||
- 404: One or more conflicts not found
|
||||
- 500: Internal server error
|
||||
|
||||
**Example:**
|
||||
```json
|
||||
{
|
||||
"conflict_ids": ["uuid-1", "uuid-2"]
|
||||
docs: "## Bulk Dismiss Conflicts\n\n Dismisses multiple sync conflicts without resolving them. This removes them from the conflict list while leaving the data unchanged.\n\n **Method:** POST\n\n **Endpoint:** /api/conflicts/bulk-dismiss\n\n **Authentication:** Bearer token\n\n **Request Body:**\n - `conflict_ids` (array): Array of conflict UUIDs to dismiss\n\n **Response:**\n - `results` (array): Results for each dismissal\n - `total` (number): Total number of conflicts processed\n - `success` (number): Number of successfully dismissed conflicts\n - `failed` (number): Number of failed dismissals\n\n **Status Codes:**\n - 200: Success\n - 400: Invalid request data\n - 401: Unauthorized\n - 403: Forbidden\n - 404: One or more conflicts not found\n - 500: Internal server error\n\n **Example:**\n ```json\n {\n \"conflict_ids\": [\"uuid-1\", \"uuid-2\"]"
|
||||
@@ -8,48 +8,11 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"conflict_ids\": [\n \"{{conflictId1"
|
||||
data: "{\n \"conflict_ids\": [\n \"{{conflictId1"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Authorization
|
||||
value: Bearer {{authToken
|
||||
|
||||
docs: |-
|
||||
## Bulk Resolve Conflicts
|
||||
|
||||
Resolves multiple sync conflicts in a single request using a specified resolution strategy.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/conflicts/bulk-resolve
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Request Body:**
|
||||
- `conflict_ids` (array): Array of conflict UUIDs to resolve
|
||||
- `strategy` (string): Resolution strategy
|
||||
- `most_recent`: Use the most recently updated progress
|
||||
- `highest_progress`: Use the reading progress with the highest percent read
|
||||
- `server`: Always prefer server-side data
|
||||
- `device`: Always prefer device-side data
|
||||
|
||||
**Response:**
|
||||
- `results` (array): Results for each conflict resolution
|
||||
- `total` (number): Total number of conflicts processed
|
||||
- `success` (number): Number of successfully resolved conflicts
|
||||
- `failed` (number): Number of failed resolutions
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success (with partial results if some failed)
|
||||
- 400: Invalid request data
|
||||
- 401: Unauthorized
|
||||
- 403: Forbidden
|
||||
- 404: One or more conflicts not found
|
||||
- 500: Internal server error
|
||||
|
||||
**Example:**
|
||||
```json
|
||||
{
|
||||
"conflict_ids": ["uuid-1", "uuid-2", "uuid-3"],
|
||||
"strategy": "most_recent"
|
||||
docs: "## Bulk Resolve Conflicts\n\n Resolves multiple sync conflicts in a single request using a specified resolution strategy.\n\n **Method:** POST\n\n **Endpoint:** /api/conflicts/bulk-resolve\n\n **Authentication:** Bearer token\n\n **Request Body:**\n - `conflict_ids` (array): Array of conflict UUIDs to resolve\n - `strategy` (string): Resolution strategy\n - `most_recent`: Use the most recently updated progress\n - `highest_progress`: Use the reading progress with the highest percent read\n - `server`: Always prefer server-side data\n - `device`: Always prefer device-side data\n\n **Response:**\n - `results` (array): Results for each conflict resolution\n - `total` (number): Total number of conflicts processed\n - `success` (number): Number of successfully resolved conflicts\n - `failed` (number): Number of failed resolutions\n\n **Status Codes:**\n - 200: Success (with partial results if some failed)\n - 400: Invalid request data\n - 401: Unauthorized\n\
|
||||
\ - 403: Forbidden\n - 404: One or more conflicts not found\n - 500: Internal server error\n\n **Example:**\n ```json\n {\n \"conflict_ids\": [\"uuid-1\", \"uuid-2\", \"uuid-3\"],\n \"strategy\": \"most_recent\""
|
||||
@@ -8,39 +8,11 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"conflict_ids\": [\n \"{{conflictId1"
|
||||
data: "{\n \"conflict_ids\": [\n \"{{conflictId1"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Authorization
|
||||
value: Bearer {{authToken
|
||||
|
||||
docs: |-
|
||||
## Bulk Resolve with Highest Progress Strategy
|
||||
|
||||
Resolves multiple sync conflicts using the "highest_progress" strategy, which keeps the reading progress with the highest percentage read.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/conflicts/bulk-resolve
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Request Body:**
|
||||
- `conflict_ids` (array): Array of conflict UUIDs to resolve
|
||||
- `strategy` (string): Must be "highest_progress"
|
||||
|
||||
**Response:**
|
||||
- `results` (array): Results for each conflict resolution
|
||||
- `total` (number): Total number of conflicts processed
|
||||
- `success` (number): Number of successfully resolved conflicts
|
||||
- `failed` (number): Number of failed resolutions
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 400: Invalid request data
|
||||
- 401: Unauthorized
|
||||
- 403: Forbidden
|
||||
- 500: Internal server error
|
||||
|
||||
**Note:** The highest progress strategy is ideal when you want to preserve the most reading progress across devices. Use this when you've been reading on multiple devices and want to keep the furthest position.
|
||||
docs: "## Bulk Resolve with Highest Progress Strategy\n\n Resolves multiple sync conflicts using the \"highest_progress\" strategy, which keeps the reading progress with the highest percentage read.\n\n **Method:** POST\n\n **Endpoint:** /api/conflicts/bulk-resolve\n\n **Authentication:** Bearer token\n\n **Request Body:**\n - `conflict_ids` (array): Array of conflict UUIDs to resolve\n - `strategy` (string): Must be \"highest_progress\"\n\n **Response:**\n - `results` (array): Results for each conflict resolution\n - `total` (number): Total number of conflicts processed\n - `success` (number): Number of successfully resolved conflicts\n - `failed` (number): Number of failed resolutions\n\n **Status Codes:**\n - 200: Success\n - 400: Invalid request data\n - 401: Unauthorized\n - 403: Forbidden\n - 500: Internal server error\n\n **Note:** The highest progress strategy is ideal when you want to preserve the most reading progress across devices. Use this when you've been\
|
||||
\ reading on multiple devices and want to keep the furthest position."
|
||||
@@ -8,40 +8,9 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"collection_name\": \"continue-reading\"\n}"
|
||||
data: "{\n \"collection_name\": \"continue-reading\"\n}"
|
||||
runtime:
|
||||
scripts:
|
||||
- type: tests
|
||||
code: "test(\"status must be 200 with valid collection\", function() {\n expect(res.status).to.eql(200);\n\
|
||||
});\n\ntest(\"response has success message\", function() {\n expect(res.body.message).to.exist;\n\
|
||||
});"
|
||||
|
||||
docs: |-
|
||||
Restore a system collection to its default state.
|
||||
|
||||
**Endpoint**: POST /api/dashboard/restore-system-collection
|
||||
**Auth**: Required (Bearer token)
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| collection_name | string | Yes | Name of system collection to restore |
|
||||
|
||||
Valid collection names:
|
||||
- `continue-reading`: Books you're currently reading (0 < progress < 1)
|
||||
- `recently-added`: Newly added items to this library
|
||||
- `recently-read`: Books you've finished (progress >= 1)
|
||||
- `not-started`: Books you haven't read yet (progress = 0 or no record)
|
||||
|
||||
## Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"collection_name": "continue-reading"
|
||||
}
|
||||
```
|
||||
|
||||
## Response
|
||||
|
||||
Returns success message on restore.
|
||||
code: "test(\"status must be 200 with valid collection\", function() {\n expect(res.status).to.eql(200);\n});\n\ntest(\"response has success message\", function() {\n expect(res.body.message).to.exist;\n});"
|
||||
docs: "Restore a system collection to its default state.\n\n**Endpoint**: POST /api/dashboard/restore-system-collection\n**Auth**: Required (Bearer token)\n\n## Request Body\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| collection_name | string | Yes | Name of system collection to restore |\n\nValid collection names:\n- `continue-reading`: Books you're currently reading (0 < progress < 1)\n- `recently-added`: Newly added items to this library\n- `recently-read`: Books you've finished (progress >= 1)\n- `not-started`: Books you haven't read yet (progress = 0 or no record)\n\n## Example Request\n\n```json\n{\n \"collection_name\": \"continue-reading\"\n}\n```\n\n## Response\n\nReturns success message on restore."
|
||||
@@ -8,41 +8,9 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"library_id\": \"{{library_id}}\",\n \"hidden_collections\"\
|
||||
: [\"not-started\"],\n \"collection_order\": [\"recently-added\", \"continue-reading\"\
|
||||
, \"recently-read\"],\n \"items_per_section\": 20\n}"
|
||||
data: "{\n \"library_id\": \"{{library_id}}\",\n \"hidden_collections\": [\"not-started\"],\n \"collection_order\": [\"recently-added\", \"continue-reading\", \"recently-read\"],\n \"items_per_section\": 20\n}"
|
||||
runtime:
|
||||
scripts:
|
||||
- type: tests
|
||||
code: "test(\"status must be 200 with valid request\", function() {\n expect(res.status).to.eql(200);\n\
|
||||
});"
|
||||
|
||||
docs: |-
|
||||
Update dashboard preferences for the authenticated user.
|
||||
|
||||
**Endpoint**: PUT /api/dashboard/preferences
|
||||
**Auth**: Required (Bearer token)
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| library_id | string | Yes | Library UUID |
|
||||
| hidden_collections | array | No | Collection names to hide from dashboard |
|
||||
| collection_order | array | No | Collection names in custom display order |
|
||||
| items_per_section | int | No | Items to show per section (default: 20) |
|
||||
|
||||
## Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"library_id": "cc23c3a7-f8fb-451a-a78d-2a16df1b725a",
|
||||
"hidden_collections": ["not-started"],
|
||||
"collection_order": ["recently-added", "continue-reading", "recently-read"],
|
||||
"items_per_section": 20
|
||||
}
|
||||
```
|
||||
|
||||
## Response
|
||||
|
||||
Returns updated preferences object on success.
|
||||
code: "test(\"status must be 200 with valid request\", function() {\n expect(res.status).to.eql(200);\n});"
|
||||
docs: "Update dashboard preferences for the authenticated user.\n\n**Endpoint**: PUT /api/dashboard/preferences\n**Auth**: Required (Bearer token)\n\n## Request Body\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| library_id | string | Yes | Library UUID |\n| hidden_collections | array | No | Collection names to hide from dashboard |\n| collection_order | array | No | Collection names in custom display order |\n| items_per_section | int | No | Items to show per section (default: 20) |\n\n## Example Request\n\n```json\n{\n \"library_id\": \"cc23c3a7-f8fb-451a-a78d-2a16df1b725a\",\n \"hidden_collections\": [\"not-started\"],\n \"collection_order\": [\"recently-added\", \"continue-reading\", \"recently-read\"],\n \"items_per_section\": 20\n}\n```\n\n## Response\n\nReturns updated preferences object on success."
|
||||
@@ -1,22 +0,0 @@
|
||||
info:
|
||||
name: Bookhoard Device Management API
|
||||
type: collection
|
||||
seq: 1
|
||||
http:
|
||||
method: POST
|
||||
url: '"http://localhost:8765/api"'
|
||||
|
||||
docs: |-
|
||||
## Bookhoard Device Management API
|
||||
|
||||
Collection of endpoints for managing e-reader devices and their synchronization settings.
|
||||
|
||||
**Base URL:** http://localhost:8765/api
|
||||
|
||||
**Authentication:** Most endpoints require Bearer token authentication
|
||||
|
||||
**Endpoints:**
|
||||
- Device registration and management
|
||||
- Device authentication tokens
|
||||
- Sync configuration
|
||||
- Device-to-collection mappings
|
||||
@@ -0,0 +1,7 @@
|
||||
info:
|
||||
name: Bookhoard Device Management API
|
||||
type: folder
|
||||
seq: 1
|
||||
request:
|
||||
auth: inherit
|
||||
docs: "## Bookhoard Device Management API\n\n Collection of endpoints for managing e-reader devices and their synchronization settings.\n\n **Base URL:** http://localhost:8765/api\n\n **Authentication:** Most endpoints require Bearer token authentication\n\n **Endpoints:**\n - Device registration and management\n - Device authentication tokens\n - Sync configuration\n - Device-to-collection mappings"
|
||||
@@ -2,95 +2,16 @@ info:
|
||||
name: Get Analytics Tests
|
||||
type: http
|
||||
seq: 7
|
||||
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/kobo/v1/analytics/gettests'
|
||||
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/v1/analytics/gettests'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
platform: android
|
||||
firmware_version: 4.30.19023
|
||||
|
||||
docs: |-
|
||||
## Get Kobo Analytics Tests
|
||||
|
||||
Retrieves A/B testing configuration and feature flags for Kobo device.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/kobo/v1/analytics/gettests
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Request Body:**
|
||||
- `platform` (string): Device platform
|
||||
- `android`: Kobo Android app
|
||||
- `kobo`: Native Kobo firmware
|
||||
- `firmware_version` (string): Firmware version (e.g., "4.30.19023")
|
||||
- `device_model` (string, optional): Device model identifier
|
||||
- `locale` (string, optional): Device locale (e.g., "en_US")
|
||||
|
||||
**Response:**
|
||||
- `tests` (array): Active A/B tests
|
||||
- `test_name` (string): Test identifier
|
||||
- `variant` (string): Assigned variant (A, B, C, etc.)
|
||||
- `enabled` (boolean): Whether test is active
|
||||
- `parameters` (object): Test-specific parameters
|
||||
- `features` (object): Feature flags
|
||||
- `feature_name` (boolean/string): Feature state
|
||||
- `configuration` (object): Device configuration
|
||||
- `sync_interval_minutes` (integer): Recommended sync frequency
|
||||
- `batch_size` (integer): Max items per batch sync
|
||||
- `timeout_seconds` (integer): Request timeout
|
||||
- `version` (string): Configuration version
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 401: Unauthorized
|
||||
- 400: Invalid request parameters
|
||||
|
||||
**Analytics Testing Purpose:**
|
||||
- Kobo uses A/B testing for UX features
|
||||
- Feature flags for gradual rollout
|
||||
- Performance monitoring configuration
|
||||
- Sync behavior optimization
|
||||
- Device-specific tuning
|
||||
|
||||
**Common Tests:**
|
||||
- Sync frequency optimization
|
||||
- UI/UX variations
|
||||
- Network usage patterns
|
||||
- Battery life improvements
|
||||
- Feature set variations by model
|
||||
|
||||
**Feature Flags:**
|
||||
- New sync features
|
||||
- Beta functionality
|
||||
- Platform-specific capabilities
|
||||
- Experimental features
|
||||
|
||||
**Configuration Parameters:**
|
||||
- Optimal sync intervals for device
|
||||
- Batch size limits based on device capabilities
|
||||
- Timeout values for network conditions
|
||||
- Retry logic configuration
|
||||
- Cache policy settings
|
||||
|
||||
**Usage:**
|
||||
- Called during device initialization
|
||||
- Refreshed daily or weekly
|
||||
- Cached on device
|
||||
- Affects sync behavior
|
||||
- Can be overridden by server
|
||||
|
||||
**Use Cases:**
|
||||
- Device initialization
|
||||
- Feature rollout testing
|
||||
- Performance optimization
|
||||
- UX experiment participation
|
||||
- Configuration management
|
||||
data: "{\n \"platform\": \"android\",\n \"firmware_version\": \"4.30.19023\"\n}"
|
||||
docs: "## Get Kobo Analytics Tests\n\nRetrieves A/B testing configuration and feature flags for Kobo device.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/kobo/v1/analytics/gettests\n\n**Authentication:** Bearer token\n\n**Request Body:**\n- `platform` (string): Device platform\n - `android`: Kobo Android app\n - `kobo`: Native Kobo firmware\n- `firmware_version` (string): Firmware version (e.g., \"4.30.19023\")\n- `device_model` (string, optional): Device model identifier\n- `locale` (string, optional): Device locale (e.g., \"en_US\")\n\n**Response:**\n- `tests` (array): Active A/B tests\n - `test_name` (string): Test identifier\n - `variant` (string): Assigned variant (A, B, C, etc.)\n - `enabled` (boolean): Whether test is active\n - `parameters` (object): Test-specific parameters\n- `features` (object): Feature flags\n - `feature_name` (boolean/string): Feature state\n- `configuration` (object): Device configuration\n - `sync_interval_minutes` (integer): Recommended sync frequency\n\
|
||||
\ - `batch_size` (integer): Max items per batch sync\n - `timeout_seconds` (integer): Request timeout\n- `version` (string): Configuration version\n\n**Status Codes:**\n- 200: Success\n- 401: Unauthorized\n- 400: Invalid request parameters\n\n**Analytics Testing Purpose:**\n- Kobo uses A/B testing for UX features\n- Feature flags for gradual rollout\n- Performance monitoring configuration\n- Sync behavior optimization\n- Device-specific tuning\n\n**Common Tests:**\n- Sync frequency optimization\n- UI/UX variations\n- Network usage patterns\n- Battery life improvements\n- Feature set variations by model\n\n**Feature Flags:**\n- New sync features\n- Beta functionality\n- Platform-specific capabilities\n- Experimental features\n\n**Configuration Parameters:**\n- Optimal sync intervals for device\n- Batch size limits based on device capabilities\n- Timeout values for network conditions\n- Retry logic configuration\n- Cache policy settings\n\n**Usage:**\n- Called during device initialization\n\
|
||||
- Refreshed daily or weekly\n- Cached on device\n- Affects sync behavior\n- Can be overridden by server\n\n**Use Cases:**\n- Device initialization\n- Feature rollout testing\n- Performance optimization\n- UX experiment participation\n- Configuration management"
|
||||
@@ -5,7 +5,7 @@ info:
|
||||
|
||||
http:
|
||||
method: GET
|
||||
url: '{{base_url}}/api/sync/kobo/library'
|
||||
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/v1/initialization'
|
||||
auth: inherit
|
||||
|
||||
docs: |-
|
||||
|
||||
@@ -4,7 +4,7 @@ info:
|
||||
seq: 1
|
||||
http:
|
||||
method: GET
|
||||
url: '{{base_url}}/sync/unlinked-books/{{unlinkedBookId}}/suggestions'
|
||||
url: '{{base_url}}/api/sync/unlinked-books/{{unlinkedBookId}}/suggestions'
|
||||
auth: inherit
|
||||
body:
|
||||
type: none
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
info:
|
||||
name: Bookhoard Kobo Sync API
|
||||
type: collection
|
||||
seq: 1
|
||||
http:
|
||||
method: POST
|
||||
url: '"http://localhost:8765/api"'
|
||||
|
||||
docs: |-
|
||||
## Bookhoard Kobo Sync API
|
||||
|
||||
Collection of endpoints specifically for Kobo e-reader device synchronization.
|
||||
|
||||
**Base URL:** http://localhost:8765/api
|
||||
|
||||
**Authentication:** Device token or Bearer token required
|
||||
|
||||
**Endpoints:**
|
||||
- Kobo-specific sync protocols
|
||||
- Kobo store integration
|
||||
- Metadata synchronization
|
||||
- Reading progress sync
|
||||
@@ -0,0 +1,7 @@
|
||||
info:
|
||||
name: Bookhoard Kobo Sync API
|
||||
type: folder
|
||||
seq: 1
|
||||
request:
|
||||
auth: inherit
|
||||
docs: "## Bookhoard Kobo Sync API\n\n Collection of endpoints specifically for Kobo e-reader device synchronization.\n\n **Base URL:** http://localhost:8765/api\n\n **Authentication:** Device token or Bearer token required\n\n **Endpoints:**\n - Kobo-specific sync protocols\n - Kobo store integration\n - Metadata synchronization\n - Reading progress sync"
|
||||
@@ -4,42 +4,14 @@ info:
|
||||
seq: 1
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/sync/auto-link-books'
|
||||
url: '{{base_url}}/api/sync/auto-link-books'
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"confidence_threshold\": 0.8,\n \"limit\": 50"
|
||||
data: "{\n \"confidence_threshold\": 0.8,\n \"limit\": 50"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Authorization
|
||||
value: Bearer {{authToken
|
||||
|
||||
docs: |-
|
||||
## Auto-Link Unlinked Books
|
||||
|
||||
Automatically links unlinked books to media items based on title and author matching with a configurable confidence threshold.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /sync/auto-link-books
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Request Body:**
|
||||
- `confidence_threshold` (number, optional): Minimum confidence score for auto-linking (0-1, default: 0.8)
|
||||
- `limit` (number, optional): Maximum number of books to auto-link (default: 50)
|
||||
|
||||
**Response:**
|
||||
- `results` (array): Results for each auto-link attempt
|
||||
- `total` (number): Total number of books processed
|
||||
- `success` (number): Number of successful links
|
||||
- `failed` (number): Number of failed links
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 400: Invalid request data
|
||||
- 401: Unauthorized
|
||||
- 500: Internal server error
|
||||
|
||||
**Note:** Higher confidence thresholds produce fewer but more accurate matches. Consider the tradeoff between automation and accuracy.
|
||||
docs: "## Auto-Link Unlinked Books\n\n Automatically links unlinked books to media items based on title and author matching with a configurable confidence threshold.\n\n **Method:** POST\n\n **Endpoint:** /sync/auto-link-books\n\n **Authentication:** Bearer token\n\n **Request Body:**\n - `confidence_threshold` (number, optional): Minimum confidence score for auto-linking (0-1, default: 0.8)\n - `limit` (number, optional): Maximum number of books to auto-link (default: 50)\n\n **Response:**\n - `results` (array): Results for each auto-link attempt\n - `total` (number): Total number of books processed\n - `success` (number): Number of successful links\n - `failed` (number): Number of failed links\n\n **Status Codes:**\n - 200: Success\n - 400: Invalid request data\n - 401: Unauthorized\n - 500: Internal server error\n\n **Note:** Higher confidence thresholds produce fewer but more accurate matches. Consider the tradeoff between automation and accuracy."
|
||||
@@ -4,44 +4,14 @@ info:
|
||||
seq: 1
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/sync/bulk-link-books'
|
||||
url: '{{base_url}}/api/sync/bulk-link-books'
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"links\": [\n {\n \"unlinked_book_id\": \"{{unlinkedBookId1"
|
||||
data: "{\n \"links\": [\n {\n \"unlinked_book_id\": \"{{unlinkedBookId1"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Authorization
|
||||
value: Bearer {{authToken
|
||||
|
||||
docs: |-
|
||||
## Bulk Link Unlinked Books
|
||||
|
||||
Links multiple unlinked books to media items in a single request.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /sync/bulk-link-books
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Request Body:**
|
||||
- `links` (array): Array of link objects
|
||||
- `unlinked_book_id` (string): Unlinked book UUID
|
||||
- `media_item_id` (string): Media item UUID to link to
|
||||
- `confidence_score` (number): Match confidence (0-1)
|
||||
|
||||
**Response:**
|
||||
- `results` (array): Results for each link attempt
|
||||
- `total` (number): Total number of links processed
|
||||
- `success` (number): Number of successful links
|
||||
- `failed` (number): Number of failed links
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 400: Invalid request data
|
||||
- 401: Unauthorized
|
||||
- 500: Internal server error
|
||||
|
||||
**Note:** Use this endpoint after reviewing suggestions from the Get Unlinked Book Suggestions endpoint.
|
||||
docs: "## Bulk Link Unlinked Books\n\n Links multiple unlinked books to media items in a single request.\n\n **Method:** POST\n\n **Endpoint:** /sync/bulk-link-books\n\n **Authentication:** Bearer token\n\n **Request Body:**\n - `links` (array): Array of link objects\n - `unlinked_book_id` (string): Unlinked book UUID\n - `media_item_id` (string): Media item UUID to link to\n - `confidence_score` (number): Match confidence (0-1)\n\n **Response:**\n - `results` (array): Results for each link attempt\n - `total` (number): Total number of links processed\n - `success` (number): Number of successful links\n - `failed` (number): Number of failed links\n\n **Status Codes:**\n - 200: Success\n - 400: Invalid request data\n - 401: Unauthorized\n - 500: Internal server error\n\n **Note:** Use this endpoint after reviewing suggestions from the Get Unlinked Book Suggestions endpoint."
|
||||
@@ -5,7 +5,7 @@ info:
|
||||
|
||||
http:
|
||||
method: GET
|
||||
url: '{{base_url}}/api/sync/kobo/v1/initialization'
|
||||
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/v1/initialization'
|
||||
auth: inherit
|
||||
|
||||
docs: |-
|
||||
|
||||
@@ -4,50 +4,13 @@ info:
|
||||
seq: 1
|
||||
http:
|
||||
method: POST
|
||||
url: '{{baseURL}}/api/sync/kobo/sync-from-server'
|
||||
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/sync-from-server'
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "[\n {\n \"ContentId\": \"{{bookUUID"
|
||||
data: "[\n {\n \"ContentId\": \"{{bookUUID"
|
||||
headers:
|
||||
- key: Authorization
|
||||
value: Bearer {{koboToken
|
||||
|
||||
docs: |-
|
||||
## Sync from Bookhoard to Kobo
|
||||
|
||||
Server-initiated sync pushing progress, bookmarks, and highlights from Bookhoard to Kobo device. Two-way sync endpoint.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/kobo/sync-from-server
|
||||
|
||||
**Authentication:** Bearer token with Kobo device identification
|
||||
|
||||
**Headers:**
|
||||
- `x-kobo-device` (string): JSON string containing Kobo device info
|
||||
- `DeviceId`: Kobo device ID
|
||||
- `Model`: Kobo device model
|
||||
- `SerialNumber`: Kobo device serial number
|
||||
|
||||
**Request Body:** Array of sync data objects
|
||||
- `ContentId` (string): Book UUID
|
||||
- `PercentRead` (number): Reading progress percentage (0-100)
|
||||
- `LastModified` (string): ISO 8601 timestamp
|
||||
- `Bookmarks` (array, optional): Array of bookmark objects
|
||||
- `BookmarkId`: Unique bookmark ID
|
||||
- `ContentId`: Book UUID
|
||||
- `BookmarkText`: Bookmark text/note
|
||||
- `BookmarkType`: Type (bookmark, annotation, etc.)
|
||||
- `BookmarkTitle`: Bookmark title
|
||||
- `Highlights` (array, optional): Array of highlight objects (same structure as bookmarks)
|
||||
|
||||
**Response:**
|
||||
- Sync result confirmation
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 401: Unauthorized
|
||||
- 500: Internal server error
|
||||
|
||||
**Note:** Allows Bookhoard server to push updates to Kobo device, including reading progress, bookmarks, and highlights.
|
||||
docs: "## Sync from Bookhoard to Kobo\n\n Server-initiated sync pushing progress, bookmarks, and highlights from Bookhoard to Kobo device. Two-way sync endpoint.\n\n **Method:** POST\n\n **Endpoint:** /api/sync/kobo/sync-from-server\n\n **Authentication:** Bearer token with Kobo device identification\n\n **Headers:**\n - `x-kobo-device` (string): JSON string containing Kobo device info\n - `DeviceId`: Kobo device ID\n - `Model`: Kobo device model\n - `SerialNumber`: Kobo device serial number\n\n **Request Body:** Array of sync data objects\n - `ContentId` (string): Book UUID\n - `PercentRead` (number): Reading progress percentage (0-100)\n - `LastModified` (string): ISO 8601 timestamp\n - `Bookmarks` (array, optional): Array of bookmark objects\n - `BookmarkId`: Unique bookmark ID\n - `ContentId`: Book UUID\n - `BookmarkText`: Bookmark text/note\n - `BookmarkType`: Type (bookmark, annotation, etc.)\n - `BookmarkTitle`: Bookmark title\n - `Highlights` (array,\
|
||||
\ optional): Array of highlight objects (same structure as bookmarks)\n\n **Response:**\n - Sync result confirmation\n\n **Status Codes:**\n - 200: Success\n - 401: Unauthorized\n - 500: Internal server error\n\n **Note:** Allows Bookhoard server to push updates to Kobo device, including reading progress, bookmarks, and highlights."
|
||||
@@ -2,105 +2,16 @@ info:
|
||||
name: Sync Books from Server to Kobo
|
||||
type: http
|
||||
seq: 9
|
||||
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/kobo/sync-from-server'
|
||||
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/sync-from-server'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
force_sync: true
|
||||
books:
|
||||
- book-uuid-1
|
||||
- book-uuid-2
|
||||
|
||||
docs: |-
|
||||
## Sync Books from Server to Kobo
|
||||
|
||||
Pulls reading progress, annotations, and bookmarks from server to Kobo device.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/kobo/sync-from-server
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Request Body:**
|
||||
- `force_sync` (boolean): Force full sync (ignore last sync time)
|
||||
- `books` (array, optional): List of book UUIDs to sync
|
||||
- If empty, syncs all books with server data
|
||||
- If specified, only syncs listed books
|
||||
- `sync_options` (object, optional):
|
||||
- `since_date` (string): ISO 8601 timestamp for incremental sync
|
||||
- `include_annotations` (boolean): Include highlights/notes
|
||||
- `include_progress` (boolean): Include reading progress
|
||||
- `conflict_resolution` (string): `most_recent`, `server_wins`, `client_wins`
|
||||
|
||||
**Response:**
|
||||
- `synced` (integer): Number of books synced
|
||||
- `skipped` (integer): Books with no server changes
|
||||
- `failed` (integer): Books that failed to sync
|
||||
- `results` (array): Per-book sync results
|
||||
- `book_id` (string): Book UUID
|
||||
- `status` (string): `synced`, `skipped`, `failed`
|
||||
- `progress_pulled` (boolean): Whether progress was downloaded
|
||||
- `annotations_pulled` (integer): Number of annotations downloaded
|
||||
- `error` (string, optional): Error message if failed
|
||||
- `server_timestamp` (string): Server timestamp of sync
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Sync completed
|
||||
- 207: Multi-status (some succeeded, some failed)
|
||||
- 401: Unauthorized
|
||||
- 400: Invalid request
|
||||
|
||||
**Sync Direction:**
|
||||
- **Server → Device** (this endpoint)
|
||||
- Device → Server: Use `/sync/kobo/markup` endpoint
|
||||
- Bidirectional sync achieved by calling both
|
||||
|
||||
**Pull Sync Use Cases:**
|
||||
- New device setup (download all progress)
|
||||
- Device replacement (restore from server)
|
||||
- Multi-device sync (pull changes from other devices)
|
||||
- Conflict resolution (server wins)
|
||||
- Manual "Download from server" operation
|
||||
|
||||
**Conflict Resolution:**
|
||||
- `most_recent`: Latest timestamp wins (default)
|
||||
- `server_wins`: Server data always used
|
||||
- `client_wins`: Device data preserved
|
||||
- Applied per-book, per-item
|
||||
|
||||
**Sync Optimization:**
|
||||
- Incremental sync by default (since last sync)
|
||||
- Force sync does full comparison
|
||||
- Book-level batching (10 books per batch)
|
||||
- Delta transfer (only changed items)
|
||||
- Compression for large annotation sets
|
||||
|
||||
**Kobo Device Behavior:**
|
||||
- Device updates local database
|
||||
- Progress reflected in reading view
|
||||
- Annotations appear in Notebook
|
||||
- Bookmarks updated in navigation
|
||||
- Conflict warnings shown to user
|
||||
- Sync progress displayed on screen
|
||||
|
||||
**Performance:**
|
||||
- Small sync (1-10 books): 2-5 seconds
|
||||
- Medium sync (10-50 books): 5-15 seconds
|
||||
- Large sync (50-200 books): 15-45 seconds
|
||||
- Timeout: 120 seconds
|
||||
|
||||
**Use Cases:**
|
||||
- Initial device sync
|
||||
- After firmware update
|
||||
- From another device's changes
|
||||
- Manual sync request
|
||||
- Conflict recovery
|
||||
- Data restoration
|
||||
data: "{\n \"force_sync\": true,\n \"books\": [\n \"book-uuid-1\",\n \"book-uuid-2\"\n ]\n}"
|
||||
docs: "## Sync Books from Server to Kobo\n\nPulls reading progress, annotations, and bookmarks from server to Kobo device.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/kobo/sync-from-server\n\n**Authentication:** Bearer token\n\n**Request Body:**\n- `force_sync` (boolean): Force full sync (ignore last sync time)\n- `books` (array, optional): List of book UUIDs to sync\n - If empty, syncs all books with server data\n - If specified, only syncs listed books\n- `sync_options` (object, optional):\n - `since_date` (string): ISO 8601 timestamp for incremental sync\n - `include_annotations` (boolean): Include highlights/notes\n - `include_progress` (boolean): Include reading progress\n - `conflict_resolution` (string): `most_recent`, `server_wins`, `client_wins`\n\n**Response:**\n- `synced` (integer): Number of books synced\n- `skipped` (integer): Books with no server changes\n- `failed` (integer): Books that failed to sync\n- `results` (array): Per-book sync results\n - `book_id` (string):\
|
||||
\ Book UUID\n - `status` (string): `synced`, `skipped`, `failed`\n - `progress_pulled` (boolean): Whether progress was downloaded\n - `annotations_pulled` (integer): Number of annotations downloaded\n - `error` (string, optional): Error message if failed\n- `server_timestamp` (string): Server timestamp of sync\n\n**Status Codes:**\n- 200: Sync completed\n- 207: Multi-status (some succeeded, some failed)\n- 401: Unauthorized\n- 400: Invalid request\n\n**Sync Direction:**\n- **Server → Device** (this endpoint)\n- Device → Server: Use `/sync/kobo/markup` endpoint\n- Bidirectional sync achieved by calling both\n\n**Pull Sync Use Cases:**\n- New device setup (download all progress)\n- Device replacement (restore from server)\n- Multi-device sync (pull changes from other devices)\n- Conflict resolution (server wins)\n- Manual \"Download from server\" operation\n\n**Conflict Resolution:**\n- `most_recent`: Latest timestamp wins (default)\n- `server_wins`: Server data always used\n- `client_wins`:\
|
||||
\ Device data preserved\n- Applied per-book, per-item\n\n**Sync Optimization:**\n- Incremental sync by default (since last sync)\n- Force sync does full comparison\n- Book-level batching (10 books per batch)\n- Delta transfer (only changed items)\n- Compression for large annotation sets\n\n**Kobo Device Behavior:**\n- Device updates local database\n- Progress reflected in reading view\n- Annotations appear in Notebook\n- Bookmarks updated in navigation\n- Conflict warnings shown to user\n- Sync progress displayed on screen\n\n**Performance:**\n- Small sync (1-10 books): 2-5 seconds\n- Medium sync (10-50 books): 5-15 seconds\n- Large sync (50-200 books): 15-45 seconds\n- Timeout: 120 seconds\n\n**Use Cases:**\n- Initial device sync\n- After firmware update\n- From another device's changes\n- Manual sync request\n- Conflict recovery\n- Data restoration"
|
||||
@@ -2,90 +2,17 @@ info:
|
||||
name: Sync Multiple Books Progress
|
||||
type: http
|
||||
seq: 3
|
||||
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/kobo/markup'
|
||||
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/markup'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: x-kobo-device
|
||||
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Aura"}'
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: x-kobo-device
|
||||
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Aura"}'
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
ReadingSync:
|
||||
- ContentId: book-1-uuid
|
||||
PercentRead: 25.0
|
||||
EntitlementId: entitlement-1
|
||||
RemainingTimeMinutes: 240
|
||||
FirstReadTime: '2026-01-25T10:00:00Z'
|
||||
LastModified: '2026-01-30T18:00:00Z'
|
||||
- ContentId: book-2-uuid
|
||||
PercentRead: 78.5
|
||||
EntitlementId: entitlement-2
|
||||
RemainingTimeMinutes: 45
|
||||
FirstReadTime: '2026-01-25T14:00:00Z'
|
||||
LastModified: '2026-01-30T20:00:00Z'
|
||||
BookmarkSync: []
|
||||
|
||||
docs: |-
|
||||
## Sync Multiple Books Progress
|
||||
|
||||
Synchronizes reading progress for multiple books in a single request.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/kobo/markup
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Headers:**
|
||||
- `Authorization`: Bearer {{kobo_device_token}}
|
||||
- `x-kobo-device`: Device information (Model: "Kobo Aura")
|
||||
|
||||
**Request Body:**
|
||||
- `ReadingSync` (array): Multiple progress items
|
||||
- Each item contains: ContentId, PercentRead, EntitlementId, etc.
|
||||
- `BookmarkSync` (array): Empty for progress-only batch
|
||||
|
||||
**Response:**
|
||||
- `total` (integer): Total items in request
|
||||
- `synced` (integer): Successfully synced
|
||||
- `failed` (integer): Failed items
|
||||
- `results` (array): Per-item results
|
||||
- `ContentId` (string): Book UUID
|
||||
- `status` (string): `synced`, `failed`, `skipped`
|
||||
- `error` (string, optional): Error message if failed
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Batch sync completed
|
||||
- 207: Multi-status (some succeeded, some failed)
|
||||
- 401: Unauthorized
|
||||
- 413: Payload too large (>1MB)
|
||||
|
||||
**Batch Sync Advantages:**
|
||||
- Efficient sync of entire library
|
||||
- Reduces HTTP overhead
|
||||
- Faster for devices with many books
|
||||
- Atomic operation (all or nothing by default)
|
||||
|
||||
**Kobo Batch Sync Behavior:**
|
||||
- Triggered when device connects after being offline
|
||||
- Occurs during manual "Sync now" operation
|
||||
- Limited to 100 books per request
|
||||
- Progress updates shown on device
|
||||
- Failed items retried individually
|
||||
|
||||
**Performance:**
|
||||
- Typical batch: 10-50 books in 1-3 seconds
|
||||
- Large batch: 50-100 books in 3-8 seconds
|
||||
- Timeout: 30 seconds
|
||||
- Rate limit: 10 batches per minute per device
|
||||
|
||||
**Use Cases:**
|
||||
- Initial device sync after registration
|
||||
- Catch-up sync after extended offline period
|
||||
- Library-wide progress update
|
||||
- Pre-sync before device firmware update
|
||||
data: "{\n \"ReadingSync\": [\n {\n \"ContentId\": \"book-1-uuid\",\n \"PercentRead\": 25.0,\n \"EntitlementId\": \"entitlement-1\",\n \"RemainingTimeMinutes\": 240,\n \"FirstReadTime\": \"2026-01-25T10:00:00Z\",\n \"LastModified\": \"2026-01-30T18:00:00Z\"\n },\n {\n \"ContentId\": \"book-2-uuid\",\n \"PercentRead\": 78.5,\n \"EntitlementId\": \"entitlement-2\",\n \"RemainingTimeMinutes\": 45,\n \"FirstReadTime\": \"2026-01-25T14:00:00Z\",\n \"LastModified\": \"2026-01-30T20:00:00Z\"\n }\n ],\n \"BookmarkSync\": []\n}"
|
||||
docs: "## Sync Multiple Books Progress\n\nSynchronizes reading progress for multiple books in a single request.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/kobo/markup\n\n**Authentication:** Bearer token\n\n**Headers:**\n- `Authorization`: Bearer {{kobo_device_token}}\n- `x-kobo-device`: Device information (Model: \"Kobo Aura\")\n\n**Request Body:**\n- `ReadingSync` (array): Multiple progress items\n - Each item contains: ContentId, PercentRead, EntitlementId, etc.\n- `BookmarkSync` (array): Empty for progress-only batch\n\n**Response:**\n- `total` (integer): Total items in request\n- `synced` (integer): Successfully synced\n- `failed` (integer): Failed items\n- `results` (array): Per-item results\n - `ContentId` (string): Book UUID\n - `status` (string): `synced`, `failed`, `skipped`\n - `error` (string, optional): Error message if failed\n\n**Status Codes:**\n- 200: Batch sync completed\n- 207: Multi-status (some succeeded, some failed)\n- 401: Unauthorized\n- 413: Payload too large\
|
||||
\ (>1MB)\n\n**Batch Sync Advantages:**\n- Efficient sync of entire library\n- Reduces HTTP overhead\n- Faster for devices with many books\n- Atomic operation (all or nothing by default)\n\n**Kobo Batch Sync Behavior:**\n- Triggered when device connects after being offline\n- Occurs during manual \"Sync now\" operation\n- Limited to 100 books per request\n- Progress updates shown on device\n- Failed items retried individually\n\n**Performance:**\n- Typical batch: 10-50 books in 1-3 seconds\n- Large batch: 50-100 books in 3-8 seconds\n- Timeout: 30 seconds\n- Rate limit: 10 batches per minute per device\n\n**Use Cases:**\n- Initial device sync after registration\n- Catch-up sync after extended offline period\n- Library-wide progress update\n- Pre-sync before device firmware update"
|
||||
@@ -2,83 +2,17 @@ info:
|
||||
name: Sync Progress with Bookmarks
|
||||
type: http
|
||||
seq: 2
|
||||
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/kobo/markup'
|
||||
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/markup'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: x-kobo-device
|
||||
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Clara"}'
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: x-kobo-device
|
||||
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Clara"}'
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
ReadingSync:
|
||||
- ContentId: book-uuid
|
||||
PercentRead: 42.3
|
||||
EntitlementId: entitlement-id
|
||||
RemainingTimeMinutes: 138
|
||||
FirstReadTime: '2026-01-25T10:00:00Z'
|
||||
LastModified: '2026-01-30T20:00:00Z'
|
||||
BookmarkSync:
|
||||
- ContentId: book-uuid
|
||||
BookmarkText: highlighted text passage
|
||||
BookmarkType: annotation
|
||||
BookmarkTitle: Chapter 3
|
||||
|
||||
docs: |-
|
||||
## Sync Progress with Bookmarks
|
||||
|
||||
Synchronizes reading progress and highlights/annotations from Kobo device.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/kobo/markup
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Headers:**
|
||||
- `Authorization`: Bearer {{kobo_device_token}}
|
||||
- `x-kobo-device`: Device information JSON
|
||||
|
||||
**Request Body:**
|
||||
- `ReadingSync` (array): Progress items (see Sync Reading Progress)
|
||||
- `BookmarkSync` (array): Highlights and annotations
|
||||
- `ContentId` (string): Book UUID
|
||||
- `BookmarkText` (string): Highlighted text or note content
|
||||
- `BookmarkType` (string): Type of bookmark
|
||||
- `annotation`: Highlighted text
|
||||
- `note`: Personal note
|
||||
- `bookmark`: Location bookmark
|
||||
- `BookmarkTitle` (string): Reference (e.g., chapter name)
|
||||
- `ChapterID` (string, optional): Chapter identifier
|
||||
- `DateCreated` (string, optional): Creation timestamp
|
||||
|
||||
**Response:**
|
||||
- `progress_synced` (integer): Progress items synced
|
||||
- `bookmarks_synced` (integer): Bookmark items synced
|
||||
- `conflicts_resolved` (integer): Number of conflicts auto-resolved
|
||||
- `timestamp` (string): Sync timestamp
|
||||
- `details` (object): Sync breakdown by type
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Successful sync
|
||||
- 401: Unauthorized
|
||||
- 400: Invalid data
|
||||
|
||||
**Kobo Highlight Features:**
|
||||
- 5 highlight colors (yellow, green, blue, pink, orange)
|
||||
- Chapter-based organization
|
||||
- Linked to reading progress
|
||||
- Appears in Kobo "Notebook" view
|
||||
- Can be exported from device
|
||||
- Syncs across all user devices
|
||||
|
||||
**Annotation Sync:**
|
||||
- Highlight text preserved exactly
|
||||
- Color mapped to system colors
|
||||
- Chapter reference maintained
|
||||
- Location data converted to standard format
|
||||
- Notes attached to highlights synced separately
|
||||
data: "{\n \"ReadingSync\": [\n {\n \"ContentId\": \"book-uuid\",\n \"PercentRead\": 42.3,\n \"EntitlementId\": \"entitlement-id\",\n \"RemainingTimeMinutes\": 138,\n \"FirstReadTime\": \"2026-01-25T10:00:00Z\",\n \"LastModified\": \"2026-01-30T20:00:00Z\"\n }\n ],\n \"BookmarkSync\": [\n {\n \"ContentId\": \"book-uuid\",\n \"BookmarkText\": \"highlighted text passage\",\n \"BookmarkType\": \"annotation\",\n \"BookmarkTitle\": \"Chapter 3\"\n }\n ]\n}"
|
||||
docs: "## Sync Progress with Bookmarks\n\nSynchronizes reading progress and highlights/annotations from Kobo device.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/kobo/markup\n\n**Authentication:** Bearer token\n\n**Headers:**\n- `Authorization`: Bearer {{kobo_device_token}}\n- `x-kobo-device`: Device information JSON\n\n**Request Body:**\n- `ReadingSync` (array): Progress items (see Sync Reading Progress)\n- `BookmarkSync` (array): Highlights and annotations\n - `ContentId` (string): Book UUID\n - `BookmarkText` (string): Highlighted text or note content\n - `BookmarkType` (string): Type of bookmark\n - `annotation`: Highlighted text\n - `note`: Personal note\n - `bookmark`: Location bookmark\n - `BookmarkTitle` (string): Reference (e.g., chapter name)\n - `ChapterID` (string, optional): Chapter identifier\n - `DateCreated` (string, optional): Creation timestamp\n\n**Response:**\n- `progress_synced` (integer): Progress items synced\n- `bookmarks_synced` (integer): Bookmark\
|
||||
\ items synced\n- `conflicts_resolved` (integer): Number of conflicts auto-resolved\n- `timestamp` (string): Sync timestamp\n- `details` (object): Sync breakdown by type\n\n**Status Codes:**\n- 200: Successful sync\n- 401: Unauthorized\n- 400: Invalid data\n\n**Kobo Highlight Features:**\n- 5 highlight colors (yellow, green, blue, pink, orange)\n- Chapter-based organization\n- Linked to reading progress\n- Appears in Kobo \"Notebook\" view\n- Can be exported from device\n- Syncs across all user devices\n\n**Annotation Sync:**\n- Highlight text preserved exactly\n- Color mapped to system colors\n- Chapter reference maintained\n- Location data converted to standard format\n- Notes attached to highlights synced separately"
|
||||
@@ -2,83 +2,18 @@ info:
|
||||
name: Sync Reading Progress
|
||||
type: http
|
||||
seq: 1
|
||||
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/kobo/markup'
|
||||
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/markup'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: x-kobo-device
|
||||
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Clara"}'
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: x-kobo-device
|
||||
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Clara"}'
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
ReadingSync:
|
||||
- ContentId: book-uuid-here
|
||||
PercentRead: 45.6
|
||||
EntitlementId: entitlement-id-here
|
||||
RemainingTimeMinutes: 120
|
||||
FirstReadTime: '2026-01-25T10:00:00Z'
|
||||
LastModified: '2026-01-30T20:00:00Z'
|
||||
BookmarkSync: []
|
||||
|
||||
docs: |-
|
||||
## Sync Kobo Reading Progress
|
||||
|
||||
Synchronizes reading progress from a Kobo device to the server using Bearer token authentication.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/kobo/markup
|
||||
|
||||
**Authentication:** Bearer token (in Authorization header)
|
||||
|
||||
**Headers:**
|
||||
- `Authorization`: Bearer {{kobo_device_token}}
|
||||
- `x-kobo-device`: JSON-encoded device info
|
||||
- `DeviceId`: Kobo device identifier
|
||||
- `Model`: Device model (e.g., "Kobo Clara", "Kobo Libra", "Kobo Aura")
|
||||
|
||||
**Request Body:**
|
||||
- `ReadingSync` (array): Reading progress items
|
||||
- `ContentId` (string): Book/Content UUID
|
||||
- `PercentRead` (number): Reading progress 0-100
|
||||
- `EntitlementId` (string): Kobo entitlement ID
|
||||
- `RemainingTimeMinutes` (integer): Estimated reading time remaining
|
||||
- `FirstReadTime` (string): ISO 8601 timestamp when first opened
|
||||
- `LastModified` (string): ISO 8601 timestamp of last progress update
|
||||
- `BookmarkSync` (array): Empty array for progress-only sync
|
||||
|
||||
**Response:**
|
||||
- `synced` (integer): Number of items synced
|
||||
- `failed` (integer): Number of items that failed to sync
|
||||
- `timestamp` (string): Server timestamp of sync
|
||||
- `books` (array): Synced book data
|
||||
- `ContentId` (string): Book UUID
|
||||
- `status` (string): `synced`, `failed`, `skipped`
|
||||
- `server_percent` (number): Server-side progress (for conflict detection)
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Sync successful
|
||||
- 401: Invalid device token
|
||||
- 403: Device not approved
|
||||
- 400: Invalid request format
|
||||
|
||||
**Authentication Methods:**
|
||||
This endpoint uses **Bearer token authentication** (token in Authorization header).
|
||||
Alternative: Use `/sync/kobo/{token}/markup` with token in URL path.
|
||||
|
||||
**Kobo Sync Features:**
|
||||
- Native Kobo sync protocol
|
||||
- Supports Kobo Clara, Libra, Aura, Forma, Sage, Elipsa
|
||||
- Progress percentage tracking
|
||||
- Reading time estimation
|
||||
- Cross-device synchronization
|
||||
- Automatic conflict resolution (most recent wins)
|
||||
|
||||
**Sync Frequency:**
|
||||
- Kobo devices auto-sync every 15-30 minutes when connected to WiFi
|
||||
- Manual sync available from device settings
|
||||
- Sync triggers on: device wake, book close, WiFi connection
|
||||
data: "{\n \"ReadingSync\": [\n {\n \"ContentId\": \"book-uuid-here\",\n \"PercentRead\": 45.6,\n \"EntitlementId\": \"entitlement-id-here\",\n \"RemainingTimeMinutes\": 120,\n \"FirstReadTime\": \"2026-01-25T10:00:00Z\",\n \"LastModified\": \"2026-01-30T20:00:00Z\"\n }\n ],\n \"BookmarkSync\": []\n}"
|
||||
docs: "## Sync Kobo Reading Progress\n\nSynchronizes reading progress from a Kobo device to the server using Bearer token authentication.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/kobo/markup\n\n**Authentication:** Bearer token (in Authorization header)\n\n**Headers:**\n- `Authorization`: Bearer {{kobo_device_token}}\n- `x-kobo-device`: JSON-encoded device info\n - `DeviceId`: Kobo device identifier\n - `Model`: Device model (e.g., \"Kobo Clara\", \"Kobo Libra\", \"Kobo Aura\")\n\n**Request Body:**\n- `ReadingSync` (array): Reading progress items\n - `ContentId` (string): Book/Content UUID\n - `PercentRead` (number): Reading progress 0-100\n - `EntitlementId` (string): Kobo entitlement ID\n - `RemainingTimeMinutes` (integer): Estimated reading time remaining\n - `FirstReadTime` (string): ISO 8601 timestamp when first opened\n - `LastModified` (string): ISO 8601 timestamp of last progress update\n- `BookmarkSync` (array): Empty array for progress-only sync\n\n**Response:**\n\
|
||||
- `synced` (integer): Number of items synced\n- `failed` (integer): Number of items that failed to sync\n- `timestamp` (string): Server timestamp of sync\n- `books` (array): Synced book data\n - `ContentId` (string): Book UUID\n - `status` (string): `synced`, `failed`, `skipped`\n - `server_percent` (number): Server-side progress (for conflict detection)\n\n**Status Codes:**\n- 200: Sync successful\n- 401: Invalid device token\n- 403: Device not approved\n- 400: Invalid request format\n\n**Authentication Methods:**\nThis endpoint uses **Bearer token authentication** (token in Authorization header).\nAlternative: Use `/sync/kobo/{token}/markup` with token in URL path.\n\n**Kobo Sync Features:**\n- Native Kobo sync protocol\n- Supports Kobo Clara, Libra, Aura, Forma, Sage, Elipsa\n- Progress percentage tracking\n- Reading time estimation\n- Cross-device synchronization\n- Automatic conflict resolution (most recent wins)\n\n**Sync Frequency:**\n- Kobo devices auto-sync every 15-30 minutes\
|
||||
\ when connected to WiFi\n- Manual sync available from device settings\n- Sync triggers on: device wake, book close, WiFi connection"
|
||||
@@ -2,91 +2,18 @@ info:
|
||||
name: Sync Single Bookmark
|
||||
type: http
|
||||
seq: 5
|
||||
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/kobo/bookmark'
|
||||
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/bookmark'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: x-kobo-device
|
||||
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Clara"}'
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: x-kobo-device
|
||||
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Clara"}'
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
ContentId: book-uuid
|
||||
BookmarkText: Bookmarked passage
|
||||
BookmarkType: annotation
|
||||
BookmarkTitle: Chapter 3
|
||||
|
||||
docs: |-
|
||||
## Sync Single Bookmark
|
||||
|
||||
Synchronizes an individual bookmark/highlight from Kobo device.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/kobo/bookmark
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Headers:**
|
||||
- `Authorization`: Bearer {{kobo_device_token}}
|
||||
- `x-kobo-device`: Device information JSON
|
||||
|
||||
**Request Body:**
|
||||
- `ContentId` (string): Book UUID
|
||||
- `BookmarkText` (string): Highlighted text or bookmark description
|
||||
- `BookmarkType` (string): Type of bookmark
|
||||
- `annotation`: Highlighted text passage
|
||||
- `note`: Personal note
|
||||
- `bookmark`: Location marker
|
||||
- `BookmarkTitle` (string): Reference title (e.g., chapter name)
|
||||
- `ChapterID` (string, optional): Chapter identifier
|
||||
- `DateCreated` (string, optional): ISO 8601 timestamp
|
||||
- `highlight_color` (string, optional): Color name (yellow, green, blue, pink, orange)
|
||||
|
||||
**Response:**
|
||||
- `id` (string): Server bookmark ID
|
||||
- `ContentId` (string): Associated book UUID
|
||||
- `status` (string): `created`, `updated`, `skipped` (duplicate)
|
||||
- `timestamp` (string): Server timestamp
|
||||
- `url` (string): API URL to retrieve bookmark
|
||||
|
||||
**Status Codes:**
|
||||
- 201: Bookmark created
|
||||
- 200: Bookmark updated (duplicate found)
|
||||
- 409: Duplicate bookmark (unchanged)
|
||||
- 401: Unauthorized
|
||||
- 400: Invalid bookmark data
|
||||
|
||||
**Single Bookmark Sync vs Batch:**
|
||||
- **Single bookmark endpoint:** Real-time, immediate sync
|
||||
- **Batch markup endpoint:** Deferred, periodic sync
|
||||
- Use single when user explicitly creates highlight
|
||||
- Use batch for periodic background sync
|
||||
|
||||
**Kobo Trigger:**
|
||||
- User highlights text → immediate single sync
|
||||
- User adds note → immediate single sync
|
||||
- Device goes online → batch sync of all changes
|
||||
|
||||
**Duplicate Detection:**
|
||||
- Same ContentId + similar BookmarkText + same location
|
||||
- Updates existing if text modified
|
||||
- Skips if identical bookmark exists
|
||||
- Preserves creation date of original
|
||||
|
||||
**Use Cases:**
|
||||
- Real-time highlight sync
|
||||
- Instant note backup
|
||||
- Immediate annotation sharing
|
||||
- Quick single annotation update
|
||||
- Testing annotation sync
|
||||
|
||||
**Notes:**
|
||||
- Much faster than full markup sync
|
||||
- Lower bandwidth usage
|
||||
- Ideal for intermittent connectivity
|
||||
- Can be called multiple times safely
|
||||
data: "{\n \"ContentId\": \"book-uuid\",\n \"BookmarkText\": \"Bookmarked passage\",\n \"BookmarkType\": \"annotation\",\n \"BookmarkTitle\": \"Chapter 3\"\n}"
|
||||
docs: "## Sync Single Bookmark\n\nSynchronizes an individual bookmark/highlight from Kobo device.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/kobo/bookmark\n\n**Authentication:** Bearer token\n\n**Headers:**\n- `Authorization`: Bearer {{kobo_device_token}}\n- `x-kobo-device`: Device information JSON\n\n**Request Body:**\n- `ContentId` (string): Book UUID\n- `BookmarkText` (string): Highlighted text or bookmark description\n- `BookmarkType` (string): Type of bookmark\n - `annotation`: Highlighted text passage\n - `note`: Personal note\n - `bookmark`: Location marker\n- `BookmarkTitle` (string): Reference title (e.g., chapter name)\n- `ChapterID` (string, optional): Chapter identifier\n- `DateCreated` (string, optional): ISO 8601 timestamp\n- `highlight_color` (string, optional): Color name (yellow, green, blue, pink, orange)\n\n**Response:**\n- `id` (string): Server bookmark ID\n- `ContentId` (string): Associated book UUID\n- `status` (string): `created`, `updated`, `skipped` (duplicate)\n\
|
||||
- `timestamp` (string): Server timestamp\n- `url` (string): API URL to retrieve bookmark\n\n**Status Codes:**\n- 201: Bookmark created\n- 200: Bookmark updated (duplicate found)\n- 409: Duplicate bookmark (unchanged)\n- 401: Unauthorized\n- 400: Invalid bookmark data\n\n**Single Bookmark Sync vs Batch:**\n- **Single bookmark endpoint:** Real-time, immediate sync\n- **Batch markup endpoint:** Deferred, periodic sync\n- Use single when user explicitly creates highlight\n- Use batch for periodic background sync\n\n**Kobo Trigger:**\n- User highlights text → immediate single sync\n- User adds note → immediate single sync\n- Device goes online → batch sync of all changes\n\n**Duplicate Detection:**\n- Same ContentId + similar BookmarkText + same location\n- Updates existing if text modified\n- Skips if identical bookmark exists\n- Preserves creation date of original\n\n**Use Cases:**\n- Real-time highlight sync\n- Instant note backup\n- Immediate annotation sharing\n- Quick single annotation\
|
||||
\ update\n- Testing annotation sync\n\n**Notes:**\n- Much faster than full markup sync\n- Lower bandwidth usage\n- Ideal for intermittent connectivity\n- Can be called multiple times safely"
|
||||
@@ -2,105 +2,17 @@ info:
|
||||
name: Sync with Annotations
|
||||
type: http
|
||||
seq: 4
|
||||
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/kobo/markup'
|
||||
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/markup'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: x-kobo-device
|
||||
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Libra"}'
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: x-kobo-device
|
||||
value: '{"DeviceId":"{{kobo_device_id}}","Model":"Kobo Libra"}'
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
ReadingSync:
|
||||
- ContentId: book-uuid
|
||||
PercentRead: 55.0
|
||||
EntitlementId: entitlement-id
|
||||
RemainingTimeMinutes: 120
|
||||
FirstReadTime: '2026-01-25T10:00:00Z'
|
||||
LastModified: '2026-01-30T20:00:00Z'
|
||||
BookmarkSync:
|
||||
- ContentId: book-uuid
|
||||
BookmarkText: Important quote
|
||||
BookmarkType: annotation
|
||||
BookmarkTitle: Chapter 4 - The Truth
|
||||
- ContentId: book-uuid
|
||||
BookmarkText: Another quote
|
||||
BookmarkType: annotation
|
||||
BookmarkTitle: Chapter 5
|
||||
- ContentId: book-uuid
|
||||
BookmarkText: Note to myself
|
||||
BookmarkType: note
|
||||
BookmarkTitle: Personal note
|
||||
|
||||
docs: |-
|
||||
## Sync with Multiple Annotations
|
||||
|
||||
Synchronizes reading progress with multiple highlights and notes.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/kobo/markup
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Headers:**
|
||||
- `Authorization`: Bearer {{kobo_device_token}}
|
||||
- `x-kobo-device`: Device info (Model: "Kobo Libra")
|
||||
|
||||
**Request Body:**
|
||||
- `ReadingSync` (array): Single book progress
|
||||
- `BookmarkSync` (array): Multiple annotations
|
||||
- Can include highlights (annotation type)
|
||||
- Can include notes (note type)
|
||||
- Each has: ContentId, BookmarkText, BookmarkType, BookmarkTitle
|
||||
|
||||
**Response:**
|
||||
- `progress_synced` (boolean): Progress update status
|
||||
- `annotations_synced` (integer): Number of annotations synced
|
||||
- `highlights_count` (integer): Highlights synced
|
||||
- `notes_count` (integer): Notes synced
|
||||
- `conflicts` (array): Any annotation conflicts resolved
|
||||
- `timestamp` (string): Sync completion time
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Successful sync
|
||||
- 401: Unauthorized
|
||||
- 400: Invalid annotation data
|
||||
|
||||
**Kobo Annotation Types:**
|
||||
- **Highlights:** Selected text passages
|
||||
- 5 preset colors available
|
||||
- Can have chapter titles
|
||||
- Exportable to PDF/Mobile
|
||||
- **Notes:** Personal annotations
|
||||
- Free-form text
|
||||
- Can be attached to highlights
|
||||
- Separate from highlights
|
||||
- **Bookmarks:** Location markers
|
||||
- Chapter positions
|
||||
- Quick navigation
|
||||
|
||||
**Sync Behavior:**
|
||||
- Duplicates detected by content matching
|
||||
- Most recent edit wins conflicts
|
||||
- Annotations linked to book content
|
||||
- Chapter references preserved
|
||||
- Order maintained from device
|
||||
|
||||
**Kobo Notebook Export:**
|
||||
- All annotations appear in Kobo "Notebook"
|
||||
- Can be exported to PDF
|
||||
- Can be exported to Mobile (text)
|
||||
- Organized by book
|
||||
- Shows highlight context
|
||||
|
||||
**Use Cases:**
|
||||
- Study and research
|
||||
- Book club discussion prep
|
||||
- Content review
|
||||
- Sharing insights
|
||||
- Personal learning archive
|
||||
data: "{\n \"ReadingSync\": [\n {\n \"ContentId\": \"book-uuid\",\n \"PercentRead\": 55.0,\n \"EntitlementId\": \"entitlement-id\",\n \"RemainingTimeMinutes\": 120,\n \"FirstReadTime\": \"2026-01-25T10:00:00Z\",\n \"LastModified\": \"2026-01-30T20:00:00Z\"\n }\n ],\n \"BookmarkSync\": [\n {\n \"ContentId\": \"book-uuid\",\n \"BookmarkText\": \"Important quote\",\n \"BookmarkType\": \"annotation\",\n \"BookmarkTitle\": \"Chapter 4 - The Truth\"\n },\n {\n \"ContentId\": \"book-uuid\",\n \"BookmarkText\": \"Another quote\",\n \"BookmarkType\": \"annotation\",\n \"BookmarkTitle\": \"Chapter 5\"\n },\n {\n \"ContentId\": \"book-uuid\",\n \"BookmarkText\": \"Note to myself\",\n \"BookmarkType\": \"note\",\n \"BookmarkTitle\": \"Personal note\"\n }\n ]\n}"
|
||||
docs: "## Sync with Multiple Annotations\n\nSynchronizes reading progress with multiple highlights and notes.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/kobo/markup\n\n**Authentication:** Bearer token\n\n**Headers:**\n- `Authorization`: Bearer {{kobo_device_token}}\n- `x-kobo-device`: Device info (Model: \"Kobo Libra\")\n\n**Request Body:**\n- `ReadingSync` (array): Single book progress\n- `BookmarkSync` (array): Multiple annotations\n - Can include highlights (annotation type)\n - Can include notes (note type)\n - Each has: ContentId, BookmarkText, BookmarkType, BookmarkTitle\n\n**Response:**\n- `progress_synced` (boolean): Progress update status\n- `annotations_synced` (integer): Number of annotations synced\n- `highlights_count` (integer): Highlights synced\n- `notes_count` (integer): Notes synced\n- `conflicts` (array): Any annotation conflicts resolved\n- `timestamp` (string): Sync completion time\n\n**Status Codes:**\n- 200: Successful sync\n- 401: Unauthorized\n- 400: Invalid\
|
||||
\ annotation data\n\n**Kobo Annotation Types:**\n- **Highlights:** Selected text passages\n - 5 preset colors available\n - Can have chapter titles\n - Exportable to PDF/Mobile\n- **Notes:** Personal annotations\n - Free-form text\n - Can be attached to highlights\n - Separate from highlights\n- **Bookmarks:** Location markers\n - Chapter positions\n - Quick navigation\n\n**Sync Behavior:**\n- Duplicates detected by content matching\n- Most recent edit wins conflicts\n- Annotations linked to book content\n- Chapter references preserved\n- Order maintained from device\n\n**Kobo Notebook Export:**\n- All annotations appear in Kobo \"Notebook\"\n- Can be exported to PDF\n- Can be exported to Mobile (text)\n- Organized by book\n- Shows highlight context\n\n**Use Cases:**\n- Study and research\n- Book club discussion prep\n- Content review\n- Sharing insights\n- Personal learning archive"
|
||||
@@ -4,42 +4,12 @@ info:
|
||||
seq: 3
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/v1/kobo/bookmark'
|
||||
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/bookmark'
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"BookmarkSync\": [\n {\n \"BookmarkId\": \"bookmark_2\"\
|
||||
,\n \"ContentId\": \"kobo_xyz789\",\n \"BookmarkText\": \"Important\
|
||||
\ note\",\n \"BookmarkType\": \"bookmark\",\n \"DateCreated\"\
|
||||
: \"2026-01-31T12:00:00Z\""
|
||||
data: "{\n \"BookmarkSync\": [\n {\n \"BookmarkId\": \"bookmark_2\",\n \"ContentId\": \"kobo_xyz789\",\n \"BookmarkText\": \"Important note\",\n \"BookmarkType\": \"bookmark\",\n \"DateCreated\": \"2026-01-31T12:00:00Z\""
|
||||
headers:
|
||||
- key: Authorization
|
||||
value: Bearer {{device_token
|
||||
|
||||
docs: |-
|
||||
## Kobo Bookmark Sync
|
||||
|
||||
Synchronizes bookmarks from a Kobo device to the Bookhoard server.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/v1/kobo/bookmark
|
||||
|
||||
**Authentication:** Bearer token (device token)
|
||||
|
||||
**Request Body:**
|
||||
- `BookmarkSync` (array): Array of bookmark objects
|
||||
- `BookmarkId` (string): Unique bookmark ID
|
||||
- `ContentId` (string): Book/content ID
|
||||
- `BookmarkText` (string): Bookmark text or note
|
||||
- `BookmarkType` (string): Type (bookmark, highlight, note)
|
||||
- `DateCreated` (string): ISO 8601 timestamp
|
||||
|
||||
**Response:**
|
||||
- `Status` (string): Sync status (Success, Partial)
|
||||
- `BookmarksSynced` (number): Number of bookmarks synced
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 401: Unauthorized
|
||||
- 500: Internal server error
|
||||
docs: "## Kobo Bookmark Sync\n\n Synchronizes bookmarks from a Kobo device to the Bookhoard server.\n\n **Method:** POST\n\n **Endpoint:** /api/v1/kobo/bookmark\n\n **Authentication:** Bearer token (device token)\n\n **Request Body:**\n - `BookmarkSync` (array): Array of bookmark objects\n - `BookmarkId` (string): Unique bookmark ID\n - `ContentId` (string): Book/content ID\n - `BookmarkText` (string): Bookmark text or note\n - `BookmarkType` (string): Type (bookmark, highlight, note)\n - `DateCreated` (string): ISO 8601 timestamp\n\n **Response:**\n - `Status` (string): Sync status (Success, Partial)\n - `BookmarksSynced` (number): Number of bookmarks synced\n\n **Status Codes:**\n - 200: Success\n - 401: Unauthorized\n - 500: Internal server error"
|
||||
@@ -4,7 +4,7 @@ info:
|
||||
seq: 4
|
||||
http:
|
||||
method: GET
|
||||
url: '{{base_url}}/sync/kobo/{{kobo_device_token}}/v1/initialization'
|
||||
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/v1/initialization'
|
||||
auth: none
|
||||
body:
|
||||
type: none
|
||||
|
||||
@@ -4,7 +4,7 @@ info:
|
||||
seq: 3
|
||||
http:
|
||||
method: GET
|
||||
url: '{{base_url}}/sync/kobo/{{kobo_device_token}}/library'
|
||||
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/v1/initialization'
|
||||
auth: none
|
||||
body:
|
||||
type: none
|
||||
|
||||
@@ -4,7 +4,7 @@ info:
|
||||
seq: 4
|
||||
http:
|
||||
method: GET
|
||||
url: '{{base_url}}/api/sync/unlinked-books'
|
||||
url: '{{base_url}}/api/devices/{{device_id}}/sync/unlinked-books'
|
||||
auth: inherit
|
||||
body:
|
||||
type: none
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
info:
|
||||
name: Kobo Initialization
|
||||
type: http
|
||||
seq: 1
|
||||
http:
|
||||
method: GET
|
||||
url: '{{base_url}}/api/v1/kobo/initialization'
|
||||
auth: inherit
|
||||
body:
|
||||
type: none
|
||||
headers:
|
||||
- key: Authorization
|
||||
value: Bearer {{device_token
|
||||
|
||||
docs: |-
|
||||
## Kobo Initialization
|
||||
|
||||
Initializes Kobo device sync, returning device resources and account information.
|
||||
|
||||
**Method:** GET
|
||||
|
||||
**Endpoint:** /api/v1/kobo/initialization
|
||||
|
||||
**Authentication:** Bearer token (device token)
|
||||
|
||||
**Response:**
|
||||
- `ContentId` (string): Device content ID
|
||||
- `Categories` (array): Available categories/collections
|
||||
- `BookhoardUUID` (string): Bookhoard instance UUID
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 401: Unauthorized
|
||||
- 500: Internal server error
|
||||
@@ -4,40 +4,12 @@ info:
|
||||
seq: 5
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/link-book'
|
||||
url: '{{base_url}}/api/devices/{{device_id}}/sync/link-book'
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"unlinked_book_id\": \"{{unlinked_book_id"
|
||||
data: "{\n \"unlinked_book_id\": \"{{unlinked_book_id"
|
||||
headers:
|
||||
- key: Authorization
|
||||
value: Bearer {{user_token
|
||||
|
||||
docs: |-
|
||||
## Link Unlinked Book - Manual Resolution
|
||||
|
||||
Manually links an unlinked book to a media item in the library.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/link-book
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Request Body:**
|
||||
- `unlinked_book_id` (string): Unlinked book UUID
|
||||
- `media_item_id` (string): Media item UUID to link to
|
||||
- `confidence_score` (number): Match confidence (0-1, 1.0 for manual)
|
||||
|
||||
**Response:**
|
||||
- `status` (string): Link status (linked)
|
||||
- `unlinked_book_id` (string): Unlinked book UUID
|
||||
- `media_item_id` (string): Media item UUID
|
||||
- `message` (string): Success message
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success - book linked
|
||||
- 400: Invalid request
|
||||
- 401: Unauthorized
|
||||
- 404: Book or media item not found
|
||||
- 500: Internal server error
|
||||
docs: "## Link Unlinked Book - Manual Resolution\n\n Manually links an unlinked book to a media item in the library.\n\n **Method:** POST\n\n **Endpoint:** /api/sync/link-book\n\n **Authentication:** Bearer token\n\n **Request Body:**\n - `unlinked_book_id` (string): Unlinked book UUID\n - `media_item_id` (string): Media item UUID to link to\n - `confidence_score` (number): Match confidence (0-1, 1.0 for manual)\n\n **Response:**\n - `status` (string): Link status (linked)\n - `unlinked_book_id` (string): Unlinked book UUID\n - `media_item_id` (string): Media item UUID\n - `message` (string): Success message\n\n **Status Codes:**\n - 200: Success - book linked\n - 400: Invalid request\n - 401: Unauthorized\n - 404: Book or media item not found\n - 500: Internal server error"
|
||||
@@ -1,52 +0,0 @@
|
||||
info:
|
||||
name: Kobo Markup Sync
|
||||
type: http
|
||||
seq: 2
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/v1/kobo/markup'
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"ReadingSync\": [\n {\n \"ContentId\": \"kobo_abc123def456\"\
|
||||
,\n \"PercentRead\": 60.0,\n \"RemainingTimeMin\": 120,\n \
|
||||
\ \"ReadingEvent\": \"BookRead\",\n \"LastModified\": \"2026-01-31T12:00:00Z\""
|
||||
headers:
|
||||
- key: Authorization
|
||||
value: Bearer {{device_token
|
||||
|
||||
docs: |-
|
||||
## Kobo Markup Sync
|
||||
|
||||
Synchronizes reading progress and markup (highlights, bookmarks) from a Kobo device.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/v1/kobo/markup
|
||||
|
||||
**Authentication:** Bearer token (device token)
|
||||
|
||||
**Request Body:**
|
||||
- `ReadingSync` (array, optional): Reading progress data
|
||||
- `ContentId` (string): Book/content ID
|
||||
- `PercentRead` (number): Percentage read (0-100)
|
||||
- `RemainingTimeMin` (number): Remaining time in minutes
|
||||
- `ReadingEvent` (string): Event type (BookRead, etc.)
|
||||
- `LastModified` (string): ISO 8601 timestamp
|
||||
- `BookmarkSync` (array, optional): Bookmark/highlight data
|
||||
- `BookmarkId` (string): Unique bookmark ID
|
||||
- `ContentId` (string): Book/content ID
|
||||
- `BookmarkText` (string): Highlighted/bookmarked text
|
||||
- `BookmarkType` (string): Type (annotation, bookmark)
|
||||
- `DateCreated` (string): ISO 8601 timestamp
|
||||
- `Metadata` (boolean): Whether to include metadata
|
||||
|
||||
**Response:**
|
||||
- `Status` (string): Sync status (Success, Partial)
|
||||
- `MarkupsSynced` (number): Number of markups synced
|
||||
- `BookmarksSynced` (number): Number of bookmarks synced
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 401: Unauthorized
|
||||
- 500: Internal server error
|
||||
@@ -4,22 +4,12 @@ info:
|
||||
seq: 2
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/sync/kobo/{{kobo_device_token}}/bookmark'
|
||||
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/bookmark'
|
||||
auth: none
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"ContentId\": \"book-uuid\",\n \"BookmarkText\": \"Highlighted\
|
||||
\ text\",\n \"BookmarkType\": \"annotation\",\n \"BookmarkTitle\": \"\
|
||||
Chapter 3\""
|
||||
data: "{\n \"ContentId\": \"book-uuid\",\n \"BookmarkText\": \"Highlighted text\",\n \"BookmarkType\": \"annotation\",\n \"BookmarkTitle\": \"Chapter 3\""
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
|
||||
docs: |-
|
||||
## Sync Bookmark - URL Path Token
|
||||
|
||||
Synchronizes bookmarks and annotations from Kobo device using token in URL path.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /sync/kobo/{kobo_device_token
|
||||
docs: "## Sync Bookmark - URL Path Token\n\n Synchronizes bookmarks and annotations from Kobo device using token in URL path.\n\n **Method:** POST\n\n **Endpoint:** /sync/kobo/{kobo_device_token"
|
||||
@@ -4,23 +4,12 @@ info:
|
||||
seq: 1
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/sync/kobo/{{kobo_device_token}}/markup'
|
||||
url: '{{base_url}}/api/sync/kobo/{{kobo_device_token}}/markup'
|
||||
auth: none
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"ReadingSync\": [\n {\n \"ContentId\": \"book-uuid\"\
|
||||
,\n \"PercentRead\": 45.6,\n \"EntitlementId\": \"entitlement-id\"\
|
||||
,\n \"RemainingTimeMinutes\": 120,\n \"FirstReadTime\": \"2026-01-25T10:00:00Z\"\
|
||||
,\n \"LastModified\": \"2026-01-30T20:00:00Z\""
|
||||
data: "{\n \"ReadingSync\": [\n {\n \"ContentId\": \"book-uuid\",\n \"PercentRead\": 45.6,\n \"EntitlementId\": \"entitlement-id\",\n \"RemainingTimeMinutes\": 120,\n \"FirstReadTime\": \"2026-01-25T10:00:00Z\",\n \"LastModified\": \"2026-01-30T20:00:00Z\""
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
|
||||
docs: |-
|
||||
## Sync Reading Progress - URL Path Token
|
||||
|
||||
Synchronizes reading progress from Kobo device using token in URL path.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /sync/kobo/{kobo_device_token
|
||||
docs: "## Sync Reading Progress - URL Path Token\n\n Synchronizes reading progress from Kobo device using token in URL path.\n\n **Method:** POST\n\n **Endpoint:** /sync/kobo/{kobo_device_token"
|
||||
@@ -1,92 +1,14 @@
|
||||
info:
|
||||
name: Get Book Metadata
|
||||
type: http
|
||||
seq: 8
|
||||
|
||||
docs: "## Get KOReader Book Metadata\n\nRetrieves metadata for a specific book from the server.\n\n**Method:** GET\n\n**Endpoint:** /api/sync/koreader/metadata/:book_uuid\n\n**Authentication:** Bearer token\n\n**Path Parameters:**\n- `book_uuid` (string): SHA-256 based book identifier\n\n**Response:**\n- `uuid` (string): Book UUID (SHA-256)\n- `title` (string): Book title\n- `authors` (array): Author names\n- `series` (string, optional): Series name\n- `series_index` (number, optional): Position in series\n- `publisher` (string, optional): Publisher name\n- `publication_date` (string, optional): Release date\n- `language` (string, optional): ISO 639-1 language code\n- `description` (string, optional): Book description\n- `cover_url` (string, optional): Cover image URL\n- `cover_thumbnail_url` (string, optional): Thumbnail URL\n- `identifiers` (object): Various identifiers\n - `isbn` (string, optional): ISBN-13\n - `asin` (string, optional): Amazon ASIN\n - `goodreads` (string, optional):\
|
||||
\ Goodreads ID\n - `google_books` (string, optional): Google Books ID\n- `metadata_sources` (array): Sources metadata was pulled from\n- `last_synced` (string): Last metadata sync timestamp\n- `file_metadata` (object):\n - `file_size` (integer): File size in bytes\n - `format` (string): File format (epub, pdf, mobi, etc.)\n - `pages` (integer, optional): Page count\n - `word_count` (integer, optional): Estimated words\n\n**Status Codes:**\n- 200: Success\n- 401: Unauthorized\n- 404: Book not found\n\n**Metadata Purpose:**\n- Enrich book information on device\n- Improve book organization\n- Enable better search\n- Support series sorting\n- Provide cover images\n- Link to external sources\n\n**KOReader Usage:**\n- Display in book info dialog\n- Used for library sorting\n- Shown in file browser\n- Series grouping\n- Cover display\n- Search optimization\n\n**SHA-256 Book ID:**\n- Primary identifier in KOReader\n- Universal across devices\n- Format-independent\n- Generated from file content\n\
|
||||
- Survives metadata changes\n\n**Metadata Sources:**\n- Google Books API\n- Open Library\n- Goodreads API\n- ISBN database lookup\n- Publisher metadata\n- User-provided metadata\n\n**Use Cases:**\n- Initial book import\n- Metadata refresh\n- Cover image download\n- Series organization\n- Duplicate detection\n- Library management"
|
||||
http:
|
||||
headers: []
|
||||
method: GET
|
||||
url: '{{base_url}}/api/sync/koreader/metadata/{{book_uuid}}'
|
||||
auth: inherit
|
||||
|
||||
docs: |-
|
||||
## Get KOReader Book Metadata
|
||||
|
||||
Retrieves metadata for a specific book from the server.
|
||||
|
||||
**Method:** GET
|
||||
|
||||
**Endpoint:** /api/sync/koreader/metadata/:book_uuid
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Path Parameters:**
|
||||
- `book_uuid` (string): SHA-256 based book identifier
|
||||
|
||||
**Response:**
|
||||
- `uuid` (string): Book UUID (SHA-256)
|
||||
- `title` (string): Book title
|
||||
- `authors` (array): Author names
|
||||
- `series` (string, optional): Series name
|
||||
- `series_index` (number, optional): Position in series
|
||||
- `publisher` (string, optional): Publisher name
|
||||
- `publication_date` (string, optional): Release date
|
||||
- `language` (string, optional): ISO 639-1 language code
|
||||
- `description` (string, optional): Book description
|
||||
- `cover_url` (string, optional): Cover image URL
|
||||
- `cover_thumbnail_url` (string, optional): Thumbnail URL
|
||||
- `identifiers` (object): Various identifiers
|
||||
- `isbn` (string, optional): ISBN-13
|
||||
- `asin` (string, optional): Amazon ASIN
|
||||
- `goodreads` (string, optional): Goodreads ID
|
||||
- `google_books` (string, optional): Google Books ID
|
||||
- `metadata_sources` (array): Sources metadata was pulled from
|
||||
- `last_synced` (string): Last metadata sync timestamp
|
||||
- `file_metadata` (object):
|
||||
- `file_size` (integer): File size in bytes
|
||||
- `format` (string): File format (epub, pdf, mobi, etc.)
|
||||
- `pages` (integer, optional): Page count
|
||||
- `word_count` (integer, optional): Estimated words
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 401: Unauthorized
|
||||
- 404: Book not found
|
||||
|
||||
**Metadata Purpose:**
|
||||
- Enrich book information on device
|
||||
- Improve book organization
|
||||
- Enable better search
|
||||
- Support series sorting
|
||||
- Provide cover images
|
||||
- Link to external sources
|
||||
|
||||
**KOReader Usage:**
|
||||
- Display in book info dialog
|
||||
- Used for library sorting
|
||||
- Shown in file browser
|
||||
- Series grouping
|
||||
- Cover display
|
||||
- Search optimization
|
||||
|
||||
**SHA-256 Book ID:**
|
||||
- Primary identifier in KOReader
|
||||
- Universal across devices
|
||||
- Format-independent
|
||||
- Generated from file content
|
||||
- Survives metadata changes
|
||||
|
||||
**Metadata Sources:**
|
||||
- Google Books API
|
||||
- Open Library
|
||||
- Goodreads API
|
||||
- ISBN database lookup
|
||||
- Publisher metadata
|
||||
- User-provided metadata
|
||||
|
||||
**Use Cases:**
|
||||
- Initial book import
|
||||
- Metadata refresh
|
||||
- Cover image download
|
||||
- Series organization
|
||||
- Duplicate detection
|
||||
- Library management
|
||||
auth:
|
||||
type: bearer
|
||||
token: '{{koreader_device_token}}'
|
||||
info:
|
||||
name: Get Book Metadata
|
||||
seq: 8
|
||||
type: http
|
||||
@@ -1,34 +1,14 @@
|
||||
info:
|
||||
name: KOReader Get Library
|
||||
type: http
|
||||
seq: 3
|
||||
docs: "## KOReader Get Library\n\n Retrieves the user's library for KOReader sync operations.\n\n **Method:** GET\n\n **Endpoint:** /api/sync/koreader/library\n\n **Authentication:** Bearer token (device token)\n\n **Response:**\n - `library_sync` (object): Library sync data\n - `total_books` (number): Total number of books\n - `books` (array): Array of book objects\n\n **Status Codes:**\n - 200: Success\n - 401: Unauthorized\n - 500: Internal server error"
|
||||
http:
|
||||
method: GET
|
||||
url: '{{base_url}}/api/sync/koreader/library'
|
||||
auth: inherit
|
||||
body:
|
||||
type: none
|
||||
headers:
|
||||
- key: Authorization
|
||||
value: Bearer {{device_token
|
||||
|
||||
docs: |-
|
||||
## KOReader Get Library
|
||||
|
||||
Retrieves the user's library for KOReader sync operations.
|
||||
|
||||
**Method:** GET
|
||||
|
||||
**Endpoint:** /api/sync/koreader/library
|
||||
|
||||
**Authentication:** Bearer token (device token)
|
||||
|
||||
**Response:**
|
||||
- `library_sync` (object): Library sync data
|
||||
- `total_books` (number): Total number of books
|
||||
- `books` (array): Array of book objects
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 401: Unauthorized
|
||||
- 500: Internal server error
|
||||
headers: []
|
||||
method: GET
|
||||
url: '{{base_url}}/api/sync/koreader/library'
|
||||
auth:
|
||||
type: bearer
|
||||
token: '{{koreader_device_token}}'
|
||||
info:
|
||||
name: KOReader Get Library
|
||||
seq: 3
|
||||
type: http
|
||||
@@ -1,103 +1,15 @@
|
||||
info:
|
||||
name: Get User Library for KOReader
|
||||
type: http
|
||||
seq: 9
|
||||
|
||||
docs: "## Get KOReader User Library\n\nRetrieves the user's book library for KOReader device sync.\n\n**Method:** GET\n\n**Endpoint:** /api/sync/koreader/library\n\n**Authentication:** Bearer token (koreader_device_token)\n\n**Query Parameters:**\nNone (returns entire library)\n\n**Response:**\n- `books` (array): Library items\n - `uuid` (string): SHA-256 based book identifier\n - `title` (string): Book title\n - `authors` (array): Author names\n - `series` (string, optional): Series name\n - `series_index` (number, optional): Series position\n - `publisher` (string, optional): Publisher\n - `publication_date` (string, optional): Release date\n - `language` (string, optional): Language code\n - `description` (string, optional): Description\n - `cover_url` (string, optional): Cover image URL\n - `cover_thumbnail_url` (string, optional): Thumbnail URL\n - `file_metadata` (object):\n - `format` (string): File format\n - `file_size` (integer): Size in bytes\n - `pages` (integer,\
|
||||
\ optional): Page count\n - `progress` (object, optional): Reading progress\n - `percentage` (number): Progress 0-100\n - `last_read` (string): Last read timestamp\n - `epubcfi` (string): Current position\n - `annotations_count` (object, optional): Annotation stats\n - `highlights` (integer): Highlight count\n - `notes` (integer): Note count\n - `bookmarks` (integer): Bookmark count\n- `library_info` (object):\n - `total_books` (integer): Total book count\n - `last_sync` (string): Last library sync timestamp\n - `has_updates` (boolean): Updates available\n- `user_info` (object):\n - `user_id` (string): User identifier\n - `email` (string): Email (masked)\n - `libraries` (array): Available library IDs\n\n**Status Codes:**\n- 200: Success\n- 401: Unauthorized\n- 403: Device not approved\n\n**Library Purpose for KOReader:**\n- Discover books available for download\n- Browse catalog on device\n- Sync reading progress across books\n- Download covers/metadata\n- Series-based\
|
||||
\ organization\n- Cloud library access\n\n**KOReader Device Features:**\n- **OPDS catalog**: Native OPDS client\n- **File browser**: See server books\n- **Cloud download**: Download books on-demand\n- **Metadata sync**: Automatic metadata fetching\n- **Cover images**: Display in library view\n- **Progress sync**: See progress across all books\n- **Search**: Search library by title/author\n\n**KOReader-Specific Features:**\n- SHA-256 based book IDs\n- Multi-format support (EPUB, FB2, PDF, DJVU, MOBI, etc.)\n- Series sorting and grouping\n- Language filtering\n- Cover image caching\n- Metadata for file browser enhancement\n- Integration with KOReader's OPDS client\n\n**Performance:**\n- Typical response: 100-500KB for 100 books\n- Processing time: 300ms-1s\n- Cache duration: 5 minutes\n- Pagination support for libraries >500 books\n\n**Use Cases:**\n- Initial device setup\n- Library browsing on device\n- Book download\n- Metadata refresh\n- Cover image sync\n- Progress overview\n- Series-based\
|
||||
\ reading"
|
||||
http:
|
||||
headers: []
|
||||
method: GET
|
||||
url: '{{base_url}}/api/sync/koreader/library'
|
||||
auth: inherit
|
||||
|
||||
docs: |-
|
||||
## Get KOReader User Library
|
||||
|
||||
Retrieves the user's book library for KOReader device sync.
|
||||
|
||||
**Method:** GET
|
||||
|
||||
**Endpoint:** /api/sync/koreader/library
|
||||
|
||||
**Authentication:** Bearer token (koreader_device_token)
|
||||
|
||||
**Query Parameters:**
|
||||
None (returns entire library)
|
||||
|
||||
**Response:**
|
||||
- `books` (array): Library items
|
||||
- `uuid` (string): SHA-256 based book identifier
|
||||
- `title` (string): Book title
|
||||
- `authors` (array): Author names
|
||||
- `series` (string, optional): Series name
|
||||
- `series_index` (number, optional): Series position
|
||||
- `publisher` (string, optional): Publisher
|
||||
- `publication_date` (string, optional): Release date
|
||||
- `language` (string, optional): Language code
|
||||
- `description` (string, optional): Description
|
||||
- `cover_url` (string, optional): Cover image URL
|
||||
- `cover_thumbnail_url` (string, optional): Thumbnail URL
|
||||
- `file_metadata` (object):
|
||||
- `format` (string): File format
|
||||
- `file_size` (integer): Size in bytes
|
||||
- `pages` (integer, optional): Page count
|
||||
- `progress` (object, optional): Reading progress
|
||||
- `percentage` (number): Progress 0-100
|
||||
- `last_read` (string): Last read timestamp
|
||||
- `epubcfi` (string): Current position
|
||||
- `annotations_count` (object, optional): Annotation stats
|
||||
- `highlights` (integer): Highlight count
|
||||
- `notes` (integer): Note count
|
||||
- `bookmarks` (integer): Bookmark count
|
||||
- `library_info` (object):
|
||||
- `total_books` (integer): Total book count
|
||||
- `last_sync` (string): Last library sync timestamp
|
||||
- `has_updates` (boolean): Updates available
|
||||
- `user_info` (object):
|
||||
- `user_id` (string): User identifier
|
||||
- `email` (string): Email (masked)
|
||||
- `libraries` (array): Available library IDs
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 401: Unauthorized
|
||||
- 403: Device not approved
|
||||
|
||||
**Library Purpose for KOReader:**
|
||||
- Discover books available for download
|
||||
- Browse catalog on device
|
||||
- Sync reading progress across books
|
||||
- Download covers/metadata
|
||||
- Series-based organization
|
||||
- Cloud library access
|
||||
|
||||
**KOReader Device Features:**
|
||||
- **OPDS catalog**: Native OPDS client
|
||||
- **File browser**: See server books
|
||||
- **Cloud download**: Download books on-demand
|
||||
- **Metadata sync**: Automatic metadata fetching
|
||||
- **Cover images**: Display in library view
|
||||
- **Progress sync**: See progress across all books
|
||||
- **Search**: Search library by title/author
|
||||
|
||||
**KOReader-Specific Features:**
|
||||
- SHA-256 based book IDs
|
||||
- Multi-format support (EPUB, FB2, PDF, DJVU, MOBI, etc.)
|
||||
- Series sorting and grouping
|
||||
- Language filtering
|
||||
- Cover image caching
|
||||
- Metadata for file browser enhancement
|
||||
- Integration with KOReader's OPDS client
|
||||
|
||||
**Performance:**
|
||||
- Typical response: 100-500KB for 100 books
|
||||
- Processing time: 300ms-1s
|
||||
- Cache duration: 5 minutes
|
||||
- Pagination support for libraries >500 books
|
||||
|
||||
**Use Cases:**
|
||||
- Initial device setup
|
||||
- Library browsing on device
|
||||
- Book download
|
||||
- Metadata refresh
|
||||
- Cover image sync
|
||||
- Progress overview
|
||||
- Series-based reading
|
||||
auth:
|
||||
type: bearer
|
||||
token: '{{koreader_device_token}}'
|
||||
info:
|
||||
name: Get User Library for KOReader
|
||||
seq: 9
|
||||
type: http
|
||||
@@ -1,22 +0,0 @@
|
||||
info:
|
||||
name: Bookhoard KOReader Sync API
|
||||
type: collection
|
||||
seq: 1
|
||||
http:
|
||||
method: POST
|
||||
url: '"http://localhost:8765/api"'
|
||||
|
||||
docs: |-
|
||||
## Bookhoard KOReader Sync API
|
||||
|
||||
Collection of endpoints specifically for KOReader e-reader device synchronization.
|
||||
|
||||
**Base URL:** http://localhost:8765/api
|
||||
|
||||
**Authentication:** Device token or Bearer token required
|
||||
|
||||
**Endpoints:**
|
||||
- KOReader-specific sync protocols
|
||||
- Metadata synchronization
|
||||
- Reading progress sync
|
||||
- Highlights and notes sync
|
||||
@@ -0,0 +1,7 @@
|
||||
info:
|
||||
name: Bookhoard KOReader Sync API
|
||||
type: folder
|
||||
seq: 1
|
||||
request:
|
||||
auth: inherit
|
||||
docs: "## Bookhoard KOReader Sync API\n\n Collection of endpoints specifically for KOReader e-reader device synchronization.\n\n **Base URL:** http://localhost:8765/api\n\n **Authentication:** Device token or Bearer token required\n\n **Endpoints:**\n - KOReader-specific sync protocols\n - Metadata synchronization\n - Reading progress sync\n - Highlights and notes sync"
|
||||
@@ -1,123 +1,19 @@
|
||||
info:
|
||||
name: Checkpoint Sync
|
||||
type: http
|
||||
seq: 11
|
||||
|
||||
docs: "## Checkpoint Sync\n\nIncremental sync using checkpoint-based change tracking.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/koreader/progress\n\n**Authentication:** Bearer token\n\n**Request Body:**\n- `sync_mode` (string): Must be `checkpoint`\n- `checkpoint_id` (string): Unique checkpoint identifier\n- `since_timestamp` (string): ISO 8601 timestamp for incremental sync\n- `books` (array): Book progress items\n - `uuid` (string): Book UUID\n - `percentage` (number): Progress 0.0-1.0\n - `chapter` (integer): Current chapter\n - `epubcfi` (string, optional): Current position\n - `modified_since` (boolean, optional): Whether modified since checkpoint\n\n**Response:**\n- `checkpoint_id` (string): Server checkpoint ID\n- `checkpoint_timestamp` (string): Checkpoint creation time\n- `processed` (integer): Books processed\n- `changes_only` (boolean): Whether only changed items synced\n- `next_checkpoint_id` (string): ID for next checkpoint sync\n- `results` (array): Per-book results\n\
|
||||
\n**Status Codes:**\n- 200: Checkpoint sync completed\n- 401: Unauthorized\n- 400: Invalid checkpoint or timestamp\n\n**Checkpoint Sync Benefits:**\n- **Incremental**: Only sync changed items\n- **Efficient**: Smaller payloads\n- **Fast**: Reduced processing time\n- **Reliable**: Checkpoint-based tracking\n- **Resumable**: Can continue from last checkpoint\n\n**Checkpoint Mechanism:**\n- Server tracks changes since checkpoint\n- Client provides checkpoint ID or timestamp\n- Only modified books returned/processed\n- Checkpoint ID advances on each sync\n- Supports large libraries efficiently\n\n**Use Cases:**\n- Large libraries (100+ books)\n- Intermittent connectivity\n- Bandwidth optimization\n- Battery conservation\n- Background sync\n- Periodic sync (every 5-15 minutes)\n\n**Checkpoint Lifecycle:**\n1. Initial sync: No checkpoint (full sync)\n2. Server returns checkpoint_id\n3. Next sync: Client sends checkpoint_id\n4. Server processes only changes\n5. New checkpoint_id returned\n6.\
|
||||
\ Repeat from step 3\n\n**Sync Optimization:**\n- Only books with progress changes\n- Skips unmodified books\n- Delta transfer\n- Compression for large payloads\n- Batch processing\n\n**Failure Handling:**\n- Checkpoint ID preserved on failure\n- Retry with same checkpoint\n- Full sync if checkpoint expired\n- Checkpoint validity: 24 hours\n- Auto-fallback to full sync\n\n**Performance:**\n- Small changes (1-10 books): 100-300ms\n- Medium changes (10-50 books): 300ms-1s\n- Large changes (50-100 books): 1-3s\n- Typical: 5-10x faster than full sync\n\n**When to Use:**\n- Default sync mode for most users\n- Periodic background sync\n- Large library management\n- Mobile/network-constrained environments\n- Battery-powered devices\n\n**Configuration:**\n- Checkpoint expiration: 24 hours\n- Max history: 100 checkpoints\n- Auto-cleanup of old checkpoints\n- Configurable sync interval"
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/progress'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
sync_mode: checkpoint
|
||||
checkpoint_id: checkpoint-uuid
|
||||
since_timestamp: '2026-01-30T19:00:00Z'
|
||||
books:
|
||||
- uuid: book-uuid-1
|
||||
percentage: 0.45
|
||||
chapter: 3
|
||||
- uuid: book-uuid-2
|
||||
percentage: 0.75
|
||||
chapter: 8
|
||||
|
||||
docs: |-
|
||||
## Checkpoint Sync
|
||||
|
||||
Incremental sync using checkpoint-based change tracking.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/koreader/progress
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Request Body:**
|
||||
- `sync_mode` (string): Must be `checkpoint`
|
||||
- `checkpoint_id` (string): Unique checkpoint identifier
|
||||
- `since_timestamp` (string): ISO 8601 timestamp for incremental sync
|
||||
- `books` (array): Book progress items
|
||||
- `uuid` (string): Book UUID
|
||||
- `percentage` (number): Progress 0.0-1.0
|
||||
- `chapter` (integer): Current chapter
|
||||
- `epubcfi` (string, optional): Current position
|
||||
- `modified_since` (boolean, optional): Whether modified since checkpoint
|
||||
|
||||
**Response:**
|
||||
- `checkpoint_id` (string): Server checkpoint ID
|
||||
- `checkpoint_timestamp` (string): Checkpoint creation time
|
||||
- `processed` (integer): Books processed
|
||||
- `changes_only` (boolean): Whether only changed items synced
|
||||
- `next_checkpoint_id` (string): ID for next checkpoint sync
|
||||
- `results` (array): Per-book results
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Checkpoint sync completed
|
||||
- 401: Unauthorized
|
||||
- 400: Invalid checkpoint or timestamp
|
||||
|
||||
**Checkpoint Sync Benefits:**
|
||||
- **Incremental**: Only sync changed items
|
||||
- **Efficient**: Smaller payloads
|
||||
- **Fast**: Reduced processing time
|
||||
- **Reliable**: Checkpoint-based tracking
|
||||
- **Resumable**: Can continue from last checkpoint
|
||||
|
||||
**Checkpoint Mechanism:**
|
||||
- Server tracks changes since checkpoint
|
||||
- Client provides checkpoint ID or timestamp
|
||||
- Only modified books returned/processed
|
||||
- Checkpoint ID advances on each sync
|
||||
- Supports large libraries efficiently
|
||||
|
||||
**Use Cases:**
|
||||
- Large libraries (100+ books)
|
||||
- Intermittent connectivity
|
||||
- Bandwidth optimization
|
||||
- Battery conservation
|
||||
- Background sync
|
||||
- Periodic sync (every 5-15 minutes)
|
||||
|
||||
**Checkpoint Lifecycle:**
|
||||
1. Initial sync: No checkpoint (full sync)
|
||||
2. Server returns checkpoint_id
|
||||
3. Next sync: Client sends checkpoint_id
|
||||
4. Server processes only changes
|
||||
5. New checkpoint_id returned
|
||||
6. Repeat from step 3
|
||||
|
||||
**Sync Optimization:**
|
||||
- Only books with progress changes
|
||||
- Skips unmodified books
|
||||
- Delta transfer
|
||||
- Compression for large payloads
|
||||
- Batch processing
|
||||
|
||||
**Failure Handling:**
|
||||
- Checkpoint ID preserved on failure
|
||||
- Retry with same checkpoint
|
||||
- Full sync if checkpoint expired
|
||||
- Checkpoint validity: 24 hours
|
||||
- Auto-fallback to full sync
|
||||
|
||||
**Performance:**
|
||||
- Small changes (1-10 books): 100-300ms
|
||||
- Medium changes (10-50 books): 300ms-1s
|
||||
- Large changes (50-100 books): 1-3s
|
||||
- Typical: 5-10x faster than full sync
|
||||
|
||||
**When to Use:**
|
||||
- Default sync mode for most users
|
||||
- Periodic background sync
|
||||
- Large library management
|
||||
- Mobile/network-constrained environments
|
||||
- Battery-powered devices
|
||||
|
||||
**Configuration:**
|
||||
- Checkpoint expiration: 24 hours
|
||||
- Max history: 100 checkpoints
|
||||
- Auto-cleanup of old checkpoints
|
||||
- Configurable sync interval
|
||||
data: "{\n \"books\": [\n {\n \"chapter\": 3,\n \"percentage\": 0.45,\n \"uuid\": \"{{media_item_id}}\"\n },\n {\n \"chapter\": 8,\n \"percentage\": 0.75,\n \"uuid\": \"{{media_item_id}}\"\n }\n ],\n \"checkpoint_id\": \"checkpoint-uuid\",\n \"since_timestamp\": \"2026-01-30T19:00:00Z\",\n \"sync_mode\": \"checkpoint\"\n}"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/progress'
|
||||
auth:
|
||||
type: bearer
|
||||
token: '{{koreader_device_token}}'
|
||||
info:
|
||||
name: Checkpoint Sync
|
||||
seq: 11
|
||||
type: http
|
||||
@@ -1,105 +1,19 @@
|
||||
info:
|
||||
name: Immediate Sync - Page Turn
|
||||
type: http
|
||||
seq: 10
|
||||
|
||||
docs: "## Immediate Sync - Page Turn\n\nReal-time progress sync triggered immediately on page turn.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/koreader/progress\n\n**Authentication:** Bearer token\n\n**Request Body:**\n- `sync_mode` (string): Must be `immediate`\n- `books` (array): Current book progress\n - `uuid` (string): Book UUID\n - `percentage` (number): Precise progress (0.45678 = 45.678%)\n - `chapter` (integer): Current chapter\n - `timestamp` (string): ISO 8601 timestamp\n - `epubcfi` (string, optional): Current position\n - `page` (integer, optional): Current page\n\n**Response:**\n- `synced` (boolean): Immediate sync status\n- `timestamp` (string): Server timestamp\n- `next_sync_suggested` (string): Suggested next sync time\n\n**Status Codes:**\n- 200: Sync queued\n- 202: Accepted for processing\n- 401: Unauthorized\n- 429: Too many immediate sync requests (rate limited)\n\n**Immediate Sync Mode:**\n- **Purpose**: Real-time progress updates\n- **Trigger**: Every page\
|
||||
\ turn (configurable)\n- **Priority**: High priority processing\n- **Latency**: <100ms typical\n- **Best effort**: May be queued under load\n\n**Rate Limiting:**\n- Max 60 requests per minute per device\n- Throttled after limit reached\n- Suggests switching to periodic sync\n- Prevents server overload\n\n**Use Cases:**\n- Real-time multi-device reading\n- Live progress sharing\n- Instant position backup\n- Critical reading points\n- Test/profiling mode\n\n**Performance:**\n- Ultra-fast sync\n- Minimal payload\n- Optimized for speed\n- Async processing\n- No confirmation wait\n\n**Battery Considerations:**\n- More frequent network use\n- Higher battery consumption\n- WiFi recommended\n- Can reduce sync frequency in settings\n\n**Configuration:**\n- Can enable/disable per device\n- Adjustable frequency (every page, every N pages)\n- Automatic fallback to periodic sync on error\n- Respects device power-save mode\n\n**When to Use:**\n- Critical reading sessions\n- Multi-device concurrent reading\n\
|
||||
- Research and study\n- Testing sync functionality\n- When power source available\n\n**When NOT to Use:**\n- Battery conservation needed\n- Unstable network\n- Extended reading sessions\n- Background sync preferred"
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/progress'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
sync_mode: immediate
|
||||
books:
|
||||
- uuid: book-uuid
|
||||
percentage: 0.45678
|
||||
chapter: 3
|
||||
timestamp: '2026-01-30T20:00:00Z'
|
||||
|
||||
docs: |-
|
||||
## Immediate Sync - Page Turn
|
||||
|
||||
Real-time progress sync triggered immediately on page turn.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/koreader/progress
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Request Body:**
|
||||
- `sync_mode` (string): Must be `immediate`
|
||||
- `books` (array): Current book progress
|
||||
- `uuid` (string): Book UUID
|
||||
- `percentage` (number): Precise progress (0.45678 = 45.678%)
|
||||
- `chapter` (integer): Current chapter
|
||||
- `timestamp` (string): ISO 8601 timestamp
|
||||
- `epubcfi` (string, optional): Current position
|
||||
- `page` (integer, optional): Current page
|
||||
|
||||
**Response:**
|
||||
- `synced` (boolean): Immediate sync status
|
||||
- `timestamp` (string): Server timestamp
|
||||
- `next_sync_suggested` (string): Suggested next sync time
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Sync queued
|
||||
- 202: Accepted for processing
|
||||
- 401: Unauthorized
|
||||
- 429: Too many immediate sync requests (rate limited)
|
||||
|
||||
**Immediate Sync Mode:**
|
||||
- **Purpose**: Real-time progress updates
|
||||
- **Trigger**: Every page turn (configurable)
|
||||
- **Priority**: High priority processing
|
||||
- **Latency**: <100ms typical
|
||||
- **Best effort**: May be queued under load
|
||||
|
||||
**Rate Limiting:**
|
||||
- Max 60 requests per minute per device
|
||||
- Throttled after limit reached
|
||||
- Suggests switching to periodic sync
|
||||
- Prevents server overload
|
||||
|
||||
**Use Cases:**
|
||||
- Real-time multi-device reading
|
||||
- Live progress sharing
|
||||
- Instant position backup
|
||||
- Critical reading points
|
||||
- Test/profiling mode
|
||||
|
||||
**Performance:**
|
||||
- Ultra-fast sync
|
||||
- Minimal payload
|
||||
- Optimized for speed
|
||||
- Async processing
|
||||
- No confirmation wait
|
||||
|
||||
**Battery Considerations:**
|
||||
- More frequent network use
|
||||
- Higher battery consumption
|
||||
- WiFi recommended
|
||||
- Can reduce sync frequency in settings
|
||||
|
||||
**Configuration:**
|
||||
- Can enable/disable per device
|
||||
- Adjustable frequency (every page, every N pages)
|
||||
- Automatic fallback to periodic sync on error
|
||||
- Respects device power-save mode
|
||||
|
||||
**When to Use:**
|
||||
- Critical reading sessions
|
||||
- Multi-device concurrent reading
|
||||
- Research and study
|
||||
- Testing sync functionality
|
||||
- When power source available
|
||||
|
||||
**When NOT to Use:**
|
||||
- Battery conservation needed
|
||||
- Unstable network
|
||||
- Extended reading sessions
|
||||
- Background sync preferred
|
||||
data: "{\n \"books\": [\n {\n \"chapter\": 3,\n \"percentage\": 0.45678,\n \"timestamp\": \"2026-01-30T20:00:00Z\",\n \"uuid\": \"{{media_item_id}}\"\n }\n ],\n \"sync_mode\": \"immediate\"\n}"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/progress'
|
||||
auth:
|
||||
type: bearer
|
||||
token: '{{koreader_device_token}}'
|
||||
info:
|
||||
name: Immediate Sync - Page Turn
|
||||
seq: 10
|
||||
type: http
|
||||
@@ -1,44 +1,15 @@
|
||||
info:
|
||||
name: KOReader Sync Annotations - Per-Book SHA-256
|
||||
type: http
|
||||
seq: 4
|
||||
docs: "## KOReader Sync Annotations - Per-Book SHA-256\n\n Synchronizes annotations (highlights) from KOReader with per-annotation SHA-256 hashes for multi-book sync.\n\n **Method:** POST\n\n **Endpoint:** /api/v1/koreader/sync/bookmarks\n\n **Authentication:** Bearer token (KOReader device token)\n\n **Request Body:**\n - `book_uuid` (string): Primary book UUID\n - `highlights` (array): Array of highlight objects\n - `text` (string): Highlighted text\n - `pos0`, `pos1` (string): EPUB CFI positions\n - `color` (string): Highlight color (hex)\n - `page` (number): Page number\n - `book_sha256` (string): SHA-256 hash for this specific book\n\n **Response:**\n - `highlights_synced` (number): Number of highlights synced\n\n **Status Codes:**\n - 200: Success\n - 401: Unauthorized\n - 500: Internal server error\n\n **Note:** Each highlight can include its own book_sha256, allowing annotations from multiple books in a single request."
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/v1/koreader/sync/bookmarks'
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"book_uuid\": \"{{book_uuid"
|
||||
headers:
|
||||
- key: Authorization
|
||||
value: Bearer {{koreader_device_token
|
||||
|
||||
docs: |-
|
||||
## KOReader Sync Annotations - Per-Book SHA-256
|
||||
|
||||
Synchronizes annotations (highlights) from KOReader with per-annotation SHA-256 hashes for multi-book sync.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/v1/koreader/sync/bookmarks
|
||||
|
||||
**Authentication:** Bearer token (KOReader device token)
|
||||
|
||||
**Request Body:**
|
||||
- `book_uuid` (string): Primary book UUID
|
||||
- `highlights` (array): Array of highlight objects
|
||||
- `text` (string): Highlighted text
|
||||
- `pos0`, `pos1` (string): EPUB CFI positions
|
||||
- `color` (string): Highlight color (hex)
|
||||
- `page` (number): Page number
|
||||
- `book_sha256` (string): SHA-256 hash for this specific book
|
||||
|
||||
**Response:**
|
||||
- `highlights_synced` (number): Number of highlights synced
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 401: Unauthorized
|
||||
- 500: Internal server error
|
||||
|
||||
**Note:** Each highlight can include its own book_sha256, allowing annotations from multiple books in a single request.
|
||||
data: "{\n \"book_sha256\": \"{{book_sha256}}\",\n \"bookmarks\": [\n {\n \"chapter\": 3,\n \"datetime\": \"2026-01-30T19:55:00Z\",\n \"page\": 45,\n \"pos0\": \"p1\",\n \"text\": \"Per-book annotation\",\n \"type\": \"bookmark\"\n }\n ]\n}"
|
||||
headers: []
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/bookmarks'
|
||||
auth:
|
||||
type: bearer
|
||||
token: '{{koreader_device_token}}'
|
||||
info:
|
||||
name: KOReader Sync Annotations - Per-Book SHA-256
|
||||
seq: 4
|
||||
type: http
|
||||
@@ -1,40 +1,15 @@
|
||||
info:
|
||||
name: KOReader Sync Bookmarks - SHA-256
|
||||
type: http
|
||||
seq: 3
|
||||
docs: "## KOReader Sync Bookmarks - SHA-256\n\n Synchronizes bookmarks, notes, and highlights from KOReader using SHA-256 hash for book identification.\n\n **Method:** POST\n\n **Endpoint:** /api/v1/koreader/sync/bookmarks\n\n **Authentication:** Bearer token (KOReader device token)\n\n **Request Body:**\n - `book_sha256` (string): SHA-256 hash of book file\n - `bookmarks` (array): Array of bookmarks\n - `notes` (array): Array of notes\n - `highlights` (array): Array of highlights\n\n **Response:**\n - `sync_status` (string): Sync status\n - `total_synced` (number): Total items synced\n\n **Status Codes:**\n - 200: Success\n - 401: Unauthorized\n - 500: Internal server error"
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/v1/koreader/sync/bookmarks'
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"book_sha256\": \"{{book_sha256"
|
||||
headers:
|
||||
- key: Authorization
|
||||
value: Bearer {{koreader_device_token
|
||||
|
||||
docs: |-
|
||||
## KOReader Sync Bookmarks - SHA-256
|
||||
|
||||
Synchronizes bookmarks, notes, and highlights from KOReader using SHA-256 hash for book identification.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/v1/koreader/sync/bookmarks
|
||||
|
||||
**Authentication:** Bearer token (KOReader device token)
|
||||
|
||||
**Request Body:**
|
||||
- `book_sha256` (string): SHA-256 hash of book file
|
||||
- `bookmarks` (array): Array of bookmarks
|
||||
- `notes` (array): Array of notes
|
||||
- `highlights` (array): Array of highlights
|
||||
|
||||
**Response:**
|
||||
- `sync_status` (string): Sync status
|
||||
- `total_synced` (number): Total items synced
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 401: Unauthorized
|
||||
- 500: Internal server error
|
||||
data: "{\n \"book_sha256\": \"{{book_sha256}}\",\n \"bookmarks\": [\n {\n \"chapter\": 3,\n \"datetime\": \"2026-01-30T19:55:00Z\",\n \"page\": 45,\n \"pos0\": \"p1\",\n \"text\": \"SHA-256 bookmark\",\n \"type\": \"bookmark\"\n }\n ]\n}"
|
||||
headers: []
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/bookmarks'
|
||||
auth:
|
||||
type: bearer
|
||||
token: '{{koreader_device_token}}'
|
||||
info:
|
||||
name: KOReader Sync Bookmarks - SHA-256
|
||||
seq: 3
|
||||
type: http
|
||||
@@ -1,105 +1,19 @@
|
||||
info:
|
||||
name: Sync Bookmarks
|
||||
type: http
|
||||
seq: 5
|
||||
|
||||
docs: "## Sync KOReader Bookmarks\n\nSynchronizes bookmarks separately from progress for KOReader.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/koreader/bookmarks\n\n**Authentication:** Bearer token\n\n**Request Body:**\n- `library_id` (string, optional): Library UUID\n- `books` (array): Books with bookmarks\n - `uuid` (string): Book UUID\n - `bookmarks` (array): Bookmark items\n - `chapter` (integer): Chapter number\n - `datetime` (string): ISO 8601 timestamp\n - `notes` (string): Bookmark description\n - `pos0` (string): EPUB CFI start position\n - `pos1` (string): EPUB CFI end position\n - `page` (integer): Page number\n - `text` (string): Displayed text\n - `type` (string): `bookmark`, `highlight`, or `note`\n\n**Response:**\n- `synced` (integer): Number of bookmarks synced\n- `duplicates_skipped` (integer): Duplicate bookmarks skipped\n- `results` (array): Per-bookmark results\n- `timestamp` (string): Sync timestamp\n\n**Status Codes:**\n- 200: Success\n\
|
||||
- 401: Unauthorized\n- 400: Invalid data\n\n**Dedicated Bookmark Endpoint:**\n- **Purpose**: Sync bookmarks independently\n- **Use case**: More frequent bookmark updates\n- **Advantage**: Separate from progress sync\n- **Efficiency**: Smaller payloads\n\n**KOReader Bookmark Features:**\n- Chapter-based organization\n- Quick navigation markers\n- Hierarchical bookmarks (via plugins)\n- Custom bookmark titles\n- Date/time tracking\n- EPUB CFI precision\n\n**Bookmark Types in KOReader:**\n- **Location bookmarks**: Quick navigation points\n- **Chapter marks**: Auto-generated chapter markers\n- **Progress bookmarks**: Last read positions\n- **Custom bookmarks**: User-created markers\n- **Search bookmarks**: Saved search results\n\n**Sync Behavior:**\n- Duplicate detection by position + text\n- Most recent wins on conflicts\n- Chapter order preserved\n- Auto-generated vs manual bookmarks differentiated\n- Merge with existing bookmarks\n\n**KOReader Device Integration:**\n- Created via \"Add\
|
||||
\ bookmark\" menu\n- Shown in \"Bookmarks\" panel\n- Quick access via \"Go to bookmark\"\n- Exportable to JSON\n- Can be edited/deleted\n\n**Use Cases:**\n- Quick navigation aids\n- Chapter markers\n- Important passages\n- Reading progress points\n- Study session markers"
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/bookmarks'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
library_id: optional-library-uuid
|
||||
books:
|
||||
- uuid: book-uuid
|
||||
bookmarks:
|
||||
- chapter: 3
|
||||
datetime: '2026-01-30T19:55:00Z'
|
||||
notes: Marked this chapter as important
|
||||
pos0: 'epubcfi(/6/4/2:15)'
|
||||
pos1: 'epubcfi(/6/4/2:20)'
|
||||
page: 45
|
||||
text: Important passage
|
||||
type: bookmark
|
||||
|
||||
docs: |-
|
||||
## Sync KOReader Bookmarks
|
||||
|
||||
Synchronizes bookmarks separately from progress for KOReader.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/koreader/bookmarks
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Request Body:**
|
||||
- `library_id` (string, optional): Library UUID
|
||||
- `books` (array): Books with bookmarks
|
||||
- `uuid` (string): Book UUID
|
||||
- `bookmarks` (array): Bookmark items
|
||||
- `chapter` (integer): Chapter number
|
||||
- `datetime` (string): ISO 8601 timestamp
|
||||
- `notes` (string): Bookmark description
|
||||
- `pos0` (string): EPUB CFI start position
|
||||
- `pos1` (string): EPUB CFI end position
|
||||
- `page` (integer): Page number
|
||||
- `text` (string): Displayed text
|
||||
- `type` (string): `bookmark`, `highlight`, or `note`
|
||||
|
||||
**Response:**
|
||||
- `synced` (integer): Number of bookmarks synced
|
||||
- `duplicates_skipped` (integer): Duplicate bookmarks skipped
|
||||
- `results` (array): Per-bookmark results
|
||||
- `timestamp` (string): Sync timestamp
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 401: Unauthorized
|
||||
- 400: Invalid data
|
||||
|
||||
**Dedicated Bookmark Endpoint:**
|
||||
- **Purpose**: Sync bookmarks independently
|
||||
- **Use case**: More frequent bookmark updates
|
||||
- **Advantage**: Separate from progress sync
|
||||
- **Efficiency**: Smaller payloads
|
||||
|
||||
**KOReader Bookmark Features:**
|
||||
- Chapter-based organization
|
||||
- Quick navigation markers
|
||||
- Hierarchical bookmarks (via plugins)
|
||||
- Custom bookmark titles
|
||||
- Date/time tracking
|
||||
- EPUB CFI precision
|
||||
|
||||
**Bookmark Types in KOReader:**
|
||||
- **Location bookmarks**: Quick navigation points
|
||||
- **Chapter marks**: Auto-generated chapter markers
|
||||
- **Progress bookmarks**: Last read positions
|
||||
- **Custom bookmarks**: User-created markers
|
||||
- **Search bookmarks**: Saved search results
|
||||
|
||||
**Sync Behavior:**
|
||||
- Duplicate detection by position + text
|
||||
- Most recent wins on conflicts
|
||||
- Chapter order preserved
|
||||
- Auto-generated vs manual bookmarks differentiated
|
||||
- Merge with existing bookmarks
|
||||
|
||||
**KOReader Device Integration:**
|
||||
- Created via "Add bookmark" menu
|
||||
- Shown in "Bookmarks" panel
|
||||
- Quick access via "Go to bookmark"
|
||||
- Exportable to JSON
|
||||
- Can be edited/deleted
|
||||
|
||||
**Use Cases:**
|
||||
- Quick navigation aids
|
||||
- Chapter markers
|
||||
- Important passages
|
||||
- Reading progress points
|
||||
- Study session markers
|
||||
data: "{\n \"book_uuid\": \"{{media_item_id}}\",\n \"bookmarks\": [\n {\n \"chapter\": 3,\n \"datetime\": \"2026-01-30T19:55:00Z\",\n \"page\": 45,\n \"pos0\": \"epubcfi(/6/4/2:15)\",\n \"pos1\": \"epubcfi(/6/4/2:20)\",\n \"text\": \"Important passage\",\n \"type\": \"bookmark\"\n }\n ]\n}"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/bookmarks'
|
||||
auth:
|
||||
type: bearer
|
||||
token: '{{koreader_device_token}}'
|
||||
info:
|
||||
name: Sync Bookmarks
|
||||
seq: 5
|
||||
type: http
|
||||
@@ -1,110 +1,16 @@
|
||||
info:
|
||||
name: Sync Highlights
|
||||
type: http
|
||||
seq: 6
|
||||
|
||||
docs: "## Sync KOReader Highlights\n\nSynchronizes text highlights separately from other annotations.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/koreader/highlights\n\n**Authentication:** Bearer token\n\n**Request Body:**\n- `library_id` (string, optional): Library UUID\n- `books` (array): Books with highlights\n - `uuid` (string): Book UUID\n - `highlights` (array): Highlight items\n - `datetime` (string): Creation timestamp\n - `text` (string): Highlighted text content\n - `chapter` (integer): Chapter number\n - `pos0` (string): EPUB CFI start position\n - `pos1` (string): EPUB CFI end position\n - `page_start` (integer): Start page\n - `page_end` (integer): End page\n - `color` (string, optional): Color name or hex\n - `note` (string, optional): Attached note\n\n**Response:**\n- `synced` (integer): Highlights synced\n- `duplicates_skipped` (integer): Duplicates found\n- `with_notes` (integer): Highlights that have notes attached\n- `timestamp` (string):\
|
||||
\ Sync timestamp\n\n**KOReader Highlight Features:**\n- Precise text selection (EPUB CFI)\n- Custom color support (via plugins)\n- Multi-page highlights\n- Chapter references\n- Timestamps for sorting\n- Attached notes support\n- Full text preservation\n\n**Highlight Colors (via plugins):**\n- Yellow (default): General highlighting\n- Green: Important concepts\n- Blue: Key information\n- Red/pink: Critical content\n- Orange: Interesting quotes\n- Custom RGB colors available\n\n**EPUB CFI Advantages:**\n- Precise start/end positions\n- Works across font size changes\n- Survives text reflow\n- Device-independent\n- Standardized format\n\n**Dedicated Highlight Endpoint:**\n- **Separate from progress**: Sync highlights independently\n- **Smaller payload**: Just highlights, no progress\n- **More frequent**: Can sync highlights immediately\n- **Focused**: Single-purpose endpoint\n\n**Sync Behavior:**\n- Exact text matching for duplicates\n- Position-based conflict resolution\n- Color preservation\
|
||||
\ across devices\n- Note attachments preserved\n- Order maintained by position\n\n**KOReader Device Features:**\n- Created via long-press or selection\n- Color picker available\n- Can add notes immediately\n- Shows in \"Highlights\" panel\n- Exportable to Evernote, etc.\n- Searchable by content\n\n**Use Cases:**\n- Study and research\n- Content curation\n- Quote collection\n- Academic work\n- Sharing insights"
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/highlights'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
library_id: optional-library-uuid
|
||||
books:
|
||||
- uuid: book-uuid
|
||||
highlights:
|
||||
- datetime: '2026-01-30T19:50:00Z'
|
||||
text: Important quote from book
|
||||
chapter: 4
|
||||
pos0: 'epubcfi(/6/4/2:20)'
|
||||
pos1: 'epubcfi(/6/4/2:30)'
|
||||
page_start: 78
|
||||
page_end: 79
|
||||
|
||||
docs: |-
|
||||
## Sync KOReader Highlights
|
||||
|
||||
Synchronizes text highlights separately from other annotations.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/koreader/highlights
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Request Body:**
|
||||
- `library_id` (string, optional): Library UUID
|
||||
- `books` (array): Books with highlights
|
||||
- `uuid` (string): Book UUID
|
||||
- `highlights` (array): Highlight items
|
||||
- `datetime` (string): Creation timestamp
|
||||
- `text` (string): Highlighted text content
|
||||
- `chapter` (integer): Chapter number
|
||||
- `pos0` (string): EPUB CFI start position
|
||||
- `pos1` (string): EPUB CFI end position
|
||||
- `page_start` (integer): Start page
|
||||
- `page_end` (integer): End page
|
||||
- `color` (string, optional): Color name or hex
|
||||
- `note` (string, optional): Attached note
|
||||
|
||||
**Response:**
|
||||
- `synced` (integer): Highlights synced
|
||||
- `duplicates_skipped` (integer): Duplicates found
|
||||
- `with_notes` (integer): Highlights that have notes attached
|
||||
- `timestamp` (string): Sync timestamp
|
||||
|
||||
**KOReader Highlight Features:**
|
||||
- Precise text selection (EPUB CFI)
|
||||
- Custom color support (via plugins)
|
||||
- Multi-page highlights
|
||||
- Chapter references
|
||||
- Timestamps for sorting
|
||||
- Attached notes support
|
||||
- Full text preservation
|
||||
|
||||
**Highlight Colors (via plugins):**
|
||||
- Yellow (default): General highlighting
|
||||
- Green: Important concepts
|
||||
- Blue: Key information
|
||||
- Red/pink: Critical content
|
||||
- Orange: Interesting quotes
|
||||
- Custom RGB colors available
|
||||
|
||||
**EPUB CFI Advantages:**
|
||||
- Precise start/end positions
|
||||
- Works across font size changes
|
||||
- Survives text reflow
|
||||
- Device-independent
|
||||
- Standardized format
|
||||
|
||||
**Dedicated Highlight Endpoint:**
|
||||
- **Separate from progress**: Sync highlights independently
|
||||
- **Smaller payload**: Just highlights, no progress
|
||||
- **More frequent**: Can sync highlights immediately
|
||||
- **Focused**: Single-purpose endpoint
|
||||
|
||||
**Sync Behavior:**
|
||||
- Exact text matching for duplicates
|
||||
- Position-based conflict resolution
|
||||
- Color preservation across devices
|
||||
- Note attachments preserved
|
||||
- Order maintained by position
|
||||
|
||||
**KOReader Device Features:**
|
||||
- Created via long-press or selection
|
||||
- Color picker available
|
||||
- Can add notes immediately
|
||||
- Shows in "Highlights" panel
|
||||
- Exportable to Evernote, etc.
|
||||
- Searchable by content
|
||||
|
||||
**Use Cases:**
|
||||
- Study and research
|
||||
- Content curation
|
||||
- Quote collection
|
||||
- Academic work
|
||||
- Sharing insights
|
||||
data: "{\n \"book_uuid\": \"786b9c39-e8c3-47ab-a48a-c7f6cd769930\",\n \"highlights\": [\n {\n \"datetime\": \"2026-01-30T19:50:00Z\",\n \"text\": \"bruno sweep highlight\",\n \"chapter\": 1,\n \"page\": 1,\n \"pos0\": \"1\",\n \"pos1\": \"9\",\n \"color\": \"#ffff00\"\n }\n ]\n}"
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/bookmarks'
|
||||
auth:
|
||||
type: bearer
|
||||
token: '{{koreader_device_token}}'
|
||||
info:
|
||||
name: Sync Highlights
|
||||
seq: 6
|
||||
type: http
|
||||
@@ -1,108 +1,19 @@
|
||||
info:
|
||||
name: Sync Notes
|
||||
type: http
|
||||
seq: 7
|
||||
|
||||
docs: "## Sync KOReader Notes\n\nSynchronizes user notes separately from highlights and bookmarks.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/koreader/notes\n\n**Authentication:** Bearer token\n\n**Request Body:**\n- `library_id` (string, optional): Library UUID\n- `books` (array): Books with notes\n - `uuid` (string): Book UUID\n - `notes` (array): Note items\n - `datetime` (string): Creation/modification timestamp\n - `text` (string): Note content\n - `chapter` (integer): Chapter number\n - `pos0` (string, optional): Related EPUB CFI position\n - `page` (integer, optional): Page number\n - `highlighted_text` (string, optional): Related highlight\n\n**Response:**\n- `synced` (integer): Notes synced\n- `duplicates_skipped` (integer): Duplicate notes found\n- `attached_to_highlights` (integer): Notes linked to highlights\n- `timestamp` (string): Sync timestamp\n\n**KOReader Note Features:**\n- Free-form text notes\n- Can be standalone or attached to highlights\n- Chapter-based\
|
||||
\ organization\n- Timestamped for sorting\n- Markdown support (some versions)\n- Longer form content\n- No character limit\n\n**Note Types:**\n- **Standalone notes**: Independent notes about chapter/section\n- **Attached notes**: Notes attached to specific highlights\n- **Chapter notes**: Notes about entire chapter\n- **Book notes**: General notes about the book\n\n**Dedicated Notes Endpoint:**\n- **Separate sync**: Notes sync independently\n- **Flexible**: Not tied to highlights\n- **Efficient**: Smaller, focused payload\n- **Immediate**: Can sync right after note creation\n\n**Attached Notes:**\n- Linked to specific highlight\n- Shares highlight's position\n- Shown together with highlight\n- Deleted when highlight deleted (optional)\n- Color matches highlight\n\n**Sync Behavior:**\n- Text-based duplicate detection\n- Time-based conflict resolution\n- Chapter organization preserved\n- Markdown formatting preserved\n- Attachment links maintained\n\n**KOReader Device Integration:**\n- Created\
|
||||
\ via \"Add note\" option\n- Edited in note editor\n- Shown in \"Notes\" panel\n- Can be organized by chapter\n- Export functionality available\n- Search support\n\n**Advanced Features:**\n- **Markdown**: Bold, italic, lists (some versions)\n- **Tags**: User-defined tags (via plugins)\n- **Links**: Internal/external links\n- **Formatting**: Rich text in newer versions\n\n**Use Cases:**\n- Study notes\n- Personal reflections\n- Academic annotations\n- Research insights\n- Book club discussion prep\n- Knowledge management"
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/notes'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
library_id: optional-library-uuid
|
||||
books:
|
||||
- uuid: book-uuid
|
||||
notes:
|
||||
- datetime: '2026-01-30T19:52:00Z'
|
||||
text: My personal note about this chapter
|
||||
chapter: 4
|
||||
|
||||
docs: |-
|
||||
## Sync KOReader Notes
|
||||
|
||||
Synchronizes user notes separately from highlights and bookmarks.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/koreader/notes
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Request Body:**
|
||||
- `library_id` (string, optional): Library UUID
|
||||
- `books` (array): Books with notes
|
||||
- `uuid` (string): Book UUID
|
||||
- `notes` (array): Note items
|
||||
- `datetime` (string): Creation/modification timestamp
|
||||
- `text` (string): Note content
|
||||
- `chapter` (integer): Chapter number
|
||||
- `pos0` (string, optional): Related EPUB CFI position
|
||||
- `page` (integer, optional): Page number
|
||||
- `highlighted_text` (string, optional): Related highlight
|
||||
|
||||
**Response:**
|
||||
- `synced` (integer): Notes synced
|
||||
- `duplicates_skipped` (integer): Duplicate notes found
|
||||
- `attached_to_highlights` (integer): Notes linked to highlights
|
||||
- `timestamp` (string): Sync timestamp
|
||||
|
||||
**KOReader Note Features:**
|
||||
- Free-form text notes
|
||||
- Can be standalone or attached to highlights
|
||||
- Chapter-based organization
|
||||
- Timestamped for sorting
|
||||
- Markdown support (some versions)
|
||||
- Longer form content
|
||||
- No character limit
|
||||
|
||||
**Note Types:**
|
||||
- **Standalone notes**: Independent notes about chapter/section
|
||||
- **Attached notes**: Notes attached to specific highlights
|
||||
- **Chapter notes**: Notes about entire chapter
|
||||
- **Book notes**: General notes about the book
|
||||
|
||||
**Dedicated Notes Endpoint:**
|
||||
- **Separate sync**: Notes sync independently
|
||||
- **Flexible**: Not tied to highlights
|
||||
- **Efficient**: Smaller, focused payload
|
||||
- **Immediate**: Can sync right after note creation
|
||||
|
||||
**Attached Notes:**
|
||||
- Linked to specific highlight
|
||||
- Shares highlight's position
|
||||
- Shown together with highlight
|
||||
- Deleted when highlight deleted (optional)
|
||||
- Color matches highlight
|
||||
|
||||
**Sync Behavior:**
|
||||
- Text-based duplicate detection
|
||||
- Time-based conflict resolution
|
||||
- Chapter organization preserved
|
||||
- Markdown formatting preserved
|
||||
- Attachment links maintained
|
||||
|
||||
**KOReader Device Integration:**
|
||||
- Created via "Add note" option
|
||||
- Edited in note editor
|
||||
- Shown in "Notes" panel
|
||||
- Can be organized by chapter
|
||||
- Export functionality available
|
||||
- Search support
|
||||
|
||||
**Advanced Features:**
|
||||
- **Markdown**: Bold, italic, lists (some versions)
|
||||
- **Tags**: User-defined tags (via plugins)
|
||||
- **Links**: Internal/external links
|
||||
- **Formatting**: Rich text in newer versions
|
||||
|
||||
**Use Cases:**
|
||||
- Study notes
|
||||
- Personal reflections
|
||||
- Academic annotations
|
||||
- Research insights
|
||||
- Book club discussion prep
|
||||
- Knowledge management
|
||||
data: "{\n \"book_uuid\": \"{{media_item_id}}\",\n \"notes\": [\n {\n \"datetime\": \"2026-01-30T19:52:00Z\",\n \"notes\": \"A personal note about this chapter\",\n \"chapter\": 4,\n \"page\": 57,\n \"pos0\": \"3\"\n }\n ]\n}"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/bookmarks'
|
||||
auth:
|
||||
type: bearer
|
||||
token: '{{koreader_device_token}}'
|
||||
info:
|
||||
name: Sync Notes
|
||||
seq: 7
|
||||
type: http
|
||||
@@ -1,47 +1,15 @@
|
||||
info:
|
||||
name: KOReader Sync Progress - SHA-256 Only
|
||||
type: http
|
||||
seq: 2
|
||||
docs: "## KOReader Sync Progress - SHA-256 Only\n\n Synchronizes reading progress using only SHA-256 hash for book identification (when UUID is not available).\n\n **Method:** POST\n\n **Endpoint:** /api/v1/koreader/sync/progress\n\n **Authentication:** Bearer token (KOReader device token)\n\n **Request Body:**\n - `sync_mode` (string): Sync mode (immediate, deferred)\n - `books` (array): Array of book progress objects\n - `sha256` (string): SHA-256 hash of book file\n - `file_path` (string): Path to book file\n - `percentage` (number): Progress percentage\n - `page` (number): Current page\n - `total_pages` (number): Total pages\n\n **Response:**\n - `sync_status` (string): Sync status\n - `books_synced` (number): Number of books synced\n\n **Status Codes:**\n - 200: Success\n - 202: Accepted\n - 401: Unauthorized\n - 500: Internal server error\n\n **Note:** Use this when book UUID is not available, falling back to SHA-256 hash for identification."
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/v1/koreader/sync/progress'
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"sync_mode\": \"immediate\",\n \"books\": [\n {\n \
|
||||
\ \"sha256\": \"{{book_sha256"
|
||||
headers:
|
||||
- key: Authorization
|
||||
value: Bearer {{koreader_device_token
|
||||
|
||||
docs: |-
|
||||
## KOReader Sync Progress - SHA-256 Only
|
||||
|
||||
Synchronizes reading progress using only SHA-256 hash for book identification (when UUID is not available).
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/v1/koreader/sync/progress
|
||||
|
||||
**Authentication:** Bearer token (KOReader device token)
|
||||
|
||||
**Request Body:**
|
||||
- `sync_mode` (string): Sync mode (immediate, deferred)
|
||||
- `books` (array): Array of book progress objects
|
||||
- `sha256` (string): SHA-256 hash of book file
|
||||
- `file_path` (string): Path to book file
|
||||
- `percentage` (number): Progress percentage
|
||||
- `page` (number): Current page
|
||||
- `total_pages` (number): Total pages
|
||||
|
||||
**Response:**
|
||||
- `sync_status` (string): Sync status
|
||||
- `books_synced` (number): Number of books synced
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 202: Accepted
|
||||
- 401: Unauthorized
|
||||
- 500: Internal server error
|
||||
|
||||
**Note:** Use this when book UUID is not available, falling back to SHA-256 hash for identification.
|
||||
data: "{\n \"sync_mode\": \"immediate\",\n \"books\": [\n {\n \"sha256\": \"{{book_sha256}}\",\n \"percentage\": 0.5\n }\n ]\n}"
|
||||
headers: []
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/progress'
|
||||
auth:
|
||||
type: bearer
|
||||
token: '{{koreader_device_token}}'
|
||||
info:
|
||||
name: KOReader Sync Progress - SHA-256 Only
|
||||
seq: 2
|
||||
type: http
|
||||
@@ -1,51 +1,16 @@
|
||||
info:
|
||||
name: KOReader Sync Progress - SHA-256
|
||||
type: http
|
||||
seq: 1
|
||||
docs: "## KOReader Sync Progress - SHA-256\n\n Synchronizes reading progress from a KOReader device using SHA-256 book hash for identification.\n\n **Method:** POST\n\n **Endpoint:** /api/v1/koreader/sync/progress\n\n **Authentication:** Bearer token (KOReader device token)\n\n **Request Body:**\n - `sync_mode` (string): Sync mode (immediate, deferred)\n - `books` (array): Array of book progress objects\n - `uuid` (string): Book UUID\n - `sha256` (string): SHA-256 hash of book file for identification\n - `file_path` (string): Path to book file on device\n - `percentage` (number): Progress percentage (0-1)\n - `chapter` (number): Current chapter\n - `page` (number): Current page\n - `total_pages` (number): Total pages\n - `epubcfi` (string): EPUB location\n - `last_read` (string): ISO 8601 timestamp\n - `title` (string): Book title\n - `authors` (array): List of authors\n\n **Response:**\n - `sync_status` (string): Sync status\n - `books_synced`\
|
||||
\ (number): Number of books synced\n\n **Status Codes:**\n - 200: Success\n - 202: Accepted - processing\n - 401: Unauthorized\n - 500: Internal server error"
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/v1/koreader/sync/progress'
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"sync_mode\": \"immediate\",\n \"books\": [\n {\n \
|
||||
\ \"uuid\": \"{{book_uuid"
|
||||
headers:
|
||||
- key: Authorization
|
||||
value: Bearer {{koreader_device_token
|
||||
|
||||
docs: |-
|
||||
## KOReader Sync Progress - SHA-256
|
||||
|
||||
Synchronizes reading progress from a KOReader device using SHA-256 book hash for identification.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/v1/koreader/sync/progress
|
||||
|
||||
**Authentication:** Bearer token (KOReader device token)
|
||||
|
||||
**Request Body:**
|
||||
- `sync_mode` (string): Sync mode (immediate, deferred)
|
||||
- `books` (array): Array of book progress objects
|
||||
- `uuid` (string): Book UUID
|
||||
- `sha256` (string): SHA-256 hash of book file for identification
|
||||
- `file_path` (string): Path to book file on device
|
||||
- `percentage` (number): Progress percentage (0-1)
|
||||
- `chapter` (number): Current chapter
|
||||
- `page` (number): Current page
|
||||
- `total_pages` (number): Total pages
|
||||
- `epubcfi` (string): EPUB location
|
||||
- `last_read` (string): ISO 8601 timestamp
|
||||
- `title` (string): Book title
|
||||
- `authors` (array): List of authors
|
||||
|
||||
**Response:**
|
||||
- `sync_status` (string): Sync status
|
||||
- `books_synced` (number): Number of books synced
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 202: Accepted - processing
|
||||
- 401: Unauthorized
|
||||
- 500: Internal server error
|
||||
data: "{\n \"sync_mode\": \"immediate\",\n \"books\": [\n {\n \"sha256\": \"{{book_sha256}}\",\n \"percentage\": 0.5\n }\n ]\n}"
|
||||
headers: []
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/progress'
|
||||
auth:
|
||||
type: bearer
|
||||
token: '{{koreader_device_token}}'
|
||||
info:
|
||||
name: KOReader Sync Progress - SHA-256
|
||||
seq: 1
|
||||
type: http
|
||||
@@ -1,90 +1,18 @@
|
||||
info:
|
||||
name: Sync Progress - Multiple Books
|
||||
type: http
|
||||
seq: 2
|
||||
|
||||
docs: "## Sync KOReader Progress - Multiple Books\n\nSynchronizes reading progress for multiple books in a single request.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/koreader/progress\n\n**Authentication:** Bearer token\n\n**Request Body:**\n- `library_id` (string, optional): Library UUID\n- `books` (array): Multiple book progress items\n - Each item contains: uuid, title, authors, progress, percentage, last_read, chapter, epubcfi\n\n**Response:**\n- `synced` (integer): Number of books successfully synced\n- `failed` (integer): Number of books that failed\n- `results` (array): Per-book sync results\n- `timestamp` (string): Sync timestamp\n\n**Status Codes:**\n- 200: Batch sync completed\n- 207: Multi-status (partial success)\n- 401: Unauthorized\n- 413: Payload too large\n\n**Batch Sync Advantages:**\n- Efficient sync of entire library\n- Single HTTP request for multiple books\n- Faster periodic sync\n- Reduced battery usage vs individual syncs\n- Better for batch processing\n\n**KOReader\
|
||||
\ Batch Behavior:**\n- Triggered on device wake from sleep\n- Occurs during \"Sync now\" operation\n- Runs on WiFi connection\n- Limited to 100 books per request\n- Automatic retry on failed books\n\n**Performance:**\n- Small batch (2-10 books): 200-500ms\n- Medium batch (10-50 books): 500ms-2s\n- Large batch (50-100 books): 2-5s\n- Timeout: 30 seconds\n\n**Use Cases:**\n- Device initialization sync\n- Periodic background sync\n- Post-offline catch-up sync\n- Library-wide progress update\n- Before firmware update"
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/progress'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
library_id: optional-library-uuid
|
||||
books:
|
||||
- uuid: book-1-uuid
|
||||
title: Book One
|
||||
authors:
|
||||
- Author One
|
||||
progress: 0.25
|
||||
percentage: 0.25
|
||||
last_read: '2026-01-30T19:00:00Z'
|
||||
chapter: 1
|
||||
epubcfi: 'epubcfi(/6/4/2:10)'
|
||||
- uuid: book-2-uuid
|
||||
title: Book Two
|
||||
authors:
|
||||
- Author Two
|
||||
progress: 0.75
|
||||
percentage: 0.75
|
||||
last_read: '2026-01-30T20:00:00Z'
|
||||
chapter: 8
|
||||
epubcfi: 'epubcfi(/6/4/2:50)'
|
||||
|
||||
docs: |-
|
||||
## Sync KOReader Progress - Multiple Books
|
||||
|
||||
Synchronizes reading progress for multiple books in a single request.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/koreader/progress
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Request Body:**
|
||||
- `library_id` (string, optional): Library UUID
|
||||
- `books` (array): Multiple book progress items
|
||||
- Each item contains: uuid, title, authors, progress, percentage, last_read, chapter, epubcfi
|
||||
|
||||
**Response:**
|
||||
- `synced` (integer): Number of books successfully synced
|
||||
- `failed` (integer): Number of books that failed
|
||||
- `results` (array): Per-book sync results
|
||||
- `timestamp` (string): Sync timestamp
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Batch sync completed
|
||||
- 207: Multi-status (partial success)
|
||||
- 401: Unauthorized
|
||||
- 413: Payload too large
|
||||
|
||||
**Batch Sync Advantages:**
|
||||
- Efficient sync of entire library
|
||||
- Single HTTP request for multiple books
|
||||
- Faster periodic sync
|
||||
- Reduced battery usage vs individual syncs
|
||||
- Better for batch processing
|
||||
|
||||
**KOReader Batch Behavior:**
|
||||
- Triggered on device wake from sleep
|
||||
- Occurs during "Sync now" operation
|
||||
- Runs on WiFi connection
|
||||
- Limited to 100 books per request
|
||||
- Automatic retry on failed books
|
||||
|
||||
**Performance:**
|
||||
- Small batch (2-10 books): 200-500ms
|
||||
- Medium batch (10-50 books): 500ms-2s
|
||||
- Large batch (50-100 books): 2-5s
|
||||
- Timeout: 30 seconds
|
||||
|
||||
**Use Cases:**
|
||||
- Device initialization sync
|
||||
- Periodic background sync
|
||||
- Post-offline catch-up sync
|
||||
- Library-wide progress update
|
||||
- Before firmware update
|
||||
data: "{\n \"books\": [\n {\n \"authors\": [\n \"Author One\"\n ],\n \"chapter\": 1,\n \"epubcfi\": \"epubcfi(/6/4/2:10)\",\n \"last_read\": \"2026-01-30T19:00:00Z\",\n \"percentage\": 0.25,\n \"progress\": 0.25,\n \"title\": \"Book One\",\n \"uuid\": \"{{media_item_id}}\"\n },\n {\n \"authors\": [\n \"Author Two\"\n ],\n \"chapter\": 8,\n \"epubcfi\": \"epubcfi(/6/4/2:50)\",\n \"last_read\": \"2026-01-30T20:00:00Z\",\n \"percentage\": 0.75,\n \"progress\": 0.75,\n \"title\": \"Book Two\",\n \"uuid\": \"{{media_item_id}}\"\n }\n ],\n \"library_id\": \"optional-library-uuid\"\n}"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/progress'
|
||||
auth:
|
||||
type: bearer
|
||||
token: '{{koreader_device_token}}'
|
||||
info:
|
||||
name: Sync Progress - Multiple Books
|
||||
seq: 2
|
||||
type: http
|
||||
@@ -1,92 +1,19 @@
|
||||
info:
|
||||
name: Sync Progress - Single Book
|
||||
type: http
|
||||
seq: 1
|
||||
|
||||
docs: "## Sync KOReader Progress - Single Book\n\nSynchronizes reading progress for a single book from KOReader device.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/koreader/progress\n\n**Authentication:** Bearer token (koreader_device_token)\n\n**Request Body:**\n- `library_id` (string, optional): Library UUID for multi-library setups\n- `books` (array): Array with single book progress\n - `uuid` (string): Unique book identifier (often SHA-256 hash)\n - `title` (string): Book title\n - `authors` (array): List of authors\n - `progress` (number): Progress decimal (0.0 to 1.0)\n - `percentage` (number): Progress percentage (0.45 = 45%)\n - `last_read` (string): ISO 8601 timestamp of last read\n - `chapter` (integer): Current chapter number\n - `epubcfi` (string): EPUB Canonical Fragment Identifier\n - `character` (integer): Character position in book\n - `page` (integer, optional): Current page number\n\n**Response:**\n- `synced` (integer): Number of books synced\n- `timestamp`\
|
||||
\ (string): Server sync timestamp\n- `books` (array): Sync results\n - `uuid` (string): Book UUID\n - `status` (string): `synced`, `updated`, `skipped`\n - `server_progress` (object): Server-side progress data\n\n**Status Codes:**\n- 200: Success\n- 401: Unauthorized\n- 400: Invalid request format\n\n**KOReader Progress Tracking:**\n- SHA-256 based book identification (universal across devices)\n- EPUB CFI for precise location (standard format)\n- Chapter-based navigation\n- Character-level precision\n- Supports EPUB, FB2, PDF, DJVU, MOBI formats\n\n**EPUB CFI Format:**\n- Standardized location format for EPUBs\n- Example: `epubcfi(/6/4/2:15)`\n- Identifies exact position even after reflow\n- Works across different devices/apps\n- Preserved after file modifications\n\n**Book Identification:**\n- Primary: SHA-256 hash of book file\n- Universal: Same book = same UUID across devices\n- Format-agnostic: Works for any supported format\n- Case-sensitive: Hash must match exactly\n\n**Use Cases:**\n\
|
||||
- Real-time page turn sync\n- Progress backup\n- Cross-device continuity\n- Reading time tracking\n- Chapter completion detection"
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/progress'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
library_id: optional-library-uuid
|
||||
books:
|
||||
- uuid: book-uuid-here
|
||||
title: Book Title
|
||||
authors:
|
||||
- Author Name
|
||||
progress: 0.45
|
||||
percentage: 0.45
|
||||
last_read: '2026-01-30T20:00:00Z'
|
||||
chapter: 3
|
||||
epubcfi: 'epubcfi(/6/4/2:15)'
|
||||
character: 15432
|
||||
|
||||
docs: |-
|
||||
## Sync KOReader Progress - Single Book
|
||||
|
||||
Synchronizes reading progress for a single book from KOReader device.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/koreader/progress
|
||||
|
||||
**Authentication:** Bearer token (koreader_device_token)
|
||||
|
||||
**Request Body:**
|
||||
- `library_id` (string, optional): Library UUID for multi-library setups
|
||||
- `books` (array): Array with single book progress
|
||||
- `uuid` (string): Unique book identifier (often SHA-256 hash)
|
||||
- `title` (string): Book title
|
||||
- `authors` (array): List of authors
|
||||
- `progress` (number): Progress decimal (0.0 to 1.0)
|
||||
- `percentage` (number): Progress percentage (0.45 = 45%)
|
||||
- `last_read` (string): ISO 8601 timestamp of last read
|
||||
- `chapter` (integer): Current chapter number
|
||||
- `epubcfi` (string): EPUB Canonical Fragment Identifier
|
||||
- `character` (integer): Character position in book
|
||||
- `page` (integer, optional): Current page number
|
||||
|
||||
**Response:**
|
||||
- `synced` (integer): Number of books synced
|
||||
- `timestamp` (string): Server sync timestamp
|
||||
- `books` (array): Sync results
|
||||
- `uuid` (string): Book UUID
|
||||
- `status` (string): `synced`, `updated`, `skipped`
|
||||
- `server_progress` (object): Server-side progress data
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 401: Unauthorized
|
||||
- 400: Invalid request format
|
||||
|
||||
**KOReader Progress Tracking:**
|
||||
- SHA-256 based book identification (universal across devices)
|
||||
- EPUB CFI for precise location (standard format)
|
||||
- Chapter-based navigation
|
||||
- Character-level precision
|
||||
- Supports EPUB, FB2, PDF, DJVU, MOBI formats
|
||||
|
||||
**EPUB CFI Format:**
|
||||
- Standardized location format for EPUBs
|
||||
- Example: `epubcfi(/6/4/2:15)`
|
||||
- Identifies exact position even after reflow
|
||||
- Works across different devices/apps
|
||||
- Preserved after file modifications
|
||||
|
||||
**Book Identification:**
|
||||
- Primary: SHA-256 hash of book file
|
||||
- Universal: Same book = same UUID across devices
|
||||
- Format-agnostic: Works for any supported format
|
||||
- Case-sensitive: Hash must match exactly
|
||||
|
||||
**Use Cases:**
|
||||
- Real-time page turn sync
|
||||
- Progress backup
|
||||
- Cross-device continuity
|
||||
- Reading time tracking
|
||||
- Chapter completion detection
|
||||
data: "{\n \"books\": [\n {\n \"authors\": [\n \"Author Name\"\n ],\n \"chapter\": 3,\n \"character\": 15432,\n \"epubcfi\": \"epubcfi(/6/4/2:15)\",\n \"last_read\": \"2026-01-30T20:00:00Z\",\n \"percentage\": 0.45,\n \"progress\": 0.45,\n \"title\": \"Book Title\",\n \"uuid\": \"{{media_item_id}}\"\n }\n ],\n \"library_id\": \"optional-library-uuid\"\n}"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/progress'
|
||||
auth:
|
||||
type: bearer
|
||||
token: '{{koreader_device_token}}'
|
||||
info:
|
||||
name: Sync Progress - Single Book
|
||||
seq: 1
|
||||
type: http
|
||||
@@ -1,106 +1,19 @@
|
||||
info:
|
||||
name: Sync Progress - With Bookmarks
|
||||
type: http
|
||||
seq: 3
|
||||
|
||||
docs: "## Sync Progress with Bookmarks\n\nSynchronizes reading progress with bookmarks/highlights from KOReader.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/koreader/progress\n\n**Authentication:** Bearer token\n\n**Request Body:**\n- `library_id` (string, optional): Library UUID\n- `books` (array): Books with progress and bookmarks\n - `uuid`, `title`, `authors`, `progress`, etc.\n - `bookmarks` (array): Bookmark items\n - `chapter` (integer): Chapter number\n - `datetime` (string): ISO 8601 timestamp\n - `notes` (string): Note content or highlighted text\n - `pos0` (string): EPUB CFI start position\n - `pos1` (string): EPUB CFI end position\n - `page` (integer): Page number\n - `text` (string): Displayed text excerpt\n - `type` (string): `highlight`, `bookmark`, or `note`\n\n**Response:**\n- `progress_synced` (integer): Progress items synced\n- `bookmarks_synced` (integer): Bookmark items synced\n- `highlights_synced` (integer): Highlight count\n- `timestamp`\
|
||||
\ (string): Sync timestamp\n\n**KOReader Bookmark Types:**\n- **highlight**: Selected text passages\n- **bookmark**: Location markers\n- **note**: Text annotations (can be attached to highlights)\n\n**KOReader Highlight Features:**\n- Custom colors (via color extensions)\n- Multi-color support\n- Precise EPUB CFI positioning\n- Chapter-based organization\n- Text excerpts preserved\n- Date/time stamped\n- Page number tracking\n\n**EPUB CFI in Bookmarks:**\n- `pos0`: Start position (highlight start)\n- `pos1`: End position (highlight end)\n- Exact text selection boundaries\n- Survives text reflow\n- Works across different font sizes\n\n**Sync Behavior:**\n- Duplicate detection by text + position\n- Most recent edit wins\n- Chapter references maintained\n- Order preserved from device\n- Merges with existing server bookmarks\n\n**KOReader Device Integration:**\n- Created in KOReader highlight interface\n- Shows in \"Bookmarks\" menu\n- Can be edited/deleted on device\n- Exportable to JSON/XML\n\
|
||||
- Searchable by content\n\n**Use Cases:**\n- Study and research\n- Content review\n- Passage tracking\n- Quick navigation\n- Cross-device bookmark access"
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/progress'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
library_id: optional-library-uuid
|
||||
books:
|
||||
- uuid: book-uuid-here
|
||||
title: Book Title
|
||||
authors:
|
||||
- Author Name
|
||||
progress: 0.45
|
||||
percentage: 0.45
|
||||
last_read: '2026-01-30T20:00:00Z'
|
||||
bookmarks:
|
||||
- chapter: 3
|
||||
datetime: '2026-01-30T19:55:00Z'
|
||||
notes: highlighted text
|
||||
pos0: 'epubcfi(/6/4/2:15)'
|
||||
pos1: 'epubcfi(/6/4/2:20)'
|
||||
page: 45
|
||||
text: highlighted text excerpt
|
||||
type: highlight
|
||||
|
||||
docs: |-
|
||||
## Sync Progress with Bookmarks
|
||||
|
||||
Synchronizes reading progress with bookmarks/highlights from KOReader.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/koreader/progress
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Request Body:**
|
||||
- `library_id` (string, optional): Library UUID
|
||||
- `books` (array): Books with progress and bookmarks
|
||||
- `uuid`, `title`, `authors`, `progress`, etc.
|
||||
- `bookmarks` (array): Bookmark items
|
||||
- `chapter` (integer): Chapter number
|
||||
- `datetime` (string): ISO 8601 timestamp
|
||||
- `notes` (string): Note content or highlighted text
|
||||
- `pos0` (string): EPUB CFI start position
|
||||
- `pos1` (string): EPUB CFI end position
|
||||
- `page` (integer): Page number
|
||||
- `text` (string): Displayed text excerpt
|
||||
- `type` (string): `highlight`, `bookmark`, or `note`
|
||||
|
||||
**Response:**
|
||||
- `progress_synced` (integer): Progress items synced
|
||||
- `bookmarks_synced` (integer): Bookmark items synced
|
||||
- `highlights_synced` (integer): Highlight count
|
||||
- `timestamp` (string): Sync timestamp
|
||||
|
||||
**KOReader Bookmark Types:**
|
||||
- **highlight**: Selected text passages
|
||||
- **bookmark**: Location markers
|
||||
- **note**: Text annotations (can be attached to highlights)
|
||||
|
||||
**KOReader Highlight Features:**
|
||||
- Custom colors (via color extensions)
|
||||
- Multi-color support
|
||||
- Precise EPUB CFI positioning
|
||||
- Chapter-based organization
|
||||
- Text excerpts preserved
|
||||
- Date/time stamped
|
||||
- Page number tracking
|
||||
|
||||
**EPUB CFI in Bookmarks:**
|
||||
- `pos0`: Start position (highlight start)
|
||||
- `pos1`: End position (highlight end)
|
||||
- Exact text selection boundaries
|
||||
- Survives text reflow
|
||||
- Works across different font sizes
|
||||
|
||||
**Sync Behavior:**
|
||||
- Duplicate detection by text + position
|
||||
- Most recent edit wins
|
||||
- Chapter references maintained
|
||||
- Order preserved from device
|
||||
- Merges with existing server bookmarks
|
||||
|
||||
**KOReader Device Integration:**
|
||||
- Created in KOReader highlight interface
|
||||
- Shows in "Bookmarks" menu
|
||||
- Can be edited/deleted on device
|
||||
- Exportable to JSON/XML
|
||||
- Searchable by content
|
||||
|
||||
**Use Cases:**
|
||||
- Study and research
|
||||
- Content review
|
||||
- Passage tracking
|
||||
- Quick navigation
|
||||
- Cross-device bookmark access
|
||||
data: "{\n \"books\": [\n {\n \"authors\": [\n \"Author Name\"\n ],\n \"bookmarks\": [\n {\n \"chapter\": 3,\n \"datetime\": \"2026-01-30T19:55:00Z\",\n \"notes\": \"highlighted text\",\n \"page\": 45,\n \"pos0\": \"epubcfi(/6/4/2:15)\",\n \"pos1\": \"epubcfi(/6/4/2:20)\",\n \"text\": \"highlighted text excerpt\",\n \"type\": \"highlight\"\n }\n ],\n \"last_read\": \"2026-01-30T20:00:00Z\",\n \"percentage\": 0.45,\n \"progress\": 0.45,\n \"title\": \"Book Title\",\n \"uuid\": \"{{media_item_id}}\"\n }\n ],\n \"library_id\": \"optional-library-uuid\"\n}"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/progress'
|
||||
auth:
|
||||
type: bearer
|
||||
token: '{{koreader_device_token}}'
|
||||
info:
|
||||
name: Sync Progress - With Bookmarks
|
||||
seq: 3
|
||||
type: http
|
||||
@@ -1,117 +1,19 @@
|
||||
info:
|
||||
name: Sync Progress - With Highlights and Notes
|
||||
type: http
|
||||
seq: 4
|
||||
|
||||
docs: "## Sync Progress with Highlights and Notes\n\nSynchronizes reading progress with separate highlights and notes arrays.\n\n**Method:** POST\n\n**Endpoint:** /api/sync/koreader/progress\n\n**Authentication:** Bearer token\n\n**Request Body:**\n- `library_id` (string, optional): Library UUID\n- `books` (array): Books with progress and annotations\n - `uuid`, `title`, `authors`, `progress`, `percentage`, `last_read`\n - `highlights` (array): Text highlights\n - `datetime` (string): Creation timestamp\n - `text` (string): Highlighted text content\n - `chapter` (integer): Chapter number\n - `pos0` (string): EPUB CFI start\n - `pos1` (string): EPUB CFI end\n - `page_start` (integer): Start page\n - `page_end` (integer): End page\n - `color` (string, optional): Highlight color\n - `notes` (array): Notes\n - `datetime` (string): Creation timestamp\n - `text` (string): Note content\n - `chapter` (integer): Chapter number\n - `pos0` (string, optional):\
|
||||
\ Related position\n\n**Response:**\n- `progress_synced` (boolean): Progress sync status\n- `highlights_synced` (integer): Highlights synced\n- `notes_synced` (integer): Notes synced\n- `conflicts_resolved` (integer): Conflict count\n- `timestamp` (string): Sync timestamp\n\n**KOReader Annotation Model:**\n- **Separate arrays**: Highlights and notes stored separately\n- **Linked**: Notes can reference highlights\n- **Rich metadata**: Timestamps, positions, page numbers\n- **Flexible**: Supports complex annotations\n\n**Highlight Features:**\n- Multi-color highlighting (via plugins)\n- Precise text selection with EPUB CFI\n- Page range tracking\n- Chapter references\n- Timestamps for sorting\n- Full text preserved\n\n**Note Features:**\n- Free-form text notes\n- Can be standalone or attached\n- Chapter-based organization\n- Timestamped\n- Longer form than highlights\n- Support for markdown (some versions)\n\n**Color Support (via plugins):**\n- Yellow: Default highlight\n- Green: Important\
|
||||
\ passages\n- Blue: Key concepts\n- Red: Critical information\n- Orange: Interesting quotes\n- Custom colors available\n\n**Sync Advantages:**\n- Separation allows granular control\n- Highlights sync without notes\n- Notes sync independently\n- Better conflict resolution\n- Efficient for large annotation sets\n\n**Use Cases:**\n- Academic research\n- Study groups\n- Content analysis\n- Personal knowledge management\n- Sharing insights"
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/progress'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
library_id: optional-library-uuid
|
||||
books:
|
||||
- uuid: book-uuid-here
|
||||
title: Book Title
|
||||
authors:
|
||||
- Author Name
|
||||
progress: 0.6
|
||||
percentage: 0.6
|
||||
last_read: '2026-01-30T20:00:00Z'
|
||||
highlights:
|
||||
- datetime: '2026-01-30T19:50:00Z'
|
||||
text: Important passage
|
||||
chapter: 4
|
||||
pos0: 'epubcfi(/6/4/2:20)'
|
||||
pos1: 'epubcfi(/6/4/2:30)'
|
||||
page_start: 78
|
||||
page_end: 79
|
||||
notes:
|
||||
- datetime: '2026-01-30T19:52:00Z'
|
||||
text: My note about this chapter
|
||||
chapter: 4
|
||||
|
||||
docs: |-
|
||||
## Sync Progress with Highlights and Notes
|
||||
|
||||
Synchronizes reading progress with separate highlights and notes arrays.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/koreader/progress
|
||||
|
||||
**Authentication:** Bearer token
|
||||
|
||||
**Request Body:**
|
||||
- `library_id` (string, optional): Library UUID
|
||||
- `books` (array): Books with progress and annotations
|
||||
- `uuid`, `title`, `authors`, `progress`, `percentage`, `last_read`
|
||||
- `highlights` (array): Text highlights
|
||||
- `datetime` (string): Creation timestamp
|
||||
- `text` (string): Highlighted text content
|
||||
- `chapter` (integer): Chapter number
|
||||
- `pos0` (string): EPUB CFI start
|
||||
- `pos1` (string): EPUB CFI end
|
||||
- `page_start` (integer): Start page
|
||||
- `page_end` (integer): End page
|
||||
- `color` (string, optional): Highlight color
|
||||
- `notes` (array): Notes
|
||||
- `datetime` (string): Creation timestamp
|
||||
- `text` (string): Note content
|
||||
- `chapter` (integer): Chapter number
|
||||
- `pos0` (string, optional): Related position
|
||||
|
||||
**Response:**
|
||||
- `progress_synced` (boolean): Progress sync status
|
||||
- `highlights_synced` (integer): Highlights synced
|
||||
- `notes_synced` (integer): Notes synced
|
||||
- `conflicts_resolved` (integer): Conflict count
|
||||
- `timestamp` (string): Sync timestamp
|
||||
|
||||
**KOReader Annotation Model:**
|
||||
- **Separate arrays**: Highlights and notes stored separately
|
||||
- **Linked**: Notes can reference highlights
|
||||
- **Rich metadata**: Timestamps, positions, page numbers
|
||||
- **Flexible**: Supports complex annotations
|
||||
|
||||
**Highlight Features:**
|
||||
- Multi-color highlighting (via plugins)
|
||||
- Precise text selection with EPUB CFI
|
||||
- Page range tracking
|
||||
- Chapter references
|
||||
- Timestamps for sorting
|
||||
- Full text preserved
|
||||
|
||||
**Note Features:**
|
||||
- Free-form text notes
|
||||
- Can be standalone or attached
|
||||
- Chapter-based organization
|
||||
- Timestamped
|
||||
- Longer form than highlights
|
||||
- Support for markdown (some versions)
|
||||
|
||||
**Color Support (via plugins):**
|
||||
- Yellow: Default highlight
|
||||
- Green: Important passages
|
||||
- Blue: Key concepts
|
||||
- Red: Critical information
|
||||
- Orange: Interesting quotes
|
||||
- Custom colors available
|
||||
|
||||
**Sync Advantages:**
|
||||
- Separation allows granular control
|
||||
- Highlights sync without notes
|
||||
- Notes sync independently
|
||||
- Better conflict resolution
|
||||
- Efficient for large annotation sets
|
||||
|
||||
**Use Cases:**
|
||||
- Academic research
|
||||
- Study groups
|
||||
- Content analysis
|
||||
- Personal knowledge management
|
||||
- Sharing insights
|
||||
data: "{\n \"books\": [\n {\n \"authors\": [\n \"Author Name\"\n ],\n \"highlights\": [\n {\n \"chapter\": 4,\n \"datetime\": \"2026-01-30T19:50:00Z\",\n \"page_end\": 79,\n \"page_start\": 78,\n \"pos0\": \"epubcfi(/6/4/2:20)\",\n \"pos1\": \"epubcfi(/6/4/2:30)\",\n \"text\": \"Important passage\"\n }\n ],\n \"last_read\": \"2026-01-30T20:00:00Z\",\n \"notes\": [\n {\n \"chapter\": 4,\n \"datetime\": \"2026-01-30T19:52:00Z\",\n \"text\": \"My note about this chapter\"\n }\n ],\n \"percentage\": 0.6,\n \"progress\": 0.6,\n \"title\": \"Book Title\",\n \"uuid\": \"{{media_item_id}}\"\n }\n ],\n \"library_id\": \"optional-library-uuid\"\n}"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/progress'
|
||||
auth:
|
||||
type: bearer
|
||||
token: '{{koreader_device_token}}'
|
||||
info:
|
||||
name: Sync Progress - With Highlights and Notes
|
||||
seq: 4
|
||||
type: http
|
||||
@@ -1,53 +1,16 @@
|
||||
info:
|
||||
name: KOReader Sync Progress
|
||||
type: http
|
||||
seq: 1
|
||||
docs: "## KOReader Sync Progress\n\n Synchronizes reading progress from a KOReader device to the Bookhoard server.\n\n **Method:** POST\n\n **Endpoint:** /api/sync/koreader/progress\n\n **Authentication:** Bearer token (device token)\n\n **Request Body:**\n - `library_id` (string, optional): Library UUID\n - `books` (array): Array of book progress objects\n - `uuid` (string): Book UUID\n - `title` (string): Book title\n - `authors` (array): List of authors\n - `progress` (number): Progress value\n - `percentage` (number): Percentage complete (0-1)\n - `last_read` (string): ISO 8601 timestamp\n - `chapter` (number): Current chapter\n - `epubcfi` (string): EPUB Canonical Fragment Identifier\n - `page` (number): Current page\n - `total_pages` (number): Total pages\n - `sync_mode` (string): Sync mode (immediate, deferred)\n - `device_info` (object): Device information\n - `koreader_version` (string): KOReader version\n - `device_model` (string): Device\
|
||||
\ model identifier\n\n **Response:**\n - `sync_status` (string): Sync status (accepted, processing)\n - `books_synced` (number): Number of books synced\n\n **Status Codes:**\n - 202: Accepted - sync queued\n - 401: Unauthorized\n - 500: Internal server error"
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/progress'
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"library_id\": null,\n \"books\": [\n {\n \"\
|
||||
uuid\": \"{{book_uuid"
|
||||
headers:
|
||||
- key: Authorization
|
||||
value: Bearer {{device_token
|
||||
|
||||
docs: |-
|
||||
## KOReader Sync Progress
|
||||
|
||||
Synchronizes reading progress from a KOReader device to the Bookhoard server.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/sync/koreader/progress
|
||||
|
||||
**Authentication:** Bearer token (device token)
|
||||
|
||||
**Request Body:**
|
||||
- `library_id` (string, optional): Library UUID
|
||||
- `books` (array): Array of book progress objects
|
||||
- `uuid` (string): Book UUID
|
||||
- `title` (string): Book title
|
||||
- `authors` (array): List of authors
|
||||
- `progress` (number): Progress value
|
||||
- `percentage` (number): Percentage complete (0-1)
|
||||
- `last_read` (string): ISO 8601 timestamp
|
||||
- `chapter` (number): Current chapter
|
||||
- `epubcfi` (string): EPUB Canonical Fragment Identifier
|
||||
- `page` (number): Current page
|
||||
- `total_pages` (number): Total pages
|
||||
- `sync_mode` (string): Sync mode (immediate, deferred)
|
||||
- `device_info` (object): Device information
|
||||
- `koreader_version` (string): KOReader version
|
||||
- `device_model` (string): Device model identifier
|
||||
|
||||
**Response:**
|
||||
- `sync_status` (string): Sync status (accepted, processing)
|
||||
- `books_synced` (number): Number of books synced
|
||||
|
||||
**Status Codes:**
|
||||
- 202: Accepted - sync queued
|
||||
- 401: Unauthorized
|
||||
- 500: Internal server error
|
||||
data: "{\n \"sync_mode\": \"immediate\",\n \"books\": [\n {\n \"uuid\": \"{{media_item_id}}\",\n \"percentage\": 0.45,\n \"chapter\": 3\n }\n ]\n}"
|
||||
headers: []
|
||||
method: POST
|
||||
url: '{{base_url}}/api/sync/koreader/progress'
|
||||
auth:
|
||||
type: bearer
|
||||
token: '{{koreader_device_token}}'
|
||||
info:
|
||||
name: KOReader Sync Progress
|
||||
seq: 1
|
||||
type: http
|
||||
@@ -8,16 +8,8 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"media_item_ids\": [\n \"{{bookUUID1"
|
||||
data: "{\n \"media_item_ids\": [\n \"{{bookUUID1"
|
||||
headers:
|
||||
- key: Authorization
|
||||
value: Bearer {{userToken
|
||||
|
||||
docs: |-
|
||||
## Add Books to Kobo Shelf
|
||||
|
||||
Add one or more books to a Kobo device shelf. Manages which books should be synced to a specific Kobo device. Supports multiple shelves for organization.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/devices/{deviceID
|
||||
docs: "## Add Books to Kobo Shelf\n\n Add one or more books to a Kobo device shelf. Manages which books should be synced to a specific Kobo device. Supports multiple shelves for organization.\n\n **Method:** POST\n\n **Endpoint:** /api/devices/{deviceID"
|
||||
@@ -2,51 +2,15 @@ info:
|
||||
name: Check Pending Registration
|
||||
type: http
|
||||
seq: 4
|
||||
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/devices/register/status'
|
||||
auth: none
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
registration_id: registration-uuid-here
|
||||
|
||||
docs: |-
|
||||
## Check Registration Status
|
||||
|
||||
Checks the current status of a device registration request.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/devices/register/status
|
||||
|
||||
**Authentication:** None
|
||||
|
||||
**Request Body:**
|
||||
- `registration_id` (string): UUID received from registration request
|
||||
|
||||
**Response:**
|
||||
- `registration_id` (string): The registration UUID
|
||||
- `status` (string): Current status
|
||||
- `pending`: Awaiting user approval
|
||||
- `approved`: Registration approved, device ready
|
||||
- `rejected`: Registration rejected by user
|
||||
- `expired`: Registration expired (not approved in time)
|
||||
- `device_name` (string): Name of the device
|
||||
- `device_type` (string): Type of device
|
||||
- `created_at` (string): Registration timestamp
|
||||
- `updated_at` (string): Last status update timestamp
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Status retrieved successfully
|
||||
- 404: Registration ID not found
|
||||
- 400: Invalid registration ID format
|
||||
|
||||
**Polling Recommendations:**
|
||||
- Poll every 5-10 seconds while status is `pending`
|
||||
- Stop polling when status changes to `approved`, `rejected`, or `expired`
|
||||
- Use exponential backoff for mobile devices to save battery
|
||||
data: "{\n \"registration_id\": \"registration-uuid-here\"\n}"
|
||||
docs: "## Check Registration Status\n\nChecks the current status of a device registration request.\n\n**Method:** POST\n\n**Endpoint:** /api/devices/register/status\n\n**Authentication:** None\n\n**Request Body:**\n- `registration_id` (string): UUID received from registration request\n\n**Response:**\n- `registration_id` (string): The registration UUID\n- `status` (string): Current status\n - `pending`: Awaiting user approval\n - `approved`: Registration approved, device ready\n - `rejected`: Registration rejected by user\n - `expired`: Registration expired (not approved in time)\n- `device_name` (string): Name of the device\n- `device_type` (string): Type of device\n- `created_at` (string): Registration timestamp\n- `updated_at` (string): Last status update timestamp\n\n**Status Codes:**\n- 200: Status retrieved successfully\n- 404: Registration ID not found\n- 400: Invalid registration ID format\n\n**Polling Recommendations:**\n- Poll every 5-10 seconds while status is `pending`\n\
|
||||
- Stop polling when status changes to `approved`, `rejected`, or `expired`\n- Use exponential backoff for mobile devices to save battery"
|
||||
@@ -8,30 +8,5 @@ http:
|
||||
auth: none
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"registration_id\": \"{{registrationId}}"
|
||||
|
||||
docs: |-
|
||||
## Check Registration Status
|
||||
|
||||
Checks the current status of a device registration request.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/devices/register/status
|
||||
|
||||
**Authentication:** None
|
||||
|
||||
**Request Body:**
|
||||
- `registration_id` (string, required): Registration request ID
|
||||
|
||||
**Response:**
|
||||
- `status` (string): Registration status (pending, approved, rejected, expired)
|
||||
- `device_name` (string): Device name
|
||||
- `device_type` (string): Device type
|
||||
- `created_at` (string): Request timestamp
|
||||
- `expires_at` (string): Expiration timestamp
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 404: Registration ID not found
|
||||
- 410: Registration expired
|
||||
data: "{\n \"registration_id\": \"{{registrationId}}"
|
||||
docs: "## Check Registration Status\n\n Checks the current status of a device registration request.\n\n **Method:** POST\n\n **Endpoint:** /api/devices/register/status\n\n **Authentication:** None\n\n **Request Body:**\n - `registration_id` (string, required): Registration request ID\n\n **Response:**\n - `status` (string): Registration status (pending, approved, rejected, expired)\n - `device_name` (string): Device name\n - `device_type` (string): Device type\n - `created_at` (string): Request timestamp\n - `expires_at` (string): Expiration timestamp\n\n **Status Codes:**\n - 200: Success\n - 404: Registration ID not found\n - 410: Registration expired"
|
||||
@@ -8,48 +8,12 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"file_path\": \"/mnt/sd/books/my-book.kepub.epub\",\n \"\
|
||||
media_item_id\": \"{{media_item_id"
|
||||
data: "{\n \"file_path\": \"/mnt/sd/books/my-book.kepub.epub\",\n \"media_item_id\": \"{{media_item_id"
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
runtime:
|
||||
scripts:
|
||||
- type: tests
|
||||
code: "test_create_device_file_alias_success(status, headers, body) {\n if\
|
||||
\ (status !== 201 && status !== 200) {\n throw new Error(\"Expected status\
|
||||
\ 201 or 200, got \" + status);"
|
||||
|
||||
docs: |-
|
||||
## Create Device File Alias
|
||||
|
||||
Creates a new file alias for a device. File aliases map device-specific file paths to media items.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/devices/:id/file-aliases
|
||||
|
||||
**Authentication:** Required (Bearer token)
|
||||
|
||||
**Path Parameters:**
|
||||
- `id` (string, required): Device UUID
|
||||
|
||||
**Request Body:**
|
||||
- `file_path` (string, required): Device-specific file path
|
||||
- `media_item_id` (string, required): Media item UUID to link to
|
||||
|
||||
**Response:** Created file alias object
|
||||
- `id` (string): Alias UUID
|
||||
- `device_id` (string): Device UUID
|
||||
- `file_path` (string): Device-specific file path
|
||||
- `media_item_id` (string): Associated media item UUID
|
||||
- `created_at` (string): Creation timestamp
|
||||
- `updated_at` (string): Last update timestamp
|
||||
|
||||
**Status Codes:**
|
||||
- 201: Created
|
||||
- 200: Success
|
||||
- 400: Invalid request body
|
||||
- 401: Unauthorized
|
||||
- 404: Device not found
|
||||
- 500: Internal server error
|
||||
code: "test_create_device_file_alias_success(status, headers, body) {\n if (status !== 201 && status !== 200) {\n throw new Error(\"Expected status 201 or 200, got \" + status);"
|
||||
docs: "## Create Device File Alias\n\n Creates a new file alias for a device. File aliases map device-specific file paths to media items.\n\n **Method:** POST\n\n **Endpoint:** /api/devices/:id/file-aliases\n\n **Authentication:** Required (Bearer token)\n\n **Path Parameters:**\n - `id` (string, required): Device UUID\n\n **Request Body:**\n - `file_path` (string, required): Device-specific file path\n - `media_item_id` (string, required): Media item UUID to link to\n\n **Response:** Created file alias object\n - `id` (string): Alias UUID\n - `device_id` (string): Device UUID\n - `file_path` (string): Device-specific file path\n - `media_item_id` (string): Associated media item UUID\n - `created_at` (string): Creation timestamp\n - `updated_at` (string): Last update timestamp\n\n **Status Codes:**\n - 201: Created\n - 200: Success\n - 400: Invalid request body\n - 401: Unauthorized\n - 404: Device not found\n - 500: Internal server error"
|
||||
@@ -2,57 +2,77 @@ info:
|
||||
name: Disable Device Sync
|
||||
type: http
|
||||
seq: 8
|
||||
|
||||
http:
|
||||
method: PUT
|
||||
url: '{{base_url}}/api/devices/{{device_id}}'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
device_name: My Kobo Clara
|
||||
sync_enabled: false
|
||||
auto_sync: false
|
||||
sync_frequency_minutes: 30
|
||||
data: "{\n \"device_name\": \"My Kobo Clara\",\n \"sync_enabled\": false,\n \"auto_sync\": false,\n \"sync_frequency_minutes\": 30\n}"
|
||||
docs: '## Disable Device Sync
|
||||
|
||||
docs: |-
|
||||
## Disable Device Sync
|
||||
|
||||
Disables synchronization for a specific device.
|
||||
|
||||
|
||||
**Method:** PUT
|
||||
|
||||
|
||||
**Endpoint:** /api/devices/:device_id
|
||||
|
||||
|
||||
**Authentication:** Required (Bearer token)
|
||||
|
||||
|
||||
**Path Parameters:**
|
||||
|
||||
- `device_id` (string): UUID of the device
|
||||
|
||||
|
||||
**Request Body:**
|
||||
|
||||
- `device_name` (string, optional): Device name
|
||||
|
||||
- `sync_enabled` (boolean): Must be `false`
|
||||
|
||||
- `auto_sync` (boolean): Should be `false`
|
||||
|
||||
- `sync_frequency_minutes` (integer, optional): Any value (sync disabled)
|
||||
|
||||
|
||||
**Response:**
|
||||
|
||||
- `id` (string): Device UUID
|
||||
|
||||
- `device_name` (string): Device name
|
||||
|
||||
- `sync_enabled` (boolean): `false`
|
||||
|
||||
- `auto_sync` (boolean): `false`
|
||||
|
||||
- `message` (string): Confirmation message
|
||||
|
||||
|
||||
**Status Codes:**
|
||||
|
||||
- 200: Sync disabled successfully
|
||||
|
||||
- 401: Unauthorized
|
||||
|
||||
- 403: Forbidden
|
||||
|
||||
- 404: Device not found
|
||||
|
||||
|
||||
**Use Cases:**
|
||||
|
||||
- Temporarily disable sync for troubleshooting
|
||||
|
||||
- Stop sync for a lost or stolen device
|
||||
|
||||
- Disable sync before selling or giving away device
|
||||
- Prevent data usage on limited connections
|
||||
|
||||
- Prevent data usage on limited connections'
|
||||
@@ -8,32 +8,5 @@ http:
|
||||
auth: none
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"device_name\": \"My Kindle Paperwhite\",\n \"device_type\"\
|
||||
: \"koreader\",\n \"device_identifier\": \"kindle-pw5-hardware-id-12345\""
|
||||
|
||||
docs: |-
|
||||
## Initiate Device Registration
|
||||
|
||||
Initiates a new device registration request that requires admin approval.
|
||||
|
||||
**Method:** POST
|
||||
|
||||
**Endpoint:** /api/devices/register
|
||||
|
||||
**Authentication:** None (open endpoint)
|
||||
|
||||
**Request Body:**
|
||||
- `device_name` (string, required): Human-readable device name (max 100 chars)
|
||||
- `device_type` (string, required): Device type (kobo, koreader, kindle, etc.)
|
||||
- `device_identifier` (string, required): Unique hardware ID (max 200 chars)
|
||||
|
||||
**Response:**
|
||||
- `registration_id` (string): Unique registration request ID
|
||||
- `status` (string): Initial status (pending)
|
||||
- `expires_at` (string): Expiration timestamp (usually 24 hours)
|
||||
- `message` (string): Informational message
|
||||
|
||||
**Status Codes:**
|
||||
- 201: Registration initiated
|
||||
- 400: Invalid request
|
||||
- 409: Device already registered
|
||||
data: "{\n \"device_name\": \"My Kindle Paperwhite\",\n \"device_type\": \"koreader\",\n \"device_identifier\": \"kindle-pw5-hardware-id-12345\""
|
||||
docs: "## Initiate Device Registration\n\n Initiates a new device registration request that requires admin approval.\n\n **Method:** POST\n\n **Endpoint:** /api/devices/register\n\n **Authentication:** None (open endpoint)\n\n **Request Body:**\n - `device_name` (string, required): Human-readable device name (max 100 chars)\n - `device_type` (string, required): Device type (kobo, koreader, kindle, etc.)\n - `device_identifier` (string, required): Unique hardware ID (max 200 chars)\n\n **Response:**\n - `registration_id` (string): Unique registration request ID\n - `status` (string): Initial status (pending)\n - `expires_at` (string): Expiration timestamp (usually 24 hours)\n - `message` (string): Informational message\n\n **Status Codes:**\n - 201: Registration initiated\n - 400: Invalid request\n - 409: Device already registered"
|
||||
@@ -2,48 +2,62 @@ info:
|
||||
name: Register Device
|
||||
type: http
|
||||
seq: 1
|
||||
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/devices/register'
|
||||
auth: none
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
device_name: My Kobo Clara
|
||||
device_type: kobo
|
||||
device_identifier: N1234567890123
|
||||
data: "{\n \"device_name\": \"My Kobo Clara\",\n \"device_type\": \"kobo\",\n \"device_identifier\": \"N1234567890123\"\n}"
|
||||
docs: '## Register Device
|
||||
|
||||
docs: |-
|
||||
## Register Device
|
||||
|
||||
Initiates device registration by sending device information to the server.
|
||||
|
||||
|
||||
**Method:** POST
|
||||
|
||||
|
||||
**Endpoint:** /api/devices/register
|
||||
|
||||
|
||||
**Authentication:** None (public endpoint)
|
||||
|
||||
|
||||
**Request Body:**
|
||||
|
||||
- `device_name` (string): Human-readable name for the device
|
||||
|
||||
- `device_type` (string): Type of device - `kobo`, `koreader`, or `web`
|
||||
|
||||
- `device_identifier` (string): Unique device identifier (serial number or other ID)
|
||||
|
||||
|
||||
**Response:**
|
||||
|
||||
- `registration_id` (string): UUID for tracking registration status
|
||||
|
||||
- `status` (string): Registration status - `pending`, `approved`, or `rejected`
|
||||
|
||||
- `message` (string): Status message
|
||||
|
||||
|
||||
**Status Codes:**
|
||||
|
||||
- 201: Registration initiated successfully
|
||||
|
||||
- 400: Invalid request data
|
||||
|
||||
- 409: Device already registered
|
||||
|
||||
|
||||
**Notes:**
|
||||
|
||||
- Device registration requires user approval before activation
|
||||
|
||||
- Registration ID should be stored for status checking
|
||||
- Device identifier must be unique per device
|
||||
|
||||
- Device identifier must be unique per device'
|
||||
@@ -2,47 +2,60 @@ info:
|
||||
name: Register KOReader Device
|
||||
type: http
|
||||
seq: 2
|
||||
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/devices/register'
|
||||
auth: none
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
device_name: My Kindle Paperwhite
|
||||
device_type: koreader
|
||||
device_identifier: G090GP123456789
|
||||
data: "{\n \"device_name\": \"My Kindle Paperwhite\",\n \"device_type\": \"koreader\",\n \"device_identifier\": \"G090GP123456789\"\n}"
|
||||
docs: '## Register KOReader Device
|
||||
|
||||
docs: |-
|
||||
## Register KOReader Device
|
||||
|
||||
Registers a KOReader device (typically Kindle devices running KOReader software).
|
||||
|
||||
|
||||
**Method:** POST
|
||||
|
||||
|
||||
**Endpoint:** /api/devices/register
|
||||
|
||||
|
||||
**Authentication:** None (public endpoint)
|
||||
|
||||
|
||||
**Request Body:**
|
||||
|
||||
- `device_name` (string): Human-readable name for the device
|
||||
|
||||
- `device_type` (string): Must be `koreader`
|
||||
|
||||
- `device_identifier` (string): Kindle serial number or unique device ID
|
||||
|
||||
|
||||
**Response:**
|
||||
|
||||
- `registration_id` (string): UUID for tracking registration status
|
||||
|
||||
- `status` (string): Registration status - `pending`
|
||||
|
||||
- `message` (string): Confirmation message
|
||||
|
||||
|
||||
**Status Codes:**
|
||||
|
||||
- 201: Registration initiated
|
||||
|
||||
- 400: Invalid device type or data
|
||||
|
||||
|
||||
**KOReader Notes:**
|
||||
|
||||
- KOReader runs on Kindle, Kobo, PocketBook, and Android devices
|
||||
|
||||
- Device identifier is typically the device serial number
|
||||
- Supports bookmarks, progress, highlights, and annotations sync
|
||||
|
||||
- Supports bookmarks, progress, highlights, and annotations sync'
|
||||
@@ -2,48 +2,62 @@ info:
|
||||
name: Register Web Device
|
||||
type: http
|
||||
seq: 3
|
||||
|
||||
http:
|
||||
method: POST
|
||||
url: '{{base_url}}/api/devices/register'
|
||||
auth: none
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
device_name: Chrome Browser
|
||||
device_type: web
|
||||
device_identifier: web-client-abc123
|
||||
data: "{\n \"device_name\": \"Chrome Browser\",\n \"device_type\": \"web\",\n \"device_identifier\": \"web-client-abc123\"\n}"
|
||||
docs: '## Register Web Device
|
||||
|
||||
docs: |-
|
||||
## Register Web Device
|
||||
|
||||
Registers a web browser client for reading progress sync.
|
||||
|
||||
|
||||
**Method:** POST
|
||||
|
||||
|
||||
**Endpoint:** /api/devices/register
|
||||
|
||||
|
||||
**Authentication:** None (public endpoint)
|
||||
|
||||
|
||||
**Request Body:**
|
||||
|
||||
- `device_name` (string): Browser identification (e.g., "Chrome Browser")
|
||||
|
||||
- `device_type` (string): Must be `web`
|
||||
|
||||
- `device_identifier` (string): Unique browser/client identifier
|
||||
|
||||
|
||||
**Response:**
|
||||
|
||||
- `registration_id` (string): UUID for tracking
|
||||
|
||||
- `status` (string): `pending` or `auto-approved`
|
||||
|
||||
- `message` (string): Status message
|
||||
|
||||
|
||||
**Status Codes:**
|
||||
|
||||
- 201: Registration successful
|
||||
|
||||
- 400: Invalid request
|
||||
|
||||
|
||||
**Web Device Notes:**
|
||||
|
||||
- Web devices use localStorage for device identification
|
||||
|
||||
- May be auto-approved without admin intervention
|
||||
|
||||
- Used for browser-based reading progress tracking
|
||||
- Supports manual progress updates, highlights, and notes
|
||||
|
||||
- Supports manual progress updates, highlights, and notes'
|
||||
@@ -2,60 +2,83 @@ info:
|
||||
name: Update Device Settings
|
||||
type: http
|
||||
seq: 7
|
||||
|
||||
http:
|
||||
method: PUT
|
||||
url: '{{base_url}}/api/devices/{{device_id}}'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
device_name: Updated Device Name
|
||||
sync_enabled: true
|
||||
auto_sync: true
|
||||
sync_frequency_minutes: 10
|
||||
data: "{\n \"device_name\": \"Updated Device Name\",\n \"sync_enabled\": true,\n \"auto_sync\": true,\n \"sync_frequency_minutes\": 10\n}"
|
||||
docs: '## Update Device Settings
|
||||
|
||||
docs: |-
|
||||
## Update Device Settings
|
||||
|
||||
Updates device configuration and sync settings.
|
||||
|
||||
|
||||
**Method:** PUT
|
||||
|
||||
|
||||
**Endpoint:** /api/devices/:device_id
|
||||
|
||||
|
||||
**Authentication:** Required (Bearer token)
|
||||
|
||||
|
||||
**Path Parameters:**
|
||||
|
||||
- `device_id` (string): UUID of the device
|
||||
|
||||
|
||||
**Request Body:**
|
||||
|
||||
- `device_name` (string, optional): New device name
|
||||
|
||||
- `sync_enabled` (boolean, optional): Enable/disable sync
|
||||
|
||||
- `auto_sync` (boolean, optional): Enable automatic sync
|
||||
|
||||
- `sync_frequency_minutes` (integer, optional): Sync interval (5-1440 minutes)
|
||||
|
||||
|
||||
**Response:**
|
||||
|
||||
- `id` (string): Device UUID
|
||||
|
||||
- `device_name` (string): Updated device name
|
||||
|
||||
- `sync_enabled` (boolean): Updated sync status
|
||||
|
||||
- `auto_sync` (boolean): Updated auto-sync setting
|
||||
|
||||
- `sync_frequency_minutes` (integer): Updated sync interval
|
||||
|
||||
- `updated_at` (string): Update timestamp
|
||||
|
||||
|
||||
**Status Codes:**
|
||||
|
||||
- 200: Settings updated successfully
|
||||
|
||||
- 400: Invalid sync frequency or data
|
||||
|
||||
- 401: Unauthorized
|
||||
|
||||
- 403: Forbidden (device belongs to different user)
|
||||
|
||||
- 404: Device not found
|
||||
|
||||
|
||||
**Sync Frequency Guidelines:**
|
||||
|
||||
- Mobile devices: 10-30 minutes
|
||||
|
||||
- E-readers on WiFi: 15-60 minutes
|
||||
|
||||
- Web clients: 5-15 minutes
|
||||
|
||||
- Minimum: 5 minutes
|
||||
- Maximum: 1440 minutes (24 hours)
|
||||
|
||||
- Maximum: 1440 minutes (24 hours)'
|
||||
@@ -8,35 +8,5 @@ http:
|
||||
auth: inherit
|
||||
body:
|
||||
type: json
|
||||
jsonBody: "{\n \"device_name\": \"My Updated Kindle\",\n \"sync_enabled\"\
|
||||
: true,\n \"auto_sync\": true,\n \"sync_frequency_minutes\": 10"
|
||||
|
||||
docs: |-
|
||||
## Update Device
|
||||
|
||||
Updates device settings and synchronization preferences.
|
||||
|
||||
**Method:** PUT
|
||||
|
||||
**Endpoint:** /api/devices/{device_id}
|
||||
|
||||
**Authentication:** Required (Bearer token, admin or device owner)
|
||||
|
||||
**Path Parameters:**
|
||||
- `device_id` (string): Device ID
|
||||
|
||||
**Request Body:**
|
||||
- `device_name` (string, optional): New device name (max 100 chars)
|
||||
- `sync_enabled` (boolean, optional): Enable/disable synchronization
|
||||
- `auto_sync` (boolean, optional): Enable automatic synchronization
|
||||
- `sync_frequency_minutes` (integer, optional): Sync frequency in minutes (5-1440)
|
||||
|
||||
**Response:**
|
||||
- Updated device object
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 400: Invalid request
|
||||
- 401: Unauthorized
|
||||
- 403: Forbidden (not device owner)
|
||||
- 404: Device not found
|
||||
data: "{\n \"device_name\": \"My Updated Kindle\",\n \"sync_enabled\": true,\n \"auto_sync\": true,\n \"sync_frequency_minutes\": 10"
|
||||
docs: "## Update Device\n\n Updates device settings and synchronization preferences.\n\n **Method:** PUT\n\n **Endpoint:** /api/devices/{device_id}\n\n **Authentication:** Required (Bearer token, admin or device owner)\n\n **Path Parameters:**\n - `device_id` (string): Device ID\n\n **Request Body:**\n - `device_name` (string, optional): New device name (max 100 chars)\n - `sync_enabled` (boolean, optional): Enable/disable synchronization\n - `auto_sync` (boolean, optional): Enable automatic synchronization\n - `sync_frequency_minutes` (integer, optional): Sync frequency in minutes (5-1440)\n\n **Response:**\n - Updated device object\n\n **Status Codes:**\n - 200: Success\n - 400: Invalid request\n - 401: Unauthorized\n - 403: Forbidden (not device owner)\n - 404: Device not found"
|
||||
@@ -2,65 +2,92 @@ info:
|
||||
name: Update Sync Frequency
|
||||
type: http
|
||||
seq: 9
|
||||
|
||||
http:
|
||||
method: PUT
|
||||
url: '{{base_url}}/api/devices/{{device_id}}'
|
||||
auth: inherit
|
||||
headers:
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
- key: Content-Type
|
||||
value: application/json
|
||||
body:
|
||||
type: json
|
||||
json:
|
||||
device_name: My Kobo Clara
|
||||
sync_enabled: true
|
||||
auto_sync: true
|
||||
sync_frequency_minutes: 15
|
||||
data: "{\n \"device_name\": \"My Kobo Clara\",\n \"sync_enabled\": true,\n \"auto_sync\": true,\n \"sync_frequency_minutes\": 15\n}"
|
||||
docs: '## Update Sync Frequency
|
||||
|
||||
docs: |-
|
||||
## Update Sync Frequency
|
||||
|
||||
Changes how often the device automatically syncs with the server.
|
||||
|
||||
|
||||
**Method:** PUT
|
||||
|
||||
|
||||
**Endpoint:** /api/devices/:device_id
|
||||
|
||||
|
||||
**Authentication:** Required (Bearer token)
|
||||
|
||||
|
||||
**Path Parameters:**
|
||||
|
||||
- `device_id` (string): UUID of the device
|
||||
|
||||
|
||||
**Request Body:**
|
||||
|
||||
- `device_name` (string, optional): Device name
|
||||
|
||||
- `sync_enabled` (boolean): Must be `true` for auto-sync
|
||||
|
||||
- `auto_sync` (boolean): Must be `true`
|
||||
|
||||
- `sync_frequency_minutes` (integer): New sync interval (5-1440)
|
||||
|
||||
|
||||
**Response:**
|
||||
|
||||
- `id` (string): Device UUID
|
||||
|
||||
- `sync_enabled` (boolean): `true`
|
||||
|
||||
- `auto_sync` (boolean): `true`
|
||||
|
||||
- `sync_frequency_minutes` (integer): Updated interval
|
||||
|
||||
- `next_sync_at` (string): Estimated next sync time
|
||||
|
||||
- `updated_at` (string): Update timestamp
|
||||
|
||||
|
||||
**Status Codes:**
|
||||
|
||||
- 200: Frequency updated successfully
|
||||
|
||||
- 400: Invalid frequency value
|
||||
|
||||
- 401: Unauthorized
|
||||
|
||||
- 403: Forbidden
|
||||
|
||||
- 404: Device not found
|
||||
|
||||
|
||||
**Recommended Frequencies:**
|
||||
|
||||
- **Active reading:** 5-10 minutes
|
||||
|
||||
- **Normal usage:** 15-30 minutes
|
||||
|
||||
- **Occasional reading:** 30-60 minutes
|
||||
|
||||
- **Battery saving:** 60+ minutes
|
||||
|
||||
- **WiFi only (3G):** 30-60 minutes
|
||||
|
||||
|
||||
**Notes:**
|
||||
|
||||
- More frequent sync = more battery usage
|
||||
|
||||
- Sync only occurs when device is online
|
||||
- Manual sync can be triggered anytime regardless of frequency
|
||||
|
||||
- Manual sync can be triggered anytime regardless of frequency'
|
||||
@@ -23,7 +23,7 @@ variables:
|
||||
- name: library_folder
|
||||
value: /app/uploads
|
||||
- name: opds_base_url
|
||||
value: ""
|
||||
value: http://localhost:8765/opds
|
||||
- secret: true
|
||||
name: token
|
||||
- secret: true
|
||||
@@ -40,3 +40,7 @@ variables:
|
||||
name: comic_library_id
|
||||
- secret: true
|
||||
name: manga_library_id
|
||||
- secret: true
|
||||
name: book_sha256
|
||||
- secret: true
|
||||
name: book_uuid
|
||||
@@ -1,52 +0,0 @@
|
||||
meta:
|
||||
name: Browse library folders
|
||||
type: http
|
||||
seq: 1
|
||||
config:
|
||||
test:
|
||||
filter: "response.status == 200"
|
||||
assertions:
|
||||
- type: stddev
|
||||
target: response_time
|
||||
threshold: 1000
|
||||
- type: jsonpath
|
||||
expression: response.directories
|
||||
condition: exists
|
||||
- type: jsonpath
|
||||
expression: response.current_path
|
||||
condition: exists
|
||||
- type: jsonpath
|
||||
expression: response.parent_path
|
||||
condition: exists
|
||||
req:
|
||||
method: GET
|
||||
url: "{{base_url}}/api/libraries/browse?path=/tmp"
|
||||
headers:
|
||||
Authorization: "Bearer {{ADMIN_TOKEN}}"
|
||||
|
||||
docs: |-
|
||||
## Browse Library Folders
|
||||
|
||||
Navigates through the filesystem to browse folders for library configuration.
|
||||
|
||||
**Method:** GET
|
||||
|
||||
**Endpoint:** /api/libraries/browse
|
||||
|
||||
**Authentication:** Required (Bearer token, Admin only)
|
||||
|
||||
**Query Parameters:**
|
||||
- `path` (string, required): Filesystem path to browse
|
||||
|
||||
**Response:**
|
||||
- `current_path` (string): Current browsing path
|
||||
- `parent_path` (string): Parent directory path
|
||||
- `directories` (array): List of subdirectories
|
||||
- `files` (array): List of files (optional)
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 400: Invalid path
|
||||
- 401: Unauthorized
|
||||
- 403: Forbidden (admin access required)
|
||||
- 404: Path not found
|
||||
@@ -0,0 +1,31 @@
|
||||
info:
|
||||
name: Get Audio Chapters
|
||||
type: http
|
||||
seq: 30
|
||||
|
||||
http:
|
||||
method: GET
|
||||
url: "{{base_url}}/api/media-items/{{media_item_id}}/chapters"
|
||||
headers:
|
||||
- name: ""
|
||||
value: application/json
|
||||
auth: inherit
|
||||
|
||||
settings:
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
followRedirects: true
|
||||
maxRedirects: 5
|
||||
|
||||
docs: |-
|
||||
## Get Audio Chapters
|
||||
|
||||
The format-abstraction chapter list for audiobooks
|
||||
(media_items.audio_metadata). Single-file books return `layout: ""` and
|
||||
an empty `tracks` array; folder-of-tracks books return `layout:
|
||||
"folder"` and zip books `layout: "zip"`, each with one `tracks` entry
|
||||
per playable file (global-seconds start/end plus the per-track `url`).
|
||||
|
||||
**Method:** GET
|
||||
|
||||
**Endpoint:** /api/media-items/{id}/chapters
|
||||
@@ -0,0 +1,31 @@
|
||||
info:
|
||||
name: Get Audio Track
|
||||
type: http
|
||||
seq: 31
|
||||
|
||||
http:
|
||||
method: GET
|
||||
url: "{{base_url}}/api/media-items/{{media_item_id}}/audio/0"
|
||||
headers:
|
||||
- name: Range
|
||||
value: bytes=0-1023
|
||||
auth: inherit
|
||||
|
||||
settings:
|
||||
encodeUrl: true
|
||||
timeout: 0
|
||||
followRedirects: true
|
||||
maxRedirects: 5
|
||||
|
||||
docs: |-
|
||||
## Get Audio Track
|
||||
|
||||
Streams one track of a multi-file audiobook (folder or zip layout).
|
||||
Range requests are honored: folder tracks are served from the real
|
||||
file; zip tracks are extracted in place (backward seeks re-open the
|
||||
entry). Requires the item's library to be visible to the requester
|
||||
(403 otherwise). Single-file books have no track manifest — 404.
|
||||
|
||||
**Method:** GET
|
||||
|
||||
**Endpoint:** /api/media-items/{id}/audio/{trackIndex}
|
||||
@@ -4,7 +4,7 @@ info:
|
||||
seq: 3
|
||||
http:
|
||||
method: GET
|
||||
url: '{{opds_base_url}}/opds/devices/{{device_id}}/download/{{book_id}}?token={{device_token}}'
|
||||
url: '{{opds_base_url}}/devices/{{device_id}}/download/{{book_id}}?token={{device_token}}'
|
||||
|
||||
docs: |-
|
||||
## Download Book - Query Token
|
||||
|
||||
@@ -4,7 +4,7 @@ info:
|
||||
seq: 1
|
||||
http:
|
||||
method: GET
|
||||
url: '{{opds_base_url}}/opds/devices/{{device_id}}/catalog'
|
||||
url: '{{opds_base_url}}/devices/{{device_id}}/catalog'
|
||||
|
||||
docs: |-
|
||||
## Get Device OPDS Catalog - Bearer
|
||||
|
||||
@@ -4,7 +4,7 @@ info:
|
||||
seq: 2
|
||||
http:
|
||||
method: GET
|
||||
url: '{{opds_base_url}}/opds/devices/{{device_id}}/catalog?token={{device_token}}'
|
||||
url: '{{opds_base_url}}/devices/{{device_id}}/catalog?token={{device_token}}'
|
||||
|
||||
docs: |-
|
||||
## Get Device OPDS Catalog - Query Token
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
info:
|
||||
name: Clear Failed Items
|
||||
type: http
|
||||
seq: 8
|
||||
|
||||
http:
|
||||
method: DELETE
|
||||
url: '{{base_url}}/api/queue/clear-failed'
|
||||
auth: inherit
|
||||
|
||||
docs: |-
|
||||
## Clear Failed Queue Items
|
||||
|
||||
Removes all failed queue items from the queue.
|
||||
|
||||
**Method:** DELETE
|
||||
|
||||
**Endpoint:** /api/queue/clear-failed
|
||||
|
||||
**Authentication:** Required (Bearer token)
|
||||
|
||||
**Query Parameters:**
|
||||
- `older_than` (string, optional): ISO 8601 duration - e.g., `7d`, `24h`, `60m`
|
||||
- `device_id` (string, optional): Only clear items from specific device
|
||||
- `type` (string, optional): Only clear specific item type
|
||||
|
||||
**Request Body:**
|
||||
Optional filters:
|
||||
```json
|
||||
{
|
||||
"older_than": "7d",
|
||||
"device_id": "uuid",
|
||||
"type": "progress"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
- `deleted_count` (integer): Number of items deleted
|
||||
- `items_cleared` (array): IDs of cleared items
|
||||
- `retained_count` (integer): Items not matching filters
|
||||
- `cleared_at` (string): Deletion timestamp
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Items cleared successfully
|
||||
- 401: Unauthorized
|
||||
- 400: Invalid filter parameters
|
||||
|
||||
**Deletion Behavior:**
|
||||
- Removes failed items from queue
|
||||
- Does not affect pending/processing/completed items
|
||||
- Permanent deletion (cannot be undone)
|
||||
- Logs deletion for audit trail
|
||||
- Updates queue statistics
|
||||
|
||||
**Safety Features:**
|
||||
- Default filter prevents clearing recent failures
|
||||
- Per-device filtering for targeted cleanup
|
||||
- Type filtering for selective clearing
|
||||
- Confirmation required for large deletions
|
||||
|
||||
**Recommended Usage:**
|
||||
- **Daily:** Clear failures older than 7 days
|
||||
- **Weekly:** Clear all failed items
|
||||
- **Per-device:** After removing problematic device
|
||||
- **Per-type:** After fixing specific sync issue
|
||||
|
||||
**Use Cases:**
|
||||
- Clean up old failed sync attempts
|
||||
- Reduce queue database size
|
||||
- Remove stuck error items
|
||||
- Prepare for fresh sync attempts
|
||||
- Clear items for decommissioned devices
|
||||
- Reset after bug fixes
|
||||
|
||||
**Warnings:**
|
||||
- Cannot be undone
|
||||
- Failed items cleared permanently
|
||||
- Consider retrying before clearing
|
||||
- May hide recurring issues if overused
|
||||
- Check logs before bulk clearing
|
||||
|
||||
**Best Practices:**
|
||||
- Review error patterns before clearing
|
||||
- Fix root causes before cleanup
|
||||
- Use time-based filters to preserve recent failures
|
||||
- Document reasons for clearing
|
||||
- Monitor failure rates after cleanup
|
||||
@@ -1,83 +0,0 @@
|
||||
info:
|
||||
name: Get Queue Statistics
|
||||
type: http
|
||||
seq: 9
|
||||
|
||||
http:
|
||||
method: GET
|
||||
url: '{{base_url}}/api/queue/stats'
|
||||
auth: inherit
|
||||
|
||||
docs: |-
|
||||
## Get Queue Statistics
|
||||
|
||||
Retrieves overall queue performance and status metrics.
|
||||
|
||||
**Method:** GET
|
||||
|
||||
**Endpoint:** /api/queue/stats
|
||||
|
||||
**Authentication:** Required (Bearer token)
|
||||
|
||||
**Query Parameters:**
|
||||
None (all stats returned)
|
||||
|
||||
**Response:**
|
||||
- `overview` (object):
|
||||
- `total_items` (integer): All items in queue
|
||||
- `pending` (integer): Items awaiting processing
|
||||
- `processing` (integer): Items currently being processed
|
||||
- `completed` (integer): Successfully processed items
|
||||
- `failed` (integer): Failed items
|
||||
- `by_type` (object):
|
||||
- `progress` (object): Progress item counts
|
||||
- `note` (object): Note item counts
|
||||
- `highlight` (object): Highlight item counts
|
||||
- `bookmark` (object): Bookmark item counts
|
||||
- `by_status` (object):
|
||||
- `pending`: Count by type
|
||||
- `processing`: Count by type
|
||||
- `completed`: Count by type
|
||||
- `failed`: Count by type
|
||||
- `performance` (object):
|
||||
- `avg_processing_time_ms` (number): Average processing duration
|
||||
- `throughput_per_minute` (number): Items processed per minute
|
||||
- `success_rate` (number): Percentage of successful processing
|
||||
- `failure_rate` (number): Percentage of failures
|
||||
- `timing` (object):
|
||||
- `oldest_pending_age_seconds` (integer): Age of oldest pending item
|
||||
- `longest_processing_time_ms` (integer): Longest current processing time
|
||||
- `peak_queue_size_today` (integer): Maximum queue size today
|
||||
- `devices` (array): Top 5 devices by queue activity
|
||||
- `device_id` (string): Device UUID
|
||||
- `device_name` (string): Device name
|
||||
- `item_count` (integer): Items in queue from this device
|
||||
- `retention` (object):
|
||||
- `completed_items_30_days` (integer): Completed items in retention period
|
||||
- `purge_scheduled_at` (string): Next auto-purge time
|
||||
- `generated_at` (string): Statistics generation timestamp
|
||||
|
||||
**Status Codes:**
|
||||
- 200: Success
|
||||
- 401: Unauthorized
|
||||
|
||||
**Cache Behavior:**
|
||||
- Statistics cached for 60 seconds
|
||||
- Real-time data may vary slightly
|
||||
- Use `?refresh=true` to bypass cache
|
||||
|
||||
**Use Cases:**
|
||||
- Monitor queue health
|
||||
- Identify performance bottlenecks
|
||||
- Track processing capacity
|
||||
- Alert on failures
|
||||
- Capacity planning
|
||||
- SLA monitoring
|
||||
- Dashboard metrics
|
||||
|
||||
**Key Metrics to Watch:**
|
||||
- **Success Rate:** Should be >95%
|
||||
- **Avg Processing Time:** Depends on type
|
||||
- **Oldest Pending:** Should be <5 minutes
|
||||
- **Failed Items:** Investigate if >5%
|
||||
- **Throughput:** Baseline for capacity planning
|
||||
@@ -4,7 +4,7 @@ info:
|
||||
seq: 2
|
||||
http:
|
||||
method: GET
|
||||
url: '{{base_url}}/queue/items?limit=50&offset=0'
|
||||
url: '{{base_url}}/api/queue/items?limit=50&offset=0'
|
||||
auth: inherit
|
||||
body:
|
||||
type: none
|
||||
|
||||
Loaded 100 of 302 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user