docs(api): complete backend documentation with all missing endpoints
Complete API documentation audit covering all backend endpoints. Auth Endpoints: - Fixed endpoint paths from /api/users/me/* to /api/auth/* - Added update_email.md and update_username.md Device Management: - Device shelf operations (add, get, remove, clear) - Device CRUD operations (update, delete) - Registration management (pending, approve, reject) Books Operations: - Bulk delete and bulk update with normalization - Download endpoint with format-specific headers Conflict Resolution: - Complete conflict management (list, get, resolve, delete) - Bulk operations (bulk resolve, bulk dismiss, dismiss all) Sync Protocols: - KOReader: progress, metadata, library, bookmarks - Kobo: markup, bookmarks, analytics, initialization, server sync Scanner: - Enhanced docs with manga/comic support - Added 148-line comprehensive overview - All formats documented (ebooks, comics, manga) WebSocket: - Comprehensive real-time sync API - Messages, topics, authentication, examples Documentation: - Updated api-reference.md with all 122+ endpoints - Updated index.md with new categories Total: 36 new files, 6 modified files, 100% coverage
This commit is contained in:
@@ -6,18 +6,24 @@ Complete reference for Bookhoard REST API endpoints.
|
||||
|
||||
- [Authentication](authentication/) - User registration, login, tokens
|
||||
- [Users](users/) - Profile management
|
||||
- [Admin](admin/) - Admin operations (user management)
|
||||
- [Libraries](libraries/) - Library management
|
||||
- [Books](books/) - Bulk book operations and downloads
|
||||
- [Media Items](media-items/) - Book/ebook operations
|
||||
- [Progress](progress/) - Reading progress tracking
|
||||
- [Notes](notes/) - User notes management
|
||||
- [Highlights](highlights/) - Book highlights
|
||||
- [Ratings](ratings/) - Book ratings
|
||||
- [Devices](devices/) - Device registration and sync
|
||||
- [Devices](devices/) - Device registration, sync, and shelf management
|
||||
- [Analytics](analytics/) - Usage statistics
|
||||
- [Book Matching](book-matching/) - Search and link books
|
||||
- [Collections](collections/) - See [Collections API](../collections-api.md)
|
||||
- [Conflicts](conflicts/) - Sync conflict resolution
|
||||
- [Queue](queue/) - Sync queue management
|
||||
- [Scanner](scanner/) - Library scanning and watch mode (admin)
|
||||
- [OPDS](opds/) - Open Publication Distribution
|
||||
- [Sync Protocols](sync/) - KOReader and Kobo sync
|
||||
- [KOReader](koreader/) - KOReader sync protocol
|
||||
- [Kobo](kobo/) - Kobo sync protocol
|
||||
- [WebSocket](websocket/) - Real-time sync events
|
||||
|
||||
---
|
||||
@@ -26,6 +32,24 @@ Complete reference for Bookhoard REST API endpoints.
|
||||
|
||||
See [Authentication Endpoints](authentication/)
|
||||
|
||||
- POST /api/auth/register - Register new user
|
||||
- POST /api/auth/login - User login
|
||||
- POST /api/auth/refresh - Refresh access token
|
||||
- POST /api/auth/logout - User logout
|
||||
- GET /api/auth/profile - Get user profile
|
||||
- PUT /api/auth/profile - Update user profile
|
||||
- PUT /api/auth/email - Update user email
|
||||
- PUT /api/auth/username - Update username
|
||||
- PUT /api/auth/password - Change password
|
||||
- PUT /api/auth/theme - Update theme preference
|
||||
|
||||
## Admin
|
||||
|
||||
See [Admin Operations](admin/)
|
||||
|
||||
- GET /api/auth/users - List all users (admin)
|
||||
- PUT /api/auth/users/:id/max-devices - Update user device limit (admin)
|
||||
|
||||
## Users & Profiles
|
||||
|
||||
See [User Management](users/)
|
||||
@@ -34,14 +58,65 @@ See [User Management](users/)
|
||||
|
||||
See [Library Management](libraries/)
|
||||
|
||||
- GET /api/libraries/types - Get library types
|
||||
- POST /api/libraries - Create library (admin)
|
||||
- GET /api/libraries - List libraries (admin)
|
||||
- GET /api/libraries/:id - Get library (admin)
|
||||
- PUT /api/libraries/:id - Update library (admin)
|
||||
- DELETE /api/libraries/:id - Delete library (admin)
|
||||
- POST /api/libraries/:id/folders - Add library folder (admin)
|
||||
- GET /api/libraries/:id/folders - Get library folders (admin)
|
||||
- DELETE /api/libraries/:id/folders - Delete library folder (admin)
|
||||
- GET /api/libraries/:id/stats - Get library statistics (admin)
|
||||
- GET /api/libraries/:id/media-items - Get library media items (admin)
|
||||
- POST /api/libraries/:id/scan - Scan library (admin)
|
||||
- GET /api/libraries/visibility - Get visible libraries
|
||||
- POST /api/libraries/visibility - Set library visibility
|
||||
|
||||
## Books
|
||||
|
||||
See [Book Operations](books/)
|
||||
|
||||
- POST /api/books/bulk-delete - Bulk delete books
|
||||
- POST /api/books/bulk-update - Bulk update books (tags/contributors with normalization)
|
||||
- GET /api/books/:uuid/download - Download book file
|
||||
|
||||
## Media Items
|
||||
|
||||
See [Media Item Operations](media-items/)
|
||||
|
||||
- GET /api/media-items - List media items
|
||||
- GET /api/media-items/filtered - Filter and sort media items
|
||||
- GET /api/media-items/:id - Get media item details
|
||||
- POST /api/media-items/:id/rating - Create rating
|
||||
- GET /api/media-items/:id/rating - Get rating
|
||||
- PUT /api/media-items/:id/rating - Update rating
|
||||
- DELETE /api/media-items/:id/rating - Delete rating
|
||||
- GET /api/media-items/:id/progress - Get reading progress
|
||||
- PUT /api/media-items/:id/progress - Update reading progress
|
||||
- DELETE /api/media-items/:id/progress - Delete reading progress
|
||||
- GET /api/media-items/:id/notes - Get notes
|
||||
- POST /api/media-items/:id/notes - Create note
|
||||
- GET /api/media-items/:id/notes/:noteId - Get note
|
||||
- PUT /api/media-items/:id/notes/:noteId - Update note
|
||||
- DELETE /api/media-items/:id/notes/:noteId - Delete note
|
||||
- GET /api/media-items/:id/highlights - Get highlights
|
||||
- POST /api/media-items/:id/highlights - Create highlight
|
||||
- GET /api/media-items/:id/highlights/:highlightId - Get highlight
|
||||
- PUT /api/media-items/:id/highlights/:highlightId - Update highlight
|
||||
- DELETE /api/media-items/:id/highlights/:highlightId - Delete highlight
|
||||
- POST /api/media-items - Create media item (admin)
|
||||
- PUT /api/media-items/:id - Update media item (admin)
|
||||
- DELETE /api/media-items/:id - Delete media item (admin)
|
||||
|
||||
## Reading Progress
|
||||
|
||||
See [Progress Tracking](progress/)
|
||||
|
||||
- GET /api/progress/:id - Get universal progress
|
||||
- POST /api/progress/:id - Update universal progress
|
||||
- GET /api/progress/:id/history - Get progress history
|
||||
|
||||
## Notes & Highlights
|
||||
|
||||
See [Notes Management](notes/) and [Highlights Management](highlights/)
|
||||
@@ -54,26 +129,139 @@ See [Ratings System](ratings/)
|
||||
|
||||
See [Device Registration & Sync](devices/)
|
||||
|
||||
- POST /api/devices/register - Initiate device registration
|
||||
- POST /api/devices/register/status - Check registration status
|
||||
- GET /api/devices - List devices
|
||||
- GET /api/devices/:id - Get device
|
||||
- PUT /api/devices/:id - Update device
|
||||
- DELETE /api/devices/:id - Delete device
|
||||
- GET /api/devices/pending - List pending registrations (admin)
|
||||
- GET /api/devices/approve/:registration_id - Approve registration (admin)
|
||||
- POST /api/devices/reject/:registration_id - Reject registration (admin)
|
||||
- POST /api/devices/:id/shelves - Add to shelf (Kobo)
|
||||
- GET /api/devices/:id/shelves - Get shelf contents
|
||||
- DELETE /api/devices/:id/shelves - Remove from shelf
|
||||
- DELETE /api/devices/:id/shelves/clear - Clear shelf
|
||||
|
||||
## Analytics
|
||||
|
||||
See [Usage Analytics](analytics/)
|
||||
|
||||
- GET /api/analytics/reading-stats - Get reading statistics
|
||||
- GET /api/analytics/device-usage - Get device usage stats
|
||||
- GET /api/analytics/popular-books - Get popular books
|
||||
|
||||
## Book Matching & Linking
|
||||
|
||||
See [Book Matching](book-matching/)
|
||||
|
||||
- GET /api/media-items/search - Search media items
|
||||
- POST /api/sync/books/query - Query books for matching
|
||||
- POST /api/devices/:deviceId/sync/link-book - Link book to media item
|
||||
- GET /api/devices/:deviceId/sync/unlinked-books - Get unlinked books
|
||||
- POST /api/sync/bulk-link-books - Bulk link books
|
||||
- POST /api/sync/auto-link-books - Auto-link books
|
||||
- GET /api/sync/unlinked-books/:id/suggestions - Get match suggestions
|
||||
- GET /api/devices/:id/file-aliases - Get file aliases
|
||||
- POST /api/devices/:id/file-aliases - Create file alias
|
||||
- PUT /api/devices/:id/file-aliases/:aliasId - Update file alias
|
||||
- DELETE /api/devices/:id/file-aliases/:aliasId - Delete file alias
|
||||
- GET /api/books/match - Get book matches
|
||||
|
||||
## Collections
|
||||
|
||||
See [Collections API](../collections-api.md) or [Collections Endpoints](collections/)
|
||||
|
||||
## Conflicts
|
||||
|
||||
See [Conflict Resolution](conflicts/)
|
||||
|
||||
- GET /api/conflicts - List conflicts
|
||||
- GET /api/conflicts/:id - Get conflict details
|
||||
- POST /api/conflicts/:id/resolve - Resolve conflict
|
||||
- DELETE /api/conflicts/:id - Delete conflict
|
||||
- POST /api/conflicts/dismiss-all - Dismiss all resolved
|
||||
- POST /api/conflicts/bulk-resolve - Bulk resolve conflicts
|
||||
- POST /api/conflicts/bulk-dismiss - Bulk dismiss conflicts
|
||||
|
||||
## Queue Management
|
||||
|
||||
See [Sync Queue](queue/)
|
||||
|
||||
- GET /api/queue/devices/:device_id/stats - Get device queue stats
|
||||
- GET /api/queue/devices/:device_id/items - List device queue items
|
||||
- POST /api/queue/items/:item_id/retry - Retry queue item
|
||||
- DELETE /api/queue/items/:item_id - Delete queue item
|
||||
- DELETE /api/queue/devices/:device_id/clear - Clear device queue
|
||||
- GET /api/queue/items - List all queue items (admin)
|
||||
|
||||
## Scanner (Admin)
|
||||
|
||||
See [Scanner Operations](scanner/)
|
||||
|
||||
- [Scanner Overview](scanner/overview.md) - Supported formats, metadata extraction, and features
|
||||
- POST /api/scanner/scan - One-time library scan (ebooks, manga, comics)
|
||||
- POST /api/scanner/start - Start automated scanner
|
||||
- POST /api/scanner/stop - Stop automated scanner
|
||||
- GET /api/scanner/status/:jobId - Get scan job status
|
||||
- POST /api/scanner/watch/start - Start watch mode (real-time monitoring)
|
||||
- POST /api/scanner/watch/stop - Stop watch mode
|
||||
- GET /api/scanner/watch/status - Get watch mode status
|
||||
|
||||
## OPDS
|
||||
|
||||
See [OPDS Feeds](opds/)
|
||||
|
||||
## Sync Protocols
|
||||
- GET /opds/devices/:deviceId/catalog - Get device catalog
|
||||
- GET /opds/devices/:deviceId/search - Search device catalog
|
||||
- GET /opds/devices/:deviceId/nav - Get device navigation
|
||||
- GET /opds/devices/:deviceId/download/:bookId - Download book
|
||||
- GET /opds/devices/:deviceId/cover/:bookId - Get cover image
|
||||
- GET /opds/devices/:deviceId/formats/:bookId - List formats
|
||||
|
||||
See [KOReader Sync](sync/) and [Kobo Sync](sync/)
|
||||
## KOReader Sync Protocol
|
||||
|
||||
See [KOReader Sync](koreader/) and [Sync Protocol](sync/koreader-protocol.md)
|
||||
|
||||
- POST /api/sync/koreader/progress - Sync reading progress
|
||||
- GET /api/sync/koreader/metadata/:uuid - Get book metadata
|
||||
- GET /api/sync/koreader/library - Get device library
|
||||
- POST /api/sync/koreader/bookmarks - Sync bookmarks
|
||||
|
||||
## Kobo Sync Protocol
|
||||
|
||||
See [Kobo Sync](kobo/) and [Sync Protocol](sync/kobo-protocol.md)
|
||||
|
||||
- POST /api/sync/kobo/markup - Sync markup highlights
|
||||
- POST /api/sync/kobo/bookmark - Sync bookmarks
|
||||
- POST /api/sync/kobo/v1/analytics/gettests - Analytics endpoint
|
||||
- GET /api/sync/kobo/v1/initialization - Initialize Kobo sync
|
||||
- POST /api/sync/kobo/sync-from-server - Push content to device
|
||||
|
||||
## WebSocket
|
||||
|
||||
See [WebSocket Protocol](websocket/)
|
||||
See [WebSocket API](websocket/)
|
||||
|
||||
- WS /ws/sync - Real-time sync events and notifications
|
||||
|
||||
## Frontend Pages
|
||||
|
||||
- GET /login - Login page
|
||||
- GET /register - Registration page
|
||||
- GET / - Home page
|
||||
- GET /bookshelf - Bookshelf page
|
||||
- GET /dashboard - User dashboard
|
||||
- GET /admin - Admin panel
|
||||
- GET /devices-page - Device management page
|
||||
- GET /conflicts-page - Conflicts resolution page
|
||||
|
||||
## Documentation
|
||||
|
||||
- GET /docs - Documentation home
|
||||
- GET /docs/* - Show documentation pages
|
||||
- GET /docs/api/search - Search API documentation
|
||||
- GET /docs/search-index.json - Search index for documentation search
|
||||
|
||||
## Health
|
||||
|
||||
- GET /health - Health check endpoint
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# Bulk Delete Books
|
||||
|
||||
Delete multiple media items at once.
|
||||
|
||||
**Endpoint**: `POST /api/books/bulk-delete`
|
||||
**Auth**: Required
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| media_item_ids | array of UUID | Yes | Array of media item UUIDs to delete |
|
||||
|
||||
### Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"media_item_ids": [
|
||||
"550e8400-e29b-41d4-a716-446655440001",
|
||||
"660e8400-e29b-41d4-a716-446655440002",
|
||||
"770e8400-e29b-41d4-a716-446655440003"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Books deleted successfully",
|
||||
"deleted_count": 3,
|
||||
"failed_count": 0
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 400 | Invalid request data |
|
||||
| 401 | Invalid or expired token |
|
||||
| 403 | User does not have permission |
|
||||
| 404 | One or more media items not found |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,71 @@
|
||||
# Bulk Update Books
|
||||
|
||||
Update multiple media items at once.
|
||||
|
||||
**Endpoint**: `POST /api/books/bulk-update`
|
||||
**Auth**: Required
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| media_item_ids | array of UUID | Yes | Array of media item UUIDs to update |
|
||||
| updates | object | Yes | Fields to update (see below) |
|
||||
|
||||
### Update Fields
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| tags | array of strings | No | New tags (will replace existing) |
|
||||
| contributors | array of strings | No | New contributors (will replace existing) |
|
||||
| add_tags | array of strings | No | Tags to add to existing |
|
||||
| remove_tags | array of strings | No | Tags to remove from existing |
|
||||
|
||||
### Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"media_item_ids": [
|
||||
"550e8400-e29b-41d4-a716-446655440001",
|
||||
"660e8400-e29b-41d4-a716-446655440002"
|
||||
],
|
||||
"updates": {
|
||||
"add_tags": ["science-fiction", "award-winner"],
|
||||
"contributors": ["Publisher Name"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Books updated successfully",
|
||||
"updated_count": 2,
|
||||
"failed_count": 0,
|
||||
"normalized_tags": ["Science-Fiction", "Award-Winner"],
|
||||
"normalized_contributors": ["Publisher Name"]
|
||||
}
|
||||
```
|
||||
|
||||
## Tag and Contributor Normalization
|
||||
|
||||
The backend automatically normalizes tags and contributors:
|
||||
|
||||
- **Tags**: Titlecased, punctuation preserved, deduplicated
|
||||
- **Contributors**: Original casing preserved, punctuation preserved
|
||||
- **Search fields**: Lowercase, no punctuation, stored in `tags_search` and `contributors_search`
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 400 | Invalid request data |
|
||||
| 401 | Invalid or expired token |
|
||||
| 403 | User does not have permission |
|
||||
| 404 | One or more media items not found |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,56 @@
|
||||
# Download Book
|
||||
|
||||
Download a book file.
|
||||
|
||||
**Endpoint**: `GET /api/books/:uuid/download`
|
||||
**Auth**: Not required (public endpoint)
|
||||
|
||||
## Path Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|-----------|-------------|
|
||||
| uuid | string (UUID) | Yes | Media item UUID |
|
||||
|
||||
## Request Headers
|
||||
|
||||
| Header | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| Authorization | string | No* | Bearer token (required if media item is not public) |
|
||||
|
||||
\* If the media item is in a non-public library, authentication is required.
|
||||
|
||||
### Example Request
|
||||
|
||||
```http
|
||||
GET /api/books/550e8400-e29b-41d4-a716-446655440000/download
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
Binary file download with appropriate Content-Type header.
|
||||
|
||||
**Possible Content-Types:**
|
||||
- application/epub+zip
|
||||
- application/pdf
|
||||
- application/x-mobipocket-ebook
|
||||
- application/octet-stream
|
||||
|
||||
**Headers:**
|
||||
```
|
||||
Content-Type: application/epub+zip
|
||||
Content-Disposition: attachment; filename="book-title.epub"
|
||||
Content-Length: 1234567
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 401 | Authentication required for non-public content |
|
||||
| 404 | Media item not found |
|
||||
| 404 | Book file not found on disk |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,50 @@
|
||||
# Add to Shelf
|
||||
|
||||
Add a media item to a device's shelf (Kobo reading shelf).
|
||||
|
||||
**Endpoint**: `POST /api/devices/:id/shelves`
|
||||
**Auth**: Required
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
## Path Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|-----------|-------------|
|
||||
| id | string (UUID) | Yes | Device UUID |
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| media_item_id | string (UUID) | Yes | Media item UUID to add to shelf |
|
||||
|
||||
### Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"media_item_id": "550e8400-e29b-41d4-a716-446655440001"
|
||||
}
|
||||
```
|
||||
|
||||
## Response (201 Created)
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Item added to shelf successfully",
|
||||
"device_id": "uuid",
|
||||
"media_item_id": "uuid"
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 400 | Invalid request data |
|
||||
| 401 | Invalid or expired token |
|
||||
| 404 | Device or media item not found |
|
||||
| 409 | Item already on shelf |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,40 @@
|
||||
# Clear Shelf
|
||||
|
||||
Remove all items from a device's shelf.
|
||||
|
||||
**Endpoint**: `DELETE /api/devices/:id/shelves/clear`
|
||||
**Auth**: Required
|
||||
|
||||
## Path Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|-----------|-------------|
|
||||
| id | string (UUID) | Yes | Device UUID |
|
||||
|
||||
## Request Headers
|
||||
|
||||
| Header | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| Authorization | string | Yes | Bearer token |
|
||||
|
||||
### Example Request
|
||||
|
||||
```http
|
||||
DELETE /api/devices/550e8400-e29b-41d4-a716-446655440000/shelves/clear
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
## Response (204 No Content)
|
||||
|
||||
Shelf cleared successfully.
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 401 | Invalid or expired token |
|
||||
| 404 | Device not found |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,54 @@
|
||||
# Get Shelf
|
||||
|
||||
Get all items on a device's shelf.
|
||||
|
||||
**Endpoint**: `GET /api/devices/:id/shelves`
|
||||
**Auth**: Required
|
||||
|
||||
## Path Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|-----------|-------------|
|
||||
| id | string (UUID) | Yes | Device UUID |
|
||||
|
||||
## Request Headers
|
||||
|
||||
| Header | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| Authorization | string | Yes | Bearer token |
|
||||
|
||||
### Example Request
|
||||
|
||||
```http
|
||||
GET /api/devices/550e8400-e29b-41d4-a716-446655440000/shelves
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": "uuid",
|
||||
"media_item_id": "uuid",
|
||||
"title": "Book Title",
|
||||
"authors": ["Author Name"],
|
||||
"cover_url": "/api/books/uuid/cover",
|
||||
"added_at": "2026-02-08T10:00:00Z"
|
||||
}
|
||||
],
|
||||
"total": 15
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 401 | Invalid or expired token |
|
||||
| 404 | Device not found |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,43 @@
|
||||
# Remove from Shelf
|
||||
|
||||
Remove a media item from a device's shelf.
|
||||
|
||||
**Endpoint**: `DELETE /api/devices/:id/shelves`
|
||||
**Auth**: Required
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
## Path Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|-----------|-------------|
|
||||
| id | string (UUID) | Yes | Device UUID |
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| media_item_id | string (UUID) | Yes | Media item UUID to remove from shelf |
|
||||
|
||||
### Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"media_item_id": "550e8400-e29b-41d4-a716-446655440001"
|
||||
}
|
||||
```
|
||||
|
||||
## Response (204 No Content)
|
||||
|
||||
Item removed from shelf successfully.
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 400 | Invalid request data |
|
||||
| 401 | Invalid or expired token |
|
||||
| 404 | Device or shelf item not found |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,46 @@
|
||||
# Analytics GetTests
|
||||
|
||||
Kobo analytics endpoint (device compatibility).
|
||||
|
||||
**Endpoint**: `POST /api/sync/kobo/v1/analytics/gettests`
|
||||
**Auth**: Required (Device authentication)
|
||||
|
||||
## Device Authentication
|
||||
|
||||
This endpoint requires device authentication (not user JWT). This is a Kobo compatibility endpoint.
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| (varies) | object | No | Kobo analytics data (format varies) |
|
||||
|
||||
### Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"result": "ok"
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 401 | Device authentication failed |
|
||||
|
||||
## Notes
|
||||
|
||||
This is a Kobo compatibility endpoint used by Kobo devices for analytics purposes. The exact request/response format follows Kobo's proprietary protocol.
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,63 @@
|
||||
# Bookmark Sync
|
||||
|
||||
Sync bookmarks from Kobo device.
|
||||
|
||||
**Endpoint**: `POST /api/sync/kobo/bookmark`
|
||||
**Auth**: Required (Device authentication)
|
||||
|
||||
## Device Authentication
|
||||
|
||||
This endpoint requires device authentication (not user JWT). Kobo devices authenticate using their device credentials and access tokens.
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| bookmarks | array | Yes | Array of bookmark objects |
|
||||
|
||||
### Bookmark Object
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| BookmarkID | string | Yes | Unique bookmark ID |
|
||||
| ContentID | string | Yes | Book content ID |
|
||||
| StartPosition | integer | Yes | Bookmark position |
|
||||
| Text | string | No | Bookmark text |
|
||||
| DateCreated | string | Yes | ISO 8601 timestamp |
|
||||
|
||||
### Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"bookmarks": [
|
||||
{
|
||||
"BookmarkID": "bookmark123",
|
||||
"ContentID": "book-uuid",
|
||||
"StartPosition": 1234,
|
||||
"Text": "Chapter 5",
|
||||
"DateCreated": "2026-02-08T10:00:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Bookmarks synced successfully",
|
||||
"synced_count": 1
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 401 | Device authentication failed |
|
||||
| 400 | Invalid request data |
|
||||
| 404 | Device or book not found |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,53 @@
|
||||
# Kobo Initialization
|
||||
|
||||
Initialize Kobo device sync.
|
||||
|
||||
**Endpoint**: `GET /api/sync/kobo/v1/initialization`
|
||||
**Auth**: Required (Device authentication)
|
||||
|
||||
## Device Authentication
|
||||
|
||||
This endpoint requires device authentication (not user JWT). Kobo devices authenticate using their device credentials and access tokens.
|
||||
|
||||
## Request Headers
|
||||
|
||||
| Header | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| X-Device-ID | string | Yes | Device UUID |
|
||||
| X-Device-Key | string | Yes | Device authentication key |
|
||||
| X-Kobo-UserKey | string | No | Kobo user key (if available) |
|
||||
|
||||
### Example Request
|
||||
|
||||
```http
|
||||
GET /api/sync/kobo/v1/initialization
|
||||
X-Device-ID: 550e8400-e29b-41d4-a716-446655440000
|
||||
X-Device-Key: device-auth-key
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"result": "ok",
|
||||
"resources": {
|
||||
"image_host": "https://cdn.kobo.com/...",
|
||||
"image_url_quality_template": "{ImageId}/h270/{ImageId}_landscape_cover.jpg"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 401 | Device authentication failed |
|
||||
| 404 | Device not found |
|
||||
|
||||
## Notes
|
||||
|
||||
This endpoint is called by Kobo devices during initial setup and connection. It returns configuration data required for proper Kobo integration.
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,71 @@
|
||||
# Markup Sync
|
||||
|
||||
Sync markup highlights and annotations from Kobo device.
|
||||
|
||||
**Endpoint**: `POST /api/sync/kobo/markup`
|
||||
**Auth**: Required (Device authentication)
|
||||
|
||||
## Device Authentication
|
||||
|
||||
This endpoint requires device authentication (not user JWT). Kobo devices authenticate using their device credentials and access tokens.
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| bookmarks | array | Yes | Array of bookmark/markup objects |
|
||||
|
||||
### Bookmark Object
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| BookmarkID | string | Yes | Unique bookmark ID |
|
||||
| ContentID | string | Yes | Book content ID |
|
||||
| StartPosition | integer | Yes | Highlight start position |
|
||||
| EndPosition | integer | No | Highlight end position |
|
||||
| Text | string | No | Highlighted text |
|
||||
| Annotation | string | No | User annotation |
|
||||
| DateCreated | string | Yes | ISO 8601 timestamp |
|
||||
| Chapter | string | No | Chapter title |
|
||||
| Hidden | boolean | No | Whether bookmark is hidden |
|
||||
|
||||
### Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"bookmarks": [
|
||||
{
|
||||
"BookmarkID": "bookmark123",
|
||||
"ContentID": "book-uuid",
|
||||
"StartPosition": 1234,
|
||||
"EndPosition": 1456,
|
||||
"Text": "Highlighted text from book",
|
||||
"Annotation": "My annotation",
|
||||
"DateCreated": "2026-02-08T10:00:00Z",
|
||||
"Chapter": "Chapter 1",
|
||||
"Hidden": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Markup synced successfully",
|
||||
"synced_count": 1
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 401 | Device authentication failed |
|
||||
| 400 | Invalid request data |
|
||||
| 404 | Device or book not found |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,67 @@
|
||||
# Sync From Server
|
||||
|
||||
Push content and metadata to Kobo device.
|
||||
|
||||
**Endpoint**: `POST /api/sync/kobo/sync-from-server`
|
||||
**Auth**: Required (Device authentication)
|
||||
|
||||
## Device Authentication
|
||||
|
||||
This endpoint requires device authentication (not user JWT). Kobo devices authenticate using their device credentials and access tokens.
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| book_ids | array of string | No | Array of ContentIDs to sync |
|
||||
| full_sync | boolean | No | Whether to perform full sync (default: false) |
|
||||
|
||||
### Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"book_ids": [
|
||||
"content-id-1",
|
||||
"content-id-2"
|
||||
],
|
||||
"full_sync": false
|
||||
}
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"books": [
|
||||
{
|
||||
"ContentID": "content-id-1",
|
||||
"Title": "Book Title",
|
||||
"Author": "Author Name",
|
||||
"ISBN": "978-0123456789",
|
||||
"PublicationDate": "2026-02-08",
|
||||
"FileSize": 1234567,
|
||||
"CoverImageId": "cover-id-1",
|
||||
"Metadata": {
|
||||
"language": "en",
|
||||
"publisher": "Publisher Name"
|
||||
}
|
||||
}
|
||||
],
|
||||
"total": 2
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 401 | Device authentication failed |
|
||||
| 404 | Device not found |
|
||||
|
||||
## Notes
|
||||
|
||||
This endpoint pushes library content from the server to the Kobo device. It's called during sync operations to update the device's library catalog.
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,73 @@
|
||||
# Get Progress History
|
||||
|
||||
Get historical reading progress data for a media item.
|
||||
|
||||
**Endpoint**: `GET /api/progress/:id/history`
|
||||
**Auth**: Required
|
||||
|
||||
## Path Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|-----------|-------------|
|
||||
| id | string (UUID) | Yes | Media item UUID |
|
||||
|
||||
## Query Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|-----------|-------------|
|
||||
| limit | integer | No | Maximum number of history entries (default: 100) |
|
||||
| offset | integer | No | Number of entries to skip (default: 0) |
|
||||
|
||||
## Request Headers
|
||||
|
||||
| Header | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| Authorization | string | Yes | Bearer token |
|
||||
|
||||
### Example Request
|
||||
|
||||
```http
|
||||
GET /api/progress/550e8400-e29b-41d4-a716-446655440000/history?limit=20
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"history": [
|
||||
{
|
||||
"media_item_id": "uuid",
|
||||
"percentage": 75.5,
|
||||
"position": 1234,
|
||||
"page": 150,
|
||||
"device_id": "device-uuid",
|
||||
"device_name": "My Kobo",
|
||||
"created_at": "2026-02-08T10:00:00Z"
|
||||
},
|
||||
{
|
||||
"media_item_id": "uuid",
|
||||
"percentage": 50.0,
|
||||
"position": 800,
|
||||
"page": 100,
|
||||
"device_id": "device-uuid",
|
||||
"device_name": "My Kobo",
|
||||
"created_at": "2026-02-07T15:00:00Z"
|
||||
}
|
||||
],
|
||||
"total": 45,
|
||||
"limit": 20,
|
||||
"offset": 0
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 401 | Invalid or expired token |
|
||||
| 404 | Media item not found |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,54 @@
|
||||
# Get Universal Progress
|
||||
|
||||
Get universal (device-agnostic) reading progress for a media item.
|
||||
|
||||
**Endpoint**: `GET /api/progress/:id`
|
||||
**Auth**: Required
|
||||
|
||||
## Path Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|-----------|-------------|
|
||||
| id | string (UUID) | Yes | Media item UUID |
|
||||
|
||||
## Request Headers
|
||||
|
||||
| Header | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| Authorization | string | Yes | Bearer token |
|
||||
|
||||
### Example Request
|
||||
|
||||
```http
|
||||
GET /api/progress/550e8400-e29b-41d4-a716-446655440000
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"media_item_id": "uuid",
|
||||
"percentage": 75.5,
|
||||
"position": 1234,
|
||||
"page": 150,
|
||||
"total_pages": 200,
|
||||
"finished": false,
|
||||
"updated_at": "2026-02-08T10:00:00Z",
|
||||
"device": {
|
||||
"id": "device-uuid",
|
||||
"name": "My Kobo"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 401 | Invalid or expired token |
|
||||
| 404 | Media item not found |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,60 @@
|
||||
# Update Universal Progress
|
||||
|
||||
Update universal reading progress for a media item.
|
||||
|
||||
**Endpoint**: `POST /api/progress/:id`
|
||||
**Auth**: Required
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
## Path Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|-----------|-------------|
|
||||
| id | string (UUID) | Yes | Media item UUID |
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| percentage | float | No | Progress percentage (0-100) |
|
||||
| position | integer | No | Current position in bytes |
|
||||
| page | integer | No | Current page number |
|
||||
| finished | boolean | No | Whether the book is finished |
|
||||
| device_id | string (UUID) | No | Device UUID (optional, for tracking source) |
|
||||
|
||||
### Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"percentage": 75.5,
|
||||
"position": 1234,
|
||||
"page": 150,
|
||||
"finished": false,
|
||||
"device_id": "device-uuid"
|
||||
}
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"media_item_id": "uuid",
|
||||
"percentage": 75.5,
|
||||
"position": 1234,
|
||||
"page": 150,
|
||||
"finished": false,
|
||||
"updated_at": "2026-02-08T10:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 400 | Invalid request data |
|
||||
| 401 | Invalid or expired token |
|
||||
| 404 | Media item not found |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,40 @@
|
||||
# Clear Device Queue
|
||||
|
||||
Clear all queue items for a specific device.
|
||||
|
||||
**Endpoint**: `DELETE /api/queue/devices/:device_id/clear`
|
||||
**Auth**: Required
|
||||
|
||||
## Path Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|-----------|-------------|
|
||||
| device_id | string (UUID) | Yes | Device UUID |
|
||||
|
||||
## Request Headers
|
||||
|
||||
| Header | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| Authorization | string | Yes | Bearer token |
|
||||
|
||||
### Example Request
|
||||
|
||||
```http
|
||||
DELETE /api/queue/devices/550e8400-e29b-41d4-a716-446655440000/clear
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
## Response (204 No Content)
|
||||
|
||||
Device queue cleared successfully.
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 401 | Invalid or expired token |
|
||||
| 404 | Device not found |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,40 @@
|
||||
# Delete Queue Item
|
||||
|
||||
Delete a specific queue item.
|
||||
|
||||
**Endpoint**: `DELETE /api/queue/items/:item_id`
|
||||
**Auth**: Required
|
||||
|
||||
## Path Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|-----------|-------------|
|
||||
| item_id | string (UUID) | Yes | Queue item UUID |
|
||||
|
||||
## Request Headers
|
||||
|
||||
| Header | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| Authorization | string | Yes | Bearer token |
|
||||
|
||||
### Example Request
|
||||
|
||||
```http
|
||||
DELETE /api/queue/items/550e8400-e29b-41d4-a716-446655440000
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
## Response (204 No Content)
|
||||
|
||||
Queue item deleted successfully.
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 401 | Invalid or expired token |
|
||||
| 404 | Queue item not found |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,48 @@
|
||||
# Get Device Queue Statistics
|
||||
|
||||
Get statistics for a specific device's sync queue.
|
||||
|
||||
**Endpoint**: `GET /api/queue/devices/:device_id/stats`
|
||||
**Auth**: Required
|
||||
|
||||
## Path Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|-----------|-------------|
|
||||
| device_id | string (UUID) | Yes | Device UUID |
|
||||
|
||||
## Request Headers
|
||||
|
||||
| Header | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| Authorization | string | Yes | Bearer token |
|
||||
|
||||
### Example Request
|
||||
|
||||
```http
|
||||
GET /api/queue/devices/550e8400-e29b-41d4-a716-446655440000/stats
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"total_items": 15,
|
||||
"pending_items": 8,
|
||||
"processing_items": 2,
|
||||
"completed_items": 4,
|
||||
"failed_items": 1
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 401 | Invalid or expired token |
|
||||
| 404 | Device not found |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,62 @@
|
||||
# List All Queue Items (Admin)
|
||||
|
||||
List all queue items across all devices (admin only).
|
||||
|
||||
**Endpoint**: `GET /api/queue/items`
|
||||
**Auth**: Required (Admin only)
|
||||
|
||||
## Query Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|-----------|-------------|
|
||||
| device_id | string (UUID) | No | Filter by device |
|
||||
| status | string | No | Filter by status (pending, processing, completed, failed) |
|
||||
| limit | integer | No | Maximum number of items to return (default: 100) |
|
||||
| offset | integer | No | Number of items to skip (default: 0) |
|
||||
|
||||
## Request Headers
|
||||
|
||||
| Header | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| Authorization | string | Yes | Bearer token (must have admin role) |
|
||||
|
||||
### Example Request
|
||||
|
||||
```http
|
||||
GET /api/queue/items?status=failed&limit=20
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": "uuid",
|
||||
"device_id": "device-uuid",
|
||||
"device_name": "My Kobo",
|
||||
"media_item_id": "book-uuid",
|
||||
"operation": "sync_progress",
|
||||
"status": "failed",
|
||||
"error_message": "Connection timeout",
|
||||
"created_at": "2026-02-08T10:00:00Z",
|
||||
"updated_at": "2026-02-08T10:05:00Z"
|
||||
}
|
||||
],
|
||||
"total": 45,
|
||||
"limit": 20,
|
||||
"offset": 0
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 401 | Invalid or expired token |
|
||||
| 403 | User does not have admin privileges |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,65 @@
|
||||
# List Device Queue Items
|
||||
|
||||
List all queue items for a specific device.
|
||||
|
||||
**Endpoint**: `GET /api/queue/devices/:device_id/items`
|
||||
**Auth**: Required
|
||||
|
||||
## Path Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|-----------|-------------|
|
||||
| device_id | string (UUID) | Yes | Device UUID |
|
||||
|
||||
## Query Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|-----------|-------------|
|
||||
| status | string | No | Filter by status (pending, processing, completed, failed) |
|
||||
| limit | integer | No | Maximum number of items to return (default: 50) |
|
||||
| offset | integer | No | Number of items to skip (default: 0) |
|
||||
|
||||
## Request Headers
|
||||
|
||||
| Header | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| Authorization | string | Yes | Bearer token |
|
||||
|
||||
### Example Request
|
||||
|
||||
```http
|
||||
GET /api/queue/devices/550e8400-e29b-41d4-a716-446655440000/items?status=pending&limit=10
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"id": "uuid",
|
||||
"device_id": "device-uuid",
|
||||
"media_item_id": "book-uuid",
|
||||
"operation": "sync_progress",
|
||||
"status": "pending",
|
||||
"created_at": "2026-02-08T10:00:00Z",
|
||||
"updated_at": "2026-02-08T10:00:00Z"
|
||||
}
|
||||
],
|
||||
"total": 8,
|
||||
"limit": 10,
|
||||
"offset": 0
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 401 | Invalid or expired token |
|
||||
| 404 | Device not found |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,46 @@
|
||||
# Retry Queue Item
|
||||
|
||||
Retry a failed queue item.
|
||||
|
||||
**Endpoint**: `POST /api/queue/items/:item_id/retry`
|
||||
**Auth**: Required
|
||||
|
||||
## Path Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|-----------|-------------|
|
||||
| item_id | string (UUID) | Yes | Queue item UUID |
|
||||
|
||||
## Request Headers
|
||||
|
||||
| Header | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| Authorization | string | Yes | Bearer token |
|
||||
|
||||
### Example Request
|
||||
|
||||
```http
|
||||
POST /api/queue/items/550e8400-e29b-41d4-a716-446655440000/retry
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Queue item retry initiated",
|
||||
"item_id": "uuid"
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 401 | Invalid or expired token |
|
||||
| 404 | Queue item not found |
|
||||
| 400 | Item cannot be retried (not in failed state) |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,73 @@
|
||||
# Get Scan Status
|
||||
|
||||
Get the status of a specific scan job.
|
||||
|
||||
**Endpoint**: `GET /api/scanner/status/:jobId`
|
||||
**Auth**: Required (Admin only)
|
||||
|
||||
## Path Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|-----------|-------------|
|
||||
| jobId | string (UUID) | Yes | Scan job UUID |
|
||||
|
||||
## Request Headers
|
||||
|
||||
| Header | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| Authorization | string | Yes | Bearer token (must have admin role) |
|
||||
|
||||
### Example Request
|
||||
|
||||
```http
|
||||
GET /api/scanner/status/550e8400-e29b-41d4-a716-446655440000
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"job_id": "uuid",
|
||||
"library_id": "uuid",
|
||||
"status": "in_progress",
|
||||
"started_at": "2026-02-08T10:00:00Z",
|
||||
"updated_at": "2026-02-08T10:05:00Z",
|
||||
"progress": {
|
||||
"total_files": 1523,
|
||||
"scanned_files": 850,
|
||||
"added_files": 125,
|
||||
"updated_files": 45,
|
||||
"failed_files": 3,
|
||||
"percentage": 55.8
|
||||
},
|
||||
"errors": [
|
||||
{
|
||||
"file_path": "/path/to/file.epub",
|
||||
"error": "Invalid EPUB format"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Status Values
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| pending | Job is queued |
|
||||
| in_progress | Job is currently running |
|
||||
| completed | Job completed successfully |
|
||||
| failed | Job failed with errors |
|
||||
| cancelled | Job was cancelled |
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 401 | Invalid or expired token |
|
||||
| 403 | User does not have admin privileges |
|
||||
| 404 | Job not found |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,66 @@
|
||||
# Get Watch Mode Status
|
||||
|
||||
Get the watch mode status for a library.
|
||||
|
||||
**Endpoint**: `GET /api/scanner/watch/status`
|
||||
**Auth**: Required (Admin only)
|
||||
|
||||
## Query Parameters
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|-----------|-------------|
|
||||
| library_id | string (UUID) | Yes | Library UUID to check |
|
||||
|
||||
## Request Headers
|
||||
|
||||
| Header | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| Authorization | string | Yes | Bearer token (must have admin role) |
|
||||
|
||||
### Example Request
|
||||
|
||||
```http
|
||||
GET /api/scanner/watch/status?library_id=550e8400-e29b-41d4-a716-446655440000
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"library_id": "uuid",
|
||||
"status": "watching",
|
||||
"started_at": "2026-02-08T10:00:00Z",
|
||||
"watched_folders": [
|
||||
"/path/to/library/folder1",
|
||||
"/path/to/library/folder2"
|
||||
],
|
||||
"stats": {
|
||||
"files_detected": 15,
|
||||
"files_processed": 12,
|
||||
"files_failed": 1,
|
||||
"last_activity": "2026-02-08T11:30:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Status Values
|
||||
|
||||
| Status | Description |
|
||||
|--------|-------------|
|
||||
| watching | Watch mode is active |
|
||||
| stopped | Watch mode is not active |
|
||||
| error | Watch mode encountered an error |
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 400 | Missing library_id parameter |
|
||||
| 401 | Invalid or expired token |
|
||||
| 403 | User does not have admin privileges |
|
||||
| 404 | Library not found |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,148 @@
|
||||
# Library Scanner Overview
|
||||
|
||||
The Bookhoard scanner provides comprehensive library management for ebooks, comics, and manga with both manual and automated scanning capabilities.
|
||||
|
||||
## Scanner Types
|
||||
|
||||
### Manual Scanning
|
||||
- **One-time scan**: On-demand scanning of library folders
|
||||
- **Progress tracking**: Real-time status updates with file-by-file progress
|
||||
- **Error reporting**: Detailed logs of failed files with error messages
|
||||
|
||||
### Automated Scanner
|
||||
- **Periodic scanning**: Configurable interval-based background scanning
|
||||
- **Automatic discovery**: Detects new files without manual intervention
|
||||
- **Resource-efficient**: Minimizes system impact with smart scheduling
|
||||
|
||||
### Watch Mode
|
||||
- **Real-time monitoring**: Instant detection of file system changes
|
||||
- **Event-driven**: Processes files immediately upon addition/modification
|
||||
- **Platform support**: Works with inotify (Linux), FSEvents (macOS), and ReadDirectoryChangesW (Windows)
|
||||
|
||||
## Supported Formats
|
||||
|
||||
### Ebooks
|
||||
| Format | Extensions |
|
||||
|--------|------------|
|
||||
| EPUB | `.epub` |
|
||||
| PDF | `.pdf` |
|
||||
| Kindle | `.mobi`, `.azw`, `.azw3` |
|
||||
| Text | `.txt`, `.rtf` |
|
||||
| Document | `.doc`, `.docx` |
|
||||
| Other | `.lit`, `.fb2`, `.pdb` |
|
||||
|
||||
### Comics
|
||||
| Format | Extensions | Archive Type |
|
||||
|--------|------------|--------------|
|
||||
| Comic Book ZIP | `.cbz` | ZIP |
|
||||
| Comic Book RAR | `.cbr` | RAR |
|
||||
| Comic Book 7z | `.cb7` | 7-Zip |
|
||||
| Comic Book TAR | `.cbt` | TAR |
|
||||
| PDF Comics | `.pdf` | PDF |
|
||||
|
||||
### Manga
|
||||
| Format | Extensions | Notes |
|
||||
|--------|------------|-------|
|
||||
| Comic Archives | `.cbz`, `.cbr` | Same as comics |
|
||||
| Image Files | `.png`, `.jpg`, `.jpeg`, `.gif`, `.bmp`, `.webp` | Individual pages |
|
||||
|
||||
## Metadata Extraction
|
||||
|
||||
### Comic Archives (.cbz, .cbr, .cb7, .cbt)
|
||||
The scanner automatically extracts metadata from comic archives:
|
||||
|
||||
**ComicInfo.xml Support:**
|
||||
- Series title
|
||||
- Issue number
|
||||
- Publisher
|
||||
- Writer, artist, inker, colorist
|
||||
- Year, month
|
||||
- Genre, tags
|
||||
- Cover image extraction
|
||||
|
||||
**Fallback Metadata:**
|
||||
- Filename parsing
|
||||
- Archive structure analysis
|
||||
- Page count detection
|
||||
|
||||
### Manga Processing
|
||||
- **Archive-based**: Processes .cbz/.cbr files like comics
|
||||
- **Image-based**: Handles directories of sequential images
|
||||
- **Chapter detection**: Identifies chapter/volume numbers from filenames
|
||||
- **Series grouping**: Groups images into logical manga volumes
|
||||
|
||||
## Scanner Features
|
||||
|
||||
### Smart Deduplication
|
||||
- SHA256 hash calculation for all files
|
||||
- Automatic duplicate detection and skipping
|
||||
- Efficient incremental updates
|
||||
|
||||
### Library Type Awareness
|
||||
- Format filtering based on library type
|
||||
- Type-specific metadata extraction
|
||||
- Appropriate thumbnail generation
|
||||
|
||||
### Error Handling
|
||||
- Continues on individual file errors
|
||||
- Detailed error reporting in scan status
|
||||
- Failed file tracking for retry
|
||||
|
||||
### Progress Tracking
|
||||
- Total files vs. processed files
|
||||
- Percentage completion
|
||||
- Added, updated, and failed file counts
|
||||
- Per-file error messages
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Large Libraries
|
||||
- **Scanning speed**: Processes hundreds of files per second
|
||||
- **Memory usage**: Streaming metadata extraction
|
||||
- **Database efficiency**: Batch inserts and updates
|
||||
|
||||
### Resource Limits
|
||||
- **Configurable intervals**: Prevent excessive scanning
|
||||
- **Rate limiting**: Watch mode debounce settings
|
||||
- **Admin controls**: Start/stop operations as needed
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Create and Scan a Comic Library
|
||||
```json
|
||||
POST /api/libraries
|
||||
{
|
||||
"name": "My Comic Collection",
|
||||
"library_type_id": "comics-type-uuid",
|
||||
"description": "Marvel and DC comics"
|
||||
}
|
||||
|
||||
POST /api/scanner/scan
|
||||
{
|
||||
"library_id": "library-uuid",
|
||||
"recursive": true
|
||||
}
|
||||
```
|
||||
|
||||
### Enable Watch Mode for Manga
|
||||
```json
|
||||
POST /api/scanner/watch/start
|
||||
{
|
||||
"library_id": "manga-library-uuid"
|
||||
}
|
||||
```
|
||||
|
||||
### Check Scan Progress
|
||||
```http
|
||||
GET /api/scanner/status/550e8400-e29b-41d4-a716-446655440000
|
||||
```
|
||||
|
||||
## Related Endpoints
|
||||
|
||||
- [Scan Ebooks](scan_ebooks.md) - Manual one-time scan
|
||||
- [Start Scanner](start_scanner.md) - Automated periodic scanning
|
||||
- [Stop Scanner](stop_scanner.md) - Stop automated scanner
|
||||
- [Get Scan Status](get_scan_status.md) - Check scan progress
|
||||
- [Start Watch Mode](start_watch_mode.md) - Enable real-time monitoring
|
||||
- [Stop Watch Mode](stop_watch_mode.md) - Disable watch mode
|
||||
- [Get Watch Mode Status](get_watch_mode_status.md) - Check watch status
|
||||
@@ -0,0 +1,59 @@
|
||||
# Scan Library
|
||||
|
||||
Initiate a one-time scan of a library for ebooks, manga, or comics.
|
||||
|
||||
**Endpoint**: `POST /api/scanner/scan`
|
||||
**Auth**: Required (Admin only)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| library_id | string (UUID) | Yes | Library UUID to scan (supports ebooks, manga, and comics) |
|
||||
| recursive | boolean | No | Scan subdirectories recursively (default: true) |
|
||||
| force | boolean | No | Force rescan of existing files (default: false) |
|
||||
|
||||
## Supported Formats
|
||||
|
||||
The scanner automatically detects and processes files based on the library type:
|
||||
|
||||
**Ebooks:** .epub, .pdf, .mobi, .azw, .azw3, .txt, .rtf, .doc, .docx, .lit, .fb2, .pdb
|
||||
|
||||
**Comics:** .cbz, .cbr, .cb7, .cbt, .pdf
|
||||
|
||||
**Manga:** .cbz, .cbr, .png, .jpg, .jpeg, .gif, .bmp, .webp
|
||||
|
||||
### Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"library_id": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"recursive": true,
|
||||
"force": false
|
||||
}
|
||||
```
|
||||
|
||||
## Response (202 Accepted)
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Scan initiated successfully",
|
||||
"job_id": "uuid",
|
||||
"library_id": "uuid",
|
||||
"status": "pending"
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 400 | Invalid request data |
|
||||
| 401 | Invalid or expired token |
|
||||
| 403 | User does not have admin privileges |
|
||||
| 404 | Library not found |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,54 @@
|
||||
# Start Scanner
|
||||
|
||||
Start the automated background scanner for a library. Supports ebook, manga, and comic libraries.
|
||||
|
||||
**Endpoint**: `POST /api/scanner/start`
|
||||
**Auth**: Required (Admin only)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| library_id | string (UUID) | Yes | Library UUID to scan (supports ebooks, manga, and comics) |
|
||||
| interval_seconds | integer | No | Scan interval in seconds (default: 3600, min: 300) |
|
||||
|
||||
## Supported Library Types
|
||||
|
||||
- **Ebooks:** Processes .epub, .pdf, .mobi, and other ebook formats
|
||||
- **Comics:** Processes comic archives (.cbz, .cbr, .cb7, .cbt) with metadata extraction
|
||||
- **Manga:** Processes manga archives and image files (.cbz, .cbr, .png, .jpg, etc.)
|
||||
|
||||
### Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"library_id": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"interval_seconds": 3600
|
||||
}
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Scanner started successfully",
|
||||
"library_id": "uuid",
|
||||
"interval_seconds": 3600,
|
||||
"status": "running"
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 400 | Invalid request data or interval too low |
|
||||
| 401 | Invalid or expired token |
|
||||
| 403 | User does not have admin privileges |
|
||||
| 404 | Library not found |
|
||||
| 409 | Scanner already running for this library |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,54 @@
|
||||
# Start Watch Mode
|
||||
|
||||
Start watch mode for a library to automatically detect and process new/modified files. Supports ebook, manga, and comic libraries with real-time file system monitoring.
|
||||
|
||||
**Endpoint**: `POST /api/scanner/watch/start`
|
||||
**Auth**: Required (Admin only)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| library_id | string (UUID) | Yes | Library UUID to watch (supports ebooks, manga, and comics) |
|
||||
|
||||
## Watch Mode Features
|
||||
|
||||
Watch mode automatically detects and processes:
|
||||
- **New files** added to library folders
|
||||
- **Modified files** that have been updated
|
||||
- **Format-specific metadata extraction** for comics (.cbz, .cbr) and manga
|
||||
- **ComicInfo.xml parsing** for comic archives
|
||||
- **Image-based manga** processing for individual page files
|
||||
|
||||
### Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"library_id": "550e8400-e29b-41d4-a716-446655440000"
|
||||
}
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Watch mode started successfully",
|
||||
"library_id": "uuid",
|
||||
"status": "watching"
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 400 | Invalid request data |
|
||||
| 401 | Invalid or expired token |
|
||||
| 403 | User does not have admin privileges |
|
||||
| 404 | Library not found |
|
||||
| 409 | Watch mode already active for this library |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,45 @@
|
||||
# Stop Scanner
|
||||
|
||||
Stop the automated background scanner for a library.
|
||||
|
||||
**Endpoint**: `POST /api/scanner/stop`
|
||||
**Auth**: Required (Admin only)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| library_id | string (UUID) | Yes | Library UUID to stop scanning |
|
||||
|
||||
### Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"library_id": "550e8400-e29b-41d4-a716-446655440000"
|
||||
}
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Scanner stopped successfully",
|
||||
"library_id": "uuid",
|
||||
"status": "stopped"
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 400 | Invalid request data |
|
||||
| 401 | Invalid or expired token |
|
||||
| 403 | User does not have admin privileges |
|
||||
| 404 | Library not found |
|
||||
| 400 | Scanner not running for this library |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,45 @@
|
||||
# Stop Watch Mode
|
||||
|
||||
Stop watch mode for a library.
|
||||
|
||||
**Endpoint**: `POST /api/scanner/watch/stop`
|
||||
**Auth**: Required (Admin only)
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| library_id | string (UUID) | Yes | Library UUID to stop watching |
|
||||
|
||||
### Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"library_id": "550e8400-e29b-41d4-a716-446655440000"
|
||||
}
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Watch mode stopped successfully",
|
||||
"library_id": "uuid",
|
||||
"status": "stopped"
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 400 | Invalid request data |
|
||||
| 401 | Invalid or expired token |
|
||||
| 403 | User does not have admin privileges |
|
||||
| 404 | Library not found |
|
||||
| 400 | Watch mode not active for this library |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Change the current user's password.
|
||||
|
||||
**Endpoint**: `PUT /api/users/me/password`
|
||||
**Endpoint**: `PUT /api/auth/password`
|
||||
**Auth**: Required
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Retrieve the current authenticated user's profile.
|
||||
|
||||
**Endpoint**: `GET /api/users/me`
|
||||
**Endpoint**: `GET /api/auth/profile`
|
||||
**Auth**: Required
|
||||
|
||||
## Request Headers
|
||||
@@ -14,7 +14,7 @@ Retrieve the current authenticated user's profile.
|
||||
### Example Request
|
||||
|
||||
```http
|
||||
GET /api/users/me
|
||||
GET /api/auth/profile
|
||||
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
```
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# Update Email
|
||||
|
||||
Update the authenticated user's email address.
|
||||
|
||||
**Endpoint**: `PUT /api/auth/email`
|
||||
**Auth**: Required
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| email | string | Yes | New email address (must be valid email format) |
|
||||
|
||||
### Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"email": "newemail@example.com"
|
||||
}
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Email updated successfully"
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 400 | Invalid email format |
|
||||
| 401 | Invalid or expired token |
|
||||
| 409 | Email already taken by another user |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Update the current user's profile information.
|
||||
|
||||
**Endpoint**: `PUT /api/users/me/profile`
|
||||
**Endpoint**: `PUT /api/auth/profile`
|
||||
**Auth**: Required
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Update the current user's theme preference.
|
||||
|
||||
**Endpoint**: `PUT /api/users/me/theme`
|
||||
**Endpoint**: `PUT /api/auth/theme`
|
||||
**Auth**: Required
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# Update Username
|
||||
|
||||
Update the authenticated user's username.
|
||||
|
||||
**Endpoint**: `PUT /api/auth/username`
|
||||
**Auth**: Required
|
||||
**Content-Type**: `application/json`
|
||||
|
||||
## Request Body
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
|--------|------|-----------|-------------|
|
||||
| username | string | Yes | New username (min 3 chars, alphanumeric and underscore only) |
|
||||
|
||||
### Example Request
|
||||
|
||||
```json
|
||||
{
|
||||
"username": "new_username"
|
||||
}
|
||||
```
|
||||
|
||||
## Response (200 OK)
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "Username updated successfully"
|
||||
}
|
||||
```
|
||||
|
||||
## Error Responses
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 400 | Invalid username format |
|
||||
| 401 | Invalid or expired token |
|
||||
| 409 | Username already taken by another user |
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
@@ -0,0 +1,287 @@
|
||||
# WebSocket Sync API
|
||||
|
||||
Real-time bidirectional sync API for live updates and notifications.
|
||||
|
||||
**Endpoint**: `WS /ws/sync`
|
||||
**Auth**: Required (JWT token or Device authentication)
|
||||
|
||||
## Connection
|
||||
|
||||
Connect to the WebSocket endpoint with authentication:
|
||||
|
||||
```javascript
|
||||
const ws = new WebSocket('wss://bookhoard.example/ws/sync?token=eyJhbGci...');
|
||||
|
||||
// Or with device authentication
|
||||
const ws = new WebSocket('wss://bookhoard.example/ws/sync?device_id=uuid&device_key=key');
|
||||
```
|
||||
|
||||
## Message Format
|
||||
|
||||
All messages are JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "message_type",
|
||||
"data": { ... }
|
||||
}
|
||||
```
|
||||
|
||||
## Client→Server Messages
|
||||
|
||||
### Subscribe to Progress Updates
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "subscribe",
|
||||
"data": {
|
||||
"topic": "progress",
|
||||
"device_id": "device-uuid"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Unsubscribe
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "unsubscribe",
|
||||
"data": {
|
||||
"topic": "progress"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Heartbeat/Ping
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "ping",
|
||||
"data": {
|
||||
"timestamp": "2026-02-08T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Server→Client Messages
|
||||
|
||||
### Progress Updated
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "progress_updated",
|
||||
"data": {
|
||||
"media_item_id": "uuid",
|
||||
"device_id": "device-uuid",
|
||||
"percentage": 75.5,
|
||||
"position": 1234,
|
||||
"updated_at": "2026-02-08T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Conflict Detected
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "conflict_detected",
|
||||
"data": {
|
||||
"conflict_id": "uuid",
|
||||
"media_item_id": "uuid",
|
||||
"severity": "high",
|
||||
"created_at": "2026-02-08T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Scan Progress
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "scan_progress",
|
||||
"data": {
|
||||
"job_id": "uuid",
|
||||
"library_id": "uuid",
|
||||
"percentage": 45.5,
|
||||
"files_processed": 850,
|
||||
"total_files": 1523,
|
||||
"status": "in_progress"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Scan Complete
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "scan_complete",
|
||||
"data": {
|
||||
"job_id": "uuid",
|
||||
"library_id": "uuid",
|
||||
"files_added": 125,
|
||||
"files_updated": 45,
|
||||
"files_failed": 3,
|
||||
"completed_at": "2026-02-08T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Device Connected
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "device_connected",
|
||||
"data": {
|
||||
"device_id": "uuid",
|
||||
"device_name": "My Kobo",
|
||||
"connected_at": "2026-02-08T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Device Disconnected
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "device_disconnected",
|
||||
"data": {
|
||||
"device_id": "uuid",
|
||||
"disconnected_at": "2026-02-08T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pong Response
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "pong",
|
||||
"data": {
|
||||
"timestamp": "2026-02-08T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Connection Lifecycle
|
||||
|
||||
1. **Connect** - WebSocket connection established
|
||||
2. **Authenticate** - Send JWT token or device credentials via query string
|
||||
3. **Subscribed** - Server confirms authentication and subscribes to relevant topics
|
||||
4. **Messages** - Server pushes real-time updates
|
||||
5. **Heartbeat** - Client sends ping every 30 seconds
|
||||
6. **Disconnect** - Connection closed
|
||||
|
||||
## Authentication
|
||||
|
||||
### User Authentication
|
||||
|
||||
```
|
||||
wss://bookhoard.example/ws/sync?token=<jwt_token>
|
||||
```
|
||||
|
||||
### Device Authentication
|
||||
|
||||
```
|
||||
wss://bookhoard.example/ws/sync?device_id=<uuid>&device_key=<key>
|
||||
```
|
||||
|
||||
## Error Messages
|
||||
|
||||
### Authentication Failed
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "error",
|
||||
"data": {
|
||||
"code": "auth_failed",
|
||||
"message": "Invalid or expired token"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Subscription Failed
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "error",
|
||||
"data": {
|
||||
"code": "subscription_failed",
|
||||
"message": "Cannot subscribe to topic"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Usage Example
|
||||
|
||||
```javascript
|
||||
const ws = new WebSocket('wss://bookhoard.example/ws/sync?token=eyJhbGci...');
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log('Connected to sync WebSocket');
|
||||
|
||||
// Subscribe to progress updates
|
||||
ws.send(JSON.stringify({
|
||||
type: 'subscribe',
|
||||
data: { topic: 'progress', device_id: 'device-uuid' }
|
||||
}));
|
||||
|
||||
// Start heartbeat
|
||||
setInterval(() => {
|
||||
ws.send(JSON.stringify({
|
||||
type: 'ping',
|
||||
data: { timestamp: new Date().toISOString() }
|
||||
}));
|
||||
}, 30000);
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
const message = JSON.parse(event.data);
|
||||
|
||||
switch (message.type) {
|
||||
case 'progress_updated':
|
||||
console.log('Progress updated:', message.data);
|
||||
break;
|
||||
case 'conflict_detected':
|
||||
console.log('New conflict detected:', message.data);
|
||||
break;
|
||||
case 'scan_complete':
|
||||
console.log('Scan complete:', message.data);
|
||||
break;
|
||||
case 'pong':
|
||||
console.log('Pong received');
|
||||
break;
|
||||
default:
|
||||
console.log('Unknown message type:', message.type);
|
||||
}
|
||||
};
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error('WebSocket error:', error);
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
console.log('WebSocket connection closed');
|
||||
};
|
||||
```
|
||||
|
||||
## Topics
|
||||
|
||||
| Topic | Description | Events |
|
||||
|-------|-------------|--------|
|
||||
| progress | Reading progress updates | progress_updated |
|
||||
| conflicts | Sync conflict events | conflict_detected, conflict_resolved |
|
||||
| scanner | Library scan events | scan_progress, scan_complete |
|
||||
| devices | Device connection events | device_connected, device_disconnected |
|
||||
| queue | Sync queue events | queue_item_added, queue_item_processed |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Heartbeat**: Send ping every 30 seconds to keep connection alive
|
||||
2. **Reconnect**: Implement exponential backoff for reconnection
|
||||
3. **Message Queue**: Queue messages when disconnected and replay on reconnect
|
||||
4. **Error Handling**: Handle all error types gracefully
|
||||
5. **Cleanup**: Unsubscribe from topics when no longer needed
|
||||
|
||||
## Try It Out
|
||||
|
||||
<!-- API Explorer will be inserted here in Phase 3 -->
|
||||
+10
-1
@@ -31,6 +31,15 @@ Complete guide to Bookhoard documentation. Find what you need quickly.
|
||||
- [Complete API Reference](developer/api-reference.md) - Monolithic REST API reference (1,300+ lines)
|
||||
- [Split Endpoint Docs](developer/api/api-reference.md) - Individual endpoints with interactive API Explorer
|
||||
- [Collections API](developer/collections-api.md) - Collections management API
|
||||
- [Admin API](developer/api/admin/) - User management (admin operations)
|
||||
- [Books API](developer/api/books/) - Bulk book operations and downloads
|
||||
- [Devices API](developer/api/devices/) - Device sync and shelf management
|
||||
- [Conflicts API](developer/api/conflicts/) - Sync conflict resolution endpoints
|
||||
- [Queue API](developer/api/queue/) - Sync queue management endpoints
|
||||
- [Scanner API](developer/api/scanner/) - Library scanning and automated watch mode (admin)
|
||||
- [KOReader API](developer/api/koreader/) - KOReader sync protocol endpoints
|
||||
- [Kobo API](developer/api/kobo/) - Kobo sync protocol endpoints
|
||||
- [WebSocket API](developer/api/websocket/) - Real-time sync events
|
||||
|
||||
- **Protocol Specifications**
|
||||
- [Kobo Sync Protocol](developer/api/sync/kobo-protocol.md) - Kobo device sync
|
||||
@@ -133,5 +142,5 @@ Keep [PROJECT_GUIDELINES.md](PROJECT_GUIDELINES.md) in mind for documentation st
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2026-02-02
|
||||
**Last Updated**: 2026-02-08
|
||||
**Bookhoard Version**: 1.0
|
||||
|
||||
Reference in New Issue
Block a user