06e93fd7bd
CI build / Validate Gradle Wrapper (push) Successful in 2m30s
CI build / jlink (linux-x64, ubuntu-latest) (push) Failing after 1m12s
CI build / Build Jar (push) Failing after 2m18s
CI build / jlink (macOS-arm64, macos-15) (push) Has been cancelled
CI build / jlink (macOS-x64, macos-15-intel) (push) Has been cancelled
CI build / jlink (windows-x64, windows-latest) (push) Has been cancelled
CI build / Make linux-assets release (push) Has been cancelled
CI build / Make appimage release (push) Has been cancelled
CI build / Make debian-all release (push) Has been cancelled
CI build / Make linux-x64 release (push) Has been cancelled
CI build / Make macOS-arm64 release (push) Has been cancelled
CI build / Make macOS-x64 release (push) Has been cancelled
CI build / Make windows-x64 release (push) Has been cancelled
CI build / release (push) Has been cancelled
1734 lines
42 KiB
Markdown
1734 lines
42 KiB
Markdown
# Suwayomi-Server REST API Documentation
|
|
|
|
This document describes all REST API endpoints available in Suwayomi-Server.
|
|
|
|
**Base URL:** `http://localhost:4567/api/v1/`
|
|
|
|
---
|
|
|
|
## Authentication
|
|
|
|
All API endpoints (except where noted) require HTTP Basic Authentication.
|
|
|
|
### Authorization Header
|
|
|
|
Include the following header in your requests:
|
|
|
|
```
|
|
Authorization: Basic <base64-encoded-credentials>
|
|
```
|
|
|
|
### How to Generate the Header
|
|
|
|
1. Combine username and password with a colon: `username:password`
|
|
2. Encode the string in Base64
|
|
3. Prepend with `Basic `
|
|
|
|
**Example:**
|
|
- Username: `admin`
|
|
- Password: `password123`
|
|
- Credentials string: `admin:password123`
|
|
- Base64 encoded: `YWRtaW46cGFzc3dvcmQxMjM=`
|
|
- Header: `Authorization: Basic YWRtaW46cGFzc3dvcmQxMjM=`
|
|
|
|
### Default Credentials
|
|
|
|
The default username and password are configured in the server settings:
|
|
- Default username: `admin`
|
|
- Default password: `admin`
|
|
|
|
**Note:** These should be changed in production via server configuration.
|
|
|
|
### Authentication Modes
|
|
|
|
The server supports different authentication modes (configured in server settings):
|
|
|
|
1. **`BASIC_AUTH`** - Requires Basic Auth header for all API requests
|
|
2. **`SIMPLE_LOGIN`** - Uses cookie-based session authentication for web interface, but requires Basic Auth for API
|
|
3. **`NONE`** - No authentication required (not recommended for production)
|
|
|
|
### Unauthorized Response
|
|
|
|
If authentication fails, the server returns:
|
|
|
|
**HTTP 401 Unauthorized**
|
|
```
|
|
WWW-Authenticate: Basic
|
|
```
|
|
|
|
**Response Body:**
|
|
```json
|
|
{
|
|
"error": "Unauthorized",
|
|
"message": "Authentication required"
|
|
}
|
|
```
|
|
|
|
### WebSocket Authentication
|
|
|
|
WebSocket endpoints use the same Basic Authentication mechanism. Include the Authorization header when establishing the WebSocket connection.
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
1. [Extension Endpoints](#extension-endpoints)
|
|
2. [Source Endpoints](#source-endpoints)
|
|
3. [Manga Endpoints](#manga-endpoints)
|
|
4. [Chapter Endpoints](#chapter-endpoints)
|
|
5. [Category Endpoints](#category-endpoints)
|
|
6. [Backup Endpoints](#backup-endpoints)
|
|
7. [Download Endpoints](#download-endpoints)
|
|
8. [Update Endpoints](#update-endpoints)
|
|
9. [Track Endpoints](#track-endpoints)
|
|
10. [Global Meta Endpoints](#global-meta-endpoints)
|
|
11. [Settings Endpoints](#settings-endpoints)
|
|
12. [WebView Endpoints](#webview-endpoints)
|
|
13. [WebSocket Endpoints](#websocket-endpoints)
|
|
14. [OPDS Endpoints](#opds-endpoints)
|
|
|
|
---
|
|
|
|
## Extension Endpoints
|
|
|
|
### `GET /api/v1/extension/list`
|
|
|
|
- **What it does:** List all installed extensions
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** JSON array of ExtensionDataClass objects (HTTP 200)
|
|
|
|
**Response JSON Example:**
|
|
```json
|
|
[
|
|
{
|
|
"repo": "https://raw.githubusercontent.com/k对身体1/extensions/repo",
|
|
"apkName": "extensions/kofthub/Dramacafe",
|
|
"iconUrl": "/extension/icon/Dramacafe.apk",
|
|
"name": "Dramacafe",
|
|
"pkgName": "eu.kanade.tachiyomi.extension.en.dramacafe",
|
|
"versionName": "1.2.3",
|
|
"versionCode": 12,
|
|
"lang": "en",
|
|
"isNsfw": false,
|
|
"installed": true,
|
|
"hasUpdate": false,
|
|
"obsolete": false
|
|
}
|
|
]
|
|
```
|
|
|
|
### `GET /api/v1/extension/install/{pkgName}`
|
|
|
|
- **What it does:** Install an extension by package name
|
|
- **Expected request:** Path parameter: `pkgName` (string) - e.g., `eu.kanade.tachiyomi.extension.en.mangadex`
|
|
- **Expected response:** HTTP 201 (Created), HTTP 302 (Found), or HTTP 500 (Internal Server Error)
|
|
|
|
### `POST /api/v1/extension/install`
|
|
|
|
- **What it does:** Install an extension from uploaded APK file
|
|
- **Expected request:** Multipart form data with file field named "file" containing the extension APK
|
|
- **Expected response:** HTTP 201 (Created), HTTP 302 (Found), or HTTP 500 (Internal Server Error)
|
|
|
|
### `GET /api/v1/extension/update/{pkgName}`
|
|
|
|
- **What it does:** Update an extension by package name
|
|
- **Expected request:** Path parameter: `pkgName` (string)
|
|
- **Expected response:** HTTP 201 (Created), HTTP 302 (Found), HTTP 404 (Not Found), or HTTP 500 (Internal Server Error)
|
|
|
|
### `GET /api/v1/extension/uninstall/{pkgName}`
|
|
|
|
- **What it does:** Uninstall an extension by package name
|
|
- **Expected request:** Path parameter: `pkgName` (string)
|
|
- **Expected response:** HTTP 200 (OK), HTTP 404 (Not Found), or HTTP 500 (Internal Server Error)
|
|
|
|
### `GET /api/v1/extension/icon/{apkName}`
|
|
|
|
- **What it does:** Get the icon for an extension
|
|
- **Expected request:** Path parameter: `apkName` (string) - e.g., `Dramacafe.apk`
|
|
- **Expected response:** Image file (PNG/JPEG) with HTTP 200, or HTTP 404 (Not Found)
|
|
|
|
---
|
|
|
|
## Source Endpoints
|
|
|
|
### `GET /api/v1/source/list`
|
|
|
|
- **What it does:** List all available sources
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** JSON array of SourceDataClass objects (HTTP 200)
|
|
|
|
**Response JSON Example:**
|
|
```json
|
|
[
|
|
{
|
|
"id": "1234567890",
|
|
"name": "MangaDex",
|
|
"lang": "en",
|
|
"iconUrl": "/source/icon/1234567890",
|
|
"supportsLatest": true,
|
|
"isConfigurable": true,
|
|
"isNsfw": false,
|
|
"displayName": "MangaDex",
|
|
"baseUrl": "https://mangadex.org"
|
|
}
|
|
]
|
|
```
|
|
|
|
### `GET /api/v1/source/{sourceId}`
|
|
|
|
- **What it does:** Get information about a specific source
|
|
- **Expected request:** Path parameter: `sourceId` (long) - e.g., `1234567890`
|
|
- **Expected response:** JSON SourceDataClass object (HTTP 200) or HTTP 404 (Not Found)
|
|
|
|
### `GET /api/v1/source/{sourceId}/popular/{pageNum}`
|
|
|
|
- **What it does:** Get popular manga from a source
|
|
- **Expected request:** Path parameters: `sourceId` (long), `pageNum` (int)
|
|
- **Expected response:** JSON PagedMangaListDataClass object (HTTP 200)
|
|
|
|
**Response JSON Example:**
|
|
```json
|
|
{
|
|
"mangaList": [
|
|
{
|
|
"id": 1,
|
|
"sourceId": "1234567890",
|
|
"url": "/manga/12345",
|
|
"title": "One Piece",
|
|
"thumbnailUrl": "https://example.com/cover.jpg",
|
|
"thumbnailUrlLastFetched": 1699999999,
|
|
"initialized": true,
|
|
"artist": "Eiichiro Oda",
|
|
"author": "Eiichiro Oda",
|
|
"description": "Monkey D. Luffy sets off on an adventure...",
|
|
"genre": ["Action", "Adventure", "Comedy"],
|
|
"status": "ONGOING",
|
|
"inLibrary": true,
|
|
"inLibraryAt": 1699999999,
|
|
"source": null,
|
|
"meta": {},
|
|
"realUrl": "https://mangadex.org/manga/12345",
|
|
"lastFetchedAt": 1699999999,
|
|
"chaptersLastFetchedAt": 1699999999,
|
|
"updateStrategy": "ALWAYS_UPDATE",
|
|
"freshData": false,
|
|
"unreadCount": 100,
|
|
"downloadCount": 0,
|
|
"chapterCount": 1000,
|
|
"lastReadAt": null,
|
|
"lastChapterRead": null,
|
|
"age": 0,
|
|
"chaptersAge": 0,
|
|
"trackers": null
|
|
}
|
|
],
|
|
"hasNextPage": true
|
|
}
|
|
```
|
|
|
|
### `GET /api/v1/source/{sourceId}/latest/{pageNum}`
|
|
|
|
- **What it does:** Get latest manga from a source
|
|
- **Expected request:** Path parameters: `sourceId` (long), `pageNum` (int)
|
|
- **Expected response:** JSON PagedMangaListDataClass object (HTTP 200)
|
|
|
|
### `GET /api/v1/source/{sourceId}/preferences`
|
|
|
|
- **What it does:** Get source preferences/settings
|
|
- **Expected request:** Path parameter: `sourceId` (long)
|
|
- **Expected response:** JSON array of preference objects (HTTP 200)
|
|
|
|
**Response JSON Example:**
|
|
```json
|
|
[
|
|
{
|
|
"type": "EditTextPreference",
|
|
"props": {
|
|
"key": "username",
|
|
"title": "Username",
|
|
"summary": "",
|
|
"text": "",
|
|
"default": ""
|
|
}
|
|
},
|
|
{
|
|
"type": "SwitchPreferenceCompat",
|
|
"props": {
|
|
"key": "hentai",
|
|
"title": "Show Hentai",
|
|
"summary": "Show mature content",
|
|
"checked": false
|
|
}
|
|
}
|
|
]
|
|
```
|
|
|
|
### `POST /api/v1/source/{sourceId}/preferences`
|
|
|
|
- **What it does:** Set a source preference
|
|
- **Expected request:** Path parameter: `sourceId` (long), body: SourcePreferenceChange JSON object
|
|
|
|
**Request JSON Example:**
|
|
```json
|
|
{
|
|
"position": 0,
|
|
"value": "myusername"
|
|
}
|
|
```
|
|
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `GET /api/v1/source/{sourceId}/filters`
|
|
|
|
- **What it does:** Get source filters
|
|
- **Expected request:** Path parameter: `sourceId` (long), optional query param: `reset` (boolean)
|
|
- **Expected response:** JSON array of FilterObject objects (HTTP 200)
|
|
|
|
**Response JSON Example:**
|
|
```json
|
|
[
|
|
{
|
|
"type": "Header",
|
|
"filter": {
|
|
"name": "Content"
|
|
}
|
|
},
|
|
{
|
|
"type": "Select",
|
|
"filter": {
|
|
"name": "Genre",
|
|
"state": 0,
|
|
"values": ["All", "Action", "Adventure", "Comedy"]
|
|
}
|
|
},
|
|
{
|
|
"type": "Text",
|
|
"filter": {
|
|
"name": "Year",
|
|
"state": ""
|
|
}
|
|
},
|
|
{
|
|
"type": "CheckBox",
|
|
"filter": {
|
|
"name": "Completed",
|
|
"state": false
|
|
}
|
|
}
|
|
]
|
|
```
|
|
|
|
### `POST /api/v1/source/{sourceId}/filters`
|
|
|
|
- **What it does:** Set source filters
|
|
- **Expected request:** Path parameter: `sourceId` (long), body: FilterChange object or array of FilterChange objects
|
|
|
|
**Request JSON Example (Single filter):**
|
|
```json
|
|
{
|
|
"position": 1,
|
|
"state": "2"
|
|
}
|
|
```
|
|
|
|
**Request JSON Example (Multiple filters):**
|
|
```json
|
|
[
|
|
{ "position": 1, "state": "2" },
|
|
{ "position": 2, "state": "2023" },
|
|
{ "position": 3, "state": "true" }
|
|
]
|
|
```
|
|
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `GET /api/v1/source/{sourceId}/search`
|
|
|
|
- **What it does:** Search for manga in a single source
|
|
- **Expected request:** Path parameter: `sourceId` (long), query params: `searchTerm` (string), `pageNum` (int, default: 1)
|
|
- **Expected response:** JSON PagedMangaListDataClass object (HTTP 200)
|
|
|
|
### `POST /api/v1/source/{sourceId}/quick-search`
|
|
|
|
- **What it does:** Quick search manga in a source using filters
|
|
- **Expected request:** Path parameter: `sourceId` (long), query param: `pageNum` (int, default: 1), body: FilterData object
|
|
|
|
**Request JSON Example:**
|
|
```json
|
|
{
|
|
"searchTerm": "One Piece",
|
|
"filter": [
|
|
{ "position": 1, "state": "0" },
|
|
{ "position": 2, "state": "" }
|
|
]
|
|
}
|
|
```
|
|
|
|
- **Expected response:** JSON PagedMangaListDataClass object (HTTP 200)
|
|
|
|
---
|
|
|
|
## Manga Endpoints
|
|
|
|
### `GET /api/v1/manga/{mangaId}`
|
|
|
|
- **What it does:** Get manga information
|
|
- **Expected request:** Path parameter: `mangaId` (int), optional query param: `onlineFetch` (boolean)
|
|
- **Expected response:** JSON MangaDataClass object (HTTP 200) or HTTP 404 (Not Found)
|
|
|
|
**Response JSON Example:**
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"sourceId": "1234567890",
|
|
"url": "/manga/12345",
|
|
"title": "One Piece",
|
|
"thumbnailUrl": "https://example.com/cover.jpg",
|
|
"thumbnailUrlLastFetched": 1699999999,
|
|
"initialized": true,
|
|
"artist": "Eiichiro Oda",
|
|
"author": "Eiichiro Oda",
|
|
"description": "Monkey D. Luffy sets off on an adventure...",
|
|
"genre": ["Action", "Adventure", "Comedy", "Fantasy"],
|
|
"status": "ONGOING",
|
|
"inLibrary": true,
|
|
"inLibraryAt": 1699999999,
|
|
"source": {
|
|
"id": "1234567890",
|
|
"name": "MangaDex",
|
|
"lang": "en",
|
|
"iconUrl": "/source/icon/1234567890",
|
|
"supportsLatest": true,
|
|
"isConfigurable": true,
|
|
"isNsfw": false,
|
|
"displayName": "MangaDex",
|
|
"baseUrl": "https://mangadex.org"
|
|
},
|
|
"meta": {},
|
|
"realUrl": "https://mangadex.org/manga/12345",
|
|
"lastFetchedAt": 1699999999,
|
|
"chaptersLastFetchedAt": 1699999999,
|
|
"updateStrategy": "ALWAYS_UPDATE",
|
|
"freshData": false,
|
|
"unreadCount": 100,
|
|
"downloadCount": 0,
|
|
"chapterCount": 1000,
|
|
"lastReadAt": 1699999999,
|
|
"lastChapterRead": {
|
|
"id": 100,
|
|
"url": "/chapter/12345/1",
|
|
"name": "Chapter 1: Dawn of Adventure",
|
|
"uploadDate": 1699999999,
|
|
"chapterNumber": 1.0,
|
|
"scanlator": "MangaDex",
|
|
"mangaId": 1,
|
|
"read": true,
|
|
"bookmarked": false,
|
|
"lastPageRead": 20,
|
|
"lastReadAt": 1699999999,
|
|
"index": 1,
|
|
"fetchedAt": 1699999999,
|
|
"realUrl": "https://mangadex.org/chapter/12345/1",
|
|
"downloaded": true,
|
|
"pageCount": 20,
|
|
"chapterCount": 1000,
|
|
"meta": {}
|
|
},
|
|
"age": 0,
|
|
"chaptersAge": 0,
|
|
"trackers": [
|
|
{
|
|
"trackerId": 1,
|
|
"trackerName": "MyAnimeList",
|
|
"remoteId": "12345",
|
|
"remoteUrl": "https://myanimelist.net/manga/12345",
|
|
"title": "One Piece",
|
|
"lastChapterRead": 100,
|
|
"totalChapters": 1000,
|
|
"score": 9.5,
|
|
"status": "Reading",
|
|
"startedReadingDate": null,
|
|
"finishedReadingDate": null,
|
|
"private": false
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### `GET /api/v1/manga/{mangaId}/full`
|
|
|
|
- **What it does:** Get full manga information with all data filled in
|
|
- **Expected request:** Path parameter: `mangaId` (int), optional query param: `onlineFetch` (boolean)
|
|
- **Expected response:** JSON MangaDataClass object (HTTP 200) or HTTP 404 (Not Found)
|
|
|
|
### `GET /api/v1/manga/{mangaId}/thumbnail`
|
|
|
|
- **What it does:** Get manga thumbnail image
|
|
- **Expected request:** Path parameter: `mangaId` (int)
|
|
- **Expected response:** Image file (JPEG/PNG) with HTTP 200 or HTTP 404 (Not Found)
|
|
|
|
### `GET /api/v1/manga/{mangaId}/category`
|
|
|
|
- **What it does:** Get categories assigned to a manga
|
|
- **Expected request:** Path parameter: `mangaId` (int)
|
|
- **Expected response:** JSON array of CategoryDataClass objects (HTTP 200)
|
|
|
|
**Response JSON Example:**
|
|
```json
|
|
[
|
|
{
|
|
"id": 1,
|
|
"order": 0,
|
|
"name": "Favorites",
|
|
"default": false,
|
|
"size": 10,
|
|
"includeInUpdate": "INCLUDE",
|
|
"includeInDownload": "INCLUDE",
|
|
"meta": {}
|
|
}
|
|
]
|
|
```
|
|
|
|
### `GET /api/v1/manga/{mangaId}/category/{categoryId}`
|
|
|
|
- **What it does:** Add manga to a category
|
|
- **Expected request:** Path parameters: `mangaId` (int), `categoryId` (int)
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `DELETE /api/v1/manga/{mangaId}/category/{categoryId}`
|
|
|
|
- **What it does:** Remove manga from a category
|
|
- **Expected request:** Path parameters: `mangaId` (int), `categoryId` (int)
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `GET /api/v1/manga/{mangaId}/library`
|
|
|
|
- **What it does:** Add manga to library
|
|
- **Expected request:** Path parameter: `mangaId` (int)
|
|
- **Expected response:** HTTP 200 (OK) or HTTP 404 (Not Found)
|
|
|
|
### `DELETE /api/v1/manga/{mangaId}/library`
|
|
|
|
- **What it does:** Remove manga from library
|
|
- **Expected request:** Path parameter: `mangaId` (int)
|
|
- **Expected response:** HTTP 200 (OK) or HTTP 404 (Not Found)
|
|
|
|
### `PATCH /api/v1/manga/{mangaId}/meta`
|
|
|
|
- **What it does:** Add/update metadata to a manga
|
|
- **Expected request:** Path parameter: `mangaId` (int), form params: `key` (string), `value` (string)
|
|
- **Expected response:** HTTP 200 (OK) or HTTP 404 (Not Found)
|
|
|
|
### `GET /api/v1/manga/{mangaId}/chapters`
|
|
|
|
- **What it does:** Get manga chapter list
|
|
- **Expected request:** Path parameter: `mangaId` (int), optional query param: `onlineFetch` (boolean)
|
|
- **Expected response:** JSON array of ChapterDataClass objects (HTTP 200) or HTTP 404 (Not Found)
|
|
|
|
**Response JSON Example:**
|
|
```json
|
|
[
|
|
{
|
|
"id": 100,
|
|
"url": "/chapter/12345/1000",
|
|
"name": "Chapter 1000: The Final Battle",
|
|
"uploadDate": 1699999999,
|
|
"chapterNumber": 1000.0,
|
|
"scanlator": "MangaDex",
|
|
"mangaId": 1,
|
|
"read": false,
|
|
"bookmarked": false,
|
|
"lastPageRead": 0,
|
|
"lastReadAt": 0,
|
|
"index": 1000,
|
|
"fetchedAt": 1699999999,
|
|
"realUrl": "https://mangadex.org/chapter/12345/1000",
|
|
"downloaded": false,
|
|
"pageCount": 18,
|
|
"chapterCount": 1000,
|
|
"meta": {}
|
|
},
|
|
{
|
|
"id": 99,
|
|
"url": "/chapter/12345/999",
|
|
"name": "Chapter 999: The Beginning",
|
|
"uploadDate": 1699999998,
|
|
"chapterNumber": 999.0,
|
|
"scanlator": "MangaDex",
|
|
"mangaId": 1,
|
|
"read": true,
|
|
"bookmarked": true,
|
|
"lastPageRead": 15,
|
|
"lastReadAt": 1699999999,
|
|
"index": 999,
|
|
"fetchedAt": 1699999998,
|
|
"realUrl": "https://mangadex.org/chapter/12345/999",
|
|
"downloaded": true,
|
|
"pageCount": 15,
|
|
"chapterCount": 1000,
|
|
"meta": {}
|
|
}
|
|
]
|
|
```
|
|
|
|
### `POST /api/v1/manga/{mangaId}/chapter/batch`
|
|
|
|
- **What it does:** Batch update chapters (mark as read, bookmark, etc.)
|
|
- **Expected request:** Path parameter: `mangaId` (int), body: MangaChapterBatchEditInput object
|
|
|
|
**Request JSON Example (Mark as read and bookmark):**
|
|
```json
|
|
{
|
|
"chapterIds": [100, 101, 102],
|
|
"chapterIndexes": null,
|
|
"change": {
|
|
"isRead": true,
|
|
"isBookmarked": true,
|
|
"lastPageRead": null,
|
|
"delete": null
|
|
}
|
|
}
|
|
```
|
|
|
|
**Request JSON Example (Mark previous as read):**
|
|
```json
|
|
{
|
|
"chapterIds": [100],
|
|
"chapterIndexes": null,
|
|
"change": {
|
|
"isRead": null,
|
|
"isBookmarked": null,
|
|
"lastPageRead": null,
|
|
"delete": null,
|
|
"markPrevRead": true
|
|
}
|
|
}
|
|
```
|
|
|
|
**Request JSON Example (Delete downloaded chapters):**
|
|
```json
|
|
{
|
|
"chapterIds": [100, 101],
|
|
"change": {
|
|
"isRead": null,
|
|
"isBookmarked": null,
|
|
"lastPageRead": null,
|
|
"delete": true
|
|
}
|
|
}
|
|
```
|
|
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `GET /api/v1/manga/{mangaId}/chapter/{chapterIndex}`
|
|
|
|
- **What it does:** Get a specific chapter with pages
|
|
- **Expected request:** Path parameters: `mangaId` (int), `chapterIndex` (int)
|
|
- **Expected response:** JSON ChapterDataClass object (HTTP 200) or HTTP 404 (Not Found)
|
|
|
|
### `PATCH /api/v1/manga/{mangaId}/chapter/{chapterIndex}`
|
|
|
|
- **What it does:** Modify chapter (read status, bookmark, etc.)
|
|
- **Expected request:** Path parameters: `mangaId` (int), `chapterIndex` (int), form params: `read` (boolean, optional), `bookmarked` (boolean, optional), `markPrevRead` (boolean, optional), `lastPageRead` (int, optional)
|
|
|
|
**Form Data Example:**
|
|
```
|
|
read=true
|
|
bookmarked=false
|
|
lastPageRead=5
|
|
markPrevRead=true
|
|
```
|
|
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `PUT /api/v1/manga/{mangaId}/chapter/{chapterIndex}`
|
|
|
|
- **What it does:** Modify chapter (same as PATCH)
|
|
- **Expected request:** Same as PATCH
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `DELETE /api/v1/manga/{mangaId}/chapter/{chapterIndex}`
|
|
|
|
- **What it does:** Delete downloaded chapter files
|
|
- **Expected request:** Path parameters: `mangaId` (int), `chapterIndex` (int)
|
|
- **Expected response:** HTTP 200 (OK) or HTTP 404 (Not Found)
|
|
|
|
### `PATCH /api/v1/manga/{mangaId}/chapter/{chapterIndex}/meta`
|
|
|
|
- **What it does:** Add metadata to a chapter
|
|
- **Expected request:** Path parameters: `mangaId` (int), `chapterIndex` (int), form params: `key` (string), `value` (string)
|
|
- **Expected response:** HTTP 200 (OK) or HTTP 404 (Not Found)
|
|
|
|
### `GET /api/v1/manga/{mangaId}/chapter/{chapterIndex}/page/{index}`
|
|
|
|
- **What it does:** Get a chapter page image
|
|
- **Expected request:** Path parameters: `mangaId` (int), `chapterIndex` (int), `index` (int), optional query params: `updateProgress` (boolean), `format` (string), `opds` (boolean)
|
|
- **Expected response:** Image file with HTTP 200 or HTTP 404 (Not Found)
|
|
|
|
---
|
|
|
|
## Chapter Endpoints
|
|
|
|
### `POST /api/v1/chapter/batch`
|
|
|
|
- **What it does:** Batch update chapters across any manga
|
|
- **Expected request:** Body: ChapterBatchEditInput object
|
|
|
|
**Request JSON Example:**
|
|
```json
|
|
{
|
|
"chapterIds": [100, 101, 102, 200, 201],
|
|
"change": {
|
|
"isRead": true,
|
|
"isBookmarked": false,
|
|
"lastPageRead": null,
|
|
"delete": null
|
|
}
|
|
}
|
|
```
|
|
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `GET /api/v1/chapter/{chapterId}/download`
|
|
|
|
- **What it does:** Download chapter as CBZ file
|
|
- **Expected request:** Path parameter: `chapterId` (int), optional query param: `markAsRead` (boolean)
|
|
- **Expected response:** CBZ file stream with HTTP 200 or HTTP 404 (Not Found)
|
|
|
|
**Response Headers:**
|
|
```
|
|
Content-Type: application/vnd.comicbook+zip
|
|
Content-Disposition: attachment; filename="One Piece - Chapter 1000.cbz"
|
|
Content-Length: 1234567
|
|
```
|
|
|
|
### `HEAD /api/v1/chapter/{chapterId}/download`
|
|
|
|
- **What it does:** Get CBZ file metadata (HEAD request)
|
|
- **Expected request:** Path parameter: `chapterId` (int)
|
|
- **Expected response:** HTTP headers with file info, or HTTP 404 (Not Found)
|
|
|
|
---
|
|
|
|
## Category Endpoints
|
|
|
|
### `GET /api/v1/category`
|
|
|
|
- **What it does:** Get list of all categories
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** JSON array of CategoryDataClass objects (HTTP 200)
|
|
|
|
**Response JSON Example:**
|
|
```json
|
|
[
|
|
{
|
|
"id": 1,
|
|
"order": 0,
|
|
"name": "Favorites",
|
|
"default": false,
|
|
"size": 10,
|
|
"includeInUpdate": "INCLUDE",
|
|
"includeInDownload": "INCLUDE",
|
|
"meta": {}
|
|
},
|
|
{
|
|
"id": 2,
|
|
"order": 1,
|
|
"name": "Reading",
|
|
"default": false,
|
|
"size": 5,
|
|
"includeInUpdate": "INCLUDE",
|
|
"includeInDownload": "EXCLUDE",
|
|
"meta": {}
|
|
},
|
|
{
|
|
"id": 3,
|
|
"order": 2,
|
|
"name": "Default",
|
|
"default": true,
|
|
"size": 100,
|
|
"includeInUpdate": "INCLUDE",
|
|
"includeInDownload": "INCLUDE",
|
|
"meta": {}
|
|
}
|
|
]
|
|
```
|
|
|
|
### `POST /api/v1/category`
|
|
|
|
- **What it does:** Create a new category
|
|
- **Expected request:** Form param: `name` (string)
|
|
|
|
**Form Data Example:**
|
|
```
|
|
name=My Category
|
|
```
|
|
|
|
- **Expected response:** HTTP 200 (OK) or HTTP 400 (Bad Request)
|
|
|
|
### `PATCH /api/v1/category/reorder`
|
|
|
|
- **What it does:** Reorder categories
|
|
- **Expected request:** Form params: `from` (int), `to` (int)
|
|
|
|
**Form Data Example:**
|
|
```
|
|
from=0
|
|
to=2
|
|
```
|
|
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `GET /api/v1/category/{categoryId}`
|
|
|
|
- **What it does:** Get manga in a category
|
|
- **Expected request:** Path parameter: `categoryId` (int)
|
|
- **Expected response:** JSON array of MangaDataClass objects (HTTP 200)
|
|
|
|
### `PATCH /api/v1/category/{categoryId}`
|
|
|
|
- **What it does:** Modify a category
|
|
- **Expected request:** Path parameter: `categoryId` (int), optional form params: `name` (string), `default` (boolean), `includeInUpdate` (int), `includeInDownload` (int)
|
|
|
|
**Form Data Example:**
|
|
```
|
|
name=Updated Name
|
|
default=false
|
|
includeInUpdate=1
|
|
includeInDownload=0
|
|
```
|
|
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `DELETE /api/v1/category/{categoryId}`
|
|
|
|
- **What it does:** Delete a category
|
|
- **Expected request:** Path parameter: `categoryId` (int)
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `PATCH /api/v1/category/{categoryId}/meta`
|
|
|
|
- **What it does:** Add metadata to a category
|
|
- **Expected request:** Path parameter: `categoryId` (int), form params: `key` (string), `value` (string)
|
|
- **Expected response:** HTTP 200 (OK) or HTTP 404 (Not Found)
|
|
|
|
---
|
|
|
|
## Backup Endpoints
|
|
|
|
### `POST /api/v1/backup/import`
|
|
|
|
- **What it does:** Restore a backup from request body
|
|
- **Expected request:** Body: Tachiyomi protobuf backup data (binary)
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `POST /api/v1/backup/import/file`
|
|
|
|
- **What it does:** Restore a backup from file upload
|
|
- **Expected request:** Multipart form data with file named "backup.proto.gz"
|
|
- **Expected response:** HTTP 200 (OK) or HTTP 404 (Not Found)
|
|
|
|
### `POST /api/v1/backup/validate`
|
|
|
|
- **What it does:** Validate a backup from request body
|
|
- **Expected request:** Body: Tachiyomi protobuf backup data (binary)
|
|
- **Expected response:** JSON ValidationResult object (HTTP 200)
|
|
|
|
**Response JSON Example:**
|
|
```json
|
|
{
|
|
"missingSources": ["com.source.example"],
|
|
"missingTrackers": ["myanimelist"],
|
|
"isValid": false
|
|
}
|
|
```
|
|
|
|
### `POST /api/v1/backup/validate/file`
|
|
|
|
- **What it does:** Validate a backup from file upload
|
|
- **Expected request:** Multipart form data with file named "backup.proto.gz"
|
|
- **Expected response:** JSON ValidationResult object (HTTP 200)
|
|
|
|
### `GET /api/v1/backup/export`
|
|
|
|
- **What it does:** Create a backup (returns as body)
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** Binary stream (protobuf) with HTTP 200
|
|
|
|
**Response Headers:**
|
|
```
|
|
Content-Type: application/octet-stream
|
|
```
|
|
|
|
### `GET /api/v1/backup/export/file`
|
|
|
|
- **What it does:** Create a backup (returns as file download)
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** Binary stream (protobuf) as file download with HTTP 200
|
|
|
|
**Response Headers:**
|
|
```
|
|
Content-Type: application/octet-stream
|
|
Content-Disposition: attachment; filename="suwayomi_backup_20240101.proto.gz"
|
|
```
|
|
|
|
---
|
|
|
|
## Download Endpoints
|
|
|
|
### `GET /api/v1/downloads/start`
|
|
|
|
- **What it does:** Start the downloader
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `GET /api/v1/downloads/stop`
|
|
|
|
- **What it does:** Stop the downloader
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `GET /api/v1/downloads/clear`
|
|
|
|
- **What it does:** Clear the download queue
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `GET /api/v1/download/{mangaId}/chapter/{chapterIndex}`
|
|
|
|
- **What it does:** Queue a chapter for download
|
|
- **Expected request:** Path parameters: `mangaId` (int), `chapterIndex` (int)
|
|
- **Expected response:** HTTP 200 (OK) or HTTP 404 (Not Found)
|
|
|
|
### `DELETE /api/v1/download/{mangaId}/chapter/{chapterIndex}`
|
|
|
|
- **What it does:** Remove a chapter from download queue
|
|
- **Expected request:** Path parameters: `mangaId` (int), `chapterIndex` (int)
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `PATCH /api/v1/download/{mangaId}/chapter/{chapterIndex}/reorder/{to}`
|
|
|
|
- **What it does:** Reorder a chapter in download queue
|
|
- **Expected request:** Path parameters: `mangaId` (int), `chapterIndex` (int), `to` (int)
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `POST /api/v1/download/batch`
|
|
|
|
- **What it does:** Queue multiple chapters for download
|
|
- **Expected request:** Body: EnqueueInput object
|
|
|
|
**Request JSON Example:**
|
|
```json
|
|
{
|
|
"chapterIds": [100, 101, 102, 103, 104]
|
|
}
|
|
```
|
|
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `DELETE /api/v1/download/batch`
|
|
|
|
- **What it does:** Remove multiple chapters from download queue
|
|
- **Expected request:** Body: EnqueueInput object
|
|
|
|
**Request JSON Example:**
|
|
```json
|
|
{
|
|
"chapterIds": [100, 101, 102]
|
|
}
|
|
```
|
|
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
---
|
|
|
|
## Update Endpoints
|
|
|
|
### `GET /api/v1/update/recentChapters/{pageNum}`
|
|
|
|
- **What it does:** Get recently updated chapters
|
|
- **Expected request:** Path parameter: `pageNum` (int)
|
|
- **Expected response:** JSON PagedMangaChapterListDataClass object (HTTP 200)
|
|
|
|
**Response JSON Example:**
|
|
```json
|
|
{
|
|
"mangaList": [
|
|
{
|
|
"id": 1,
|
|
"mangaId": 1,
|
|
"mangaTitle": "One Piece",
|
|
"mangaThumbnail": "https://example.com/cover.jpg",
|
|
"chapters": [
|
|
{
|
|
"id": 100,
|
|
"url": "/chapter/1/100",
|
|
"name": "Chapter 100",
|
|
"uploadDate": 1699999999,
|
|
"chapterNumber": 100.0,
|
|
"scanlator": "MangaDex",
|
|
"read": false,
|
|
"bookmarked": false,
|
|
"lastPageRead": 0,
|
|
"lastReadAt": 0,
|
|
"index": 100,
|
|
"fetchedAt": 1699999999,
|
|
"downloaded": false
|
|
}
|
|
]
|
|
}
|
|
],
|
|
"hasNextPage": true
|
|
}
|
|
```
|
|
|
|
### `POST /api/v1/update/fetch`
|
|
|
|
- **What it does:** Start library update (optionally for specific category)
|
|
- **Expected request:** Optional form param: `categoryId` (int)
|
|
|
|
**Form Data Examples:**
|
|
```
|
|
(Updates entire library)
|
|
```
|
|
|
|
or
|
|
```
|
|
categoryId=1
|
|
```
|
|
- **Expected response:** HTTP 200 (OK) or HTTP 400 (Bad Request)
|
|
|
|
### `POST /api/v1/update/reset`
|
|
|
|
- **What it does:** Stop and reset the updater
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `GET /api/v1/update/summary`
|
|
|
|
- **What it does:** Get updater status summary
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** JSON UpdateStatus object (HTTP 200)
|
|
|
|
**Response JSON Example:**
|
|
```json
|
|
{
|
|
"status": "Running",
|
|
"progress": {
|
|
"current": 5,
|
|
"total": 100
|
|
},
|
|
"pending": 0,
|
|
"running": true,
|
|
"mangaDone": 5,
|
|
"mangaTotal": 100,
|
|
"chapterDone": 50,
|
|
"chapterAdded": 10
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Track Endpoints
|
|
|
|
### `GET /api/v1/track/list`
|
|
|
|
- **What it does:** List all supported trackers
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** JSON array of TrackerDataClass objects (HTTP 200)
|
|
|
|
**Response JSON Example:**
|
|
```json
|
|
[
|
|
{
|
|
"id": 1,
|
|
"name": "MyAnimeList",
|
|
"icon": "/track/thumbnail/1",
|
|
"isLogin": false,
|
|
"authUrl": "https://myanimelist.net/api/v2/oauth/authorize"
|
|
},
|
|
{
|
|
"id": 2,
|
|
"name": "AniList",
|
|
"icon": "/track/thumbnail/2",
|
|
"isLogin": true,
|
|
"authUrl": "https://anilist.co/api/v2/oauth/authorize"
|
|
}
|
|
]
|
|
```
|
|
|
|
### `POST /api/v1/track/login`
|
|
|
|
- **What it does:** Login to a tracker
|
|
- **Expected request:** Body: LoginInput object
|
|
|
|
**Request JSON Example:**
|
|
```json
|
|
{
|
|
"trackerId": 1,
|
|
"callbackUrl": "suwayomi://auth/myanimelist",
|
|
"username": "myuser",
|
|
"password": "mypassword"
|
|
}
|
|
```
|
|
|
|
- **Expected response:** HTTP 200 (OK) or HTTP 404 (Not Found)
|
|
|
|
### `POST /api/v1/track/logout`
|
|
|
|
- **What it does:** Logout from a tracker
|
|
- **Expected request:** Body: LogoutInput object
|
|
|
|
**Request JSON Example:**
|
|
```json
|
|
{
|
|
"trackerId": 1
|
|
}
|
|
```
|
|
|
|
- **Expected response:** HTTP 200 (OK) or HTTP 404 (Not Found)
|
|
|
|
### `POST /api/v1/track/search`
|
|
|
|
- **What it does:** Search for manga on a tracker
|
|
- **Expected request:** Body: SearchInput object
|
|
|
|
**Request JSON Example:**
|
|
```json
|
|
{
|
|
"trackerId": 1,
|
|
"title": "One Piece"
|
|
}
|
|
```
|
|
|
|
- **Expected response:** HTTP 200 (OK) or HTTP 404 (Not Found)
|
|
|
|
**Response JSON Example:**
|
|
```json
|
|
[
|
|
{
|
|
"trackerId": 1,
|
|
"remoteId": "12345",
|
|
"remoteUrl": "https://myanimelist.net/manga/12345",
|
|
"title": "One Piece",
|
|
"coverUrl": "https://example.com/cover.jpg",
|
|
"summary": "A story about pirates...",
|
|
"match": 95
|
|
}
|
|
]
|
|
```
|
|
|
|
### `POST /api/v1/track/bind`
|
|
|
|
- **What it does:** Bind a manga to a track record
|
|
- **Expected request:** Query params: `mangaId` (int), `trackerId` (int), `remoteId` (string), `private` (boolean)
|
|
|
|
**Request URL Example:**
|
|
```
|
|
/api/v1/track/bind?mangaId=1&trackerId=1&remoteId=12345&private=false
|
|
```
|
|
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `POST /api/v1/track/update`
|
|
|
|
- **What it does:** Update track record with tracker
|
|
- **Expected request:** Body: UpdateInput object
|
|
|
|
**Request JSON Example (Update reading progress):**
|
|
```json
|
|
{
|
|
"recordId": 1,
|
|
"status": 1,
|
|
"lastChapterRead": 100,
|
|
"scoreString": "9.5",
|
|
"startDate": null,
|
|
"finishDate": null,
|
|
"private": false
|
|
}
|
|
```
|
|
|
|
**Request JSON Example (Unbind from tracker):**
|
|
```json
|
|
{
|
|
"recordId": 1,
|
|
"unbind": true
|
|
}
|
|
```
|
|
|
|
**Status values:**
|
|
- 1 = Reading
|
|
- 2 = Completed
|
|
- 3 = On Hold
|
|
- 4 = Dropped
|
|
- 6 = Plan to Read
|
|
|
|
- **Expected response:** HTTP 200 (OK)
|
|
|
|
### `GET /api/v1/track/{trackerId}/thumbnail`
|
|
|
|
- **What it does:** Get tracker thumbnail image
|
|
- **Expected request:** Path parameter: `trackerId` (int)
|
|
- **Expected response:** Image file with HTTP 200 or HTTP 404 (Not Found)
|
|
|
|
---
|
|
|
|
## Global Meta Endpoints
|
|
|
|
### `GET /api/v1/meta`
|
|
|
|
- **What it does:** Get all global metadata
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** HTTP 200 (OK) with JSON key-value pairs
|
|
|
|
**Response JSON Example:**
|
|
```json
|
|
{
|
|
"customKey": "customValue",
|
|
"lastSync": "1234567890"
|
|
}
|
|
```
|
|
|
|
### `PATCH /api/v1/meta`
|
|
|
|
- **What it does:** Add/update global metadata
|
|
- **Expected request:** Form params: `key` (string), `value` (string)
|
|
|
|
**Form Data Example:**
|
|
```
|
|
key=lastSync
|
|
value=1234567890
|
|
```
|
|
|
|
- **Expected response:** HTTP 200 (OK) or HTTP 404 (Not Found)
|
|
|
|
---
|
|
|
|
## Settings Endpoints
|
|
|
|
### `GET /api/v1/settings/about`
|
|
|
|
- **What it does:** Get application information
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** JSON AboutDataClass object (HTTP 200)
|
|
|
|
**Response JSON Example:**
|
|
```json
|
|
{
|
|
"name": "Suwayomi-Server",
|
|
"version": "0.7.0",
|
|
"revision": "7a1b2c3",
|
|
"buildType": "release",
|
|
"buildTime": 1704067200,
|
|
"github": "https://github.com/Suwayomi/Suwayomi-Server",
|
|
"discord": "https://discord.gg/Suwayomi"
|
|
}
|
|
```
|
|
|
|
### `GET /api/v1/settings/check-update`
|
|
|
|
- **What it does:** Check for application updates
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** JSON array of UpdateDataClass objects (HTTP 200)
|
|
|
|
**Response JSON Example:**
|
|
```json
|
|
[
|
|
{
|
|
"name": "0.8.0",
|
|
"tagName": "v0.8.0",
|
|
"body": "## Bug fixes\n- Fixed bug #123\n- Improved performance",
|
|
"htmlUrl": "https://github.com/Suwayomi/Suwayomi-Server/releases/tag/v0.8.0",
|
|
"prerelease": false
|
|
}
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
## WebView Endpoints
|
|
|
|
### `GET /api/v1/webview`
|
|
|
|
- **What it does:** Open webview interface
|
|
- **Expected request:** Optional query param: `lang` (string)
|
|
|
|
**Request URL Example:**
|
|
```
|
|
/api/v1/webview?lang=en
|
|
```
|
|
|
|
- **Expected response:** HTML page (HTTP 200)
|
|
|
|
---
|
|
|
|
## WebSocket Endpoints
|
|
|
|
The server provides WebSocket connections for real-time communication and updates.
|
|
|
|
**Note:** Actions like starting/stopping downloads or updates are done via HTTP endpoints (`GET /api/v1/downloads/start`, `GET /api/v1/downloads/stop`, `POST /api/v1/update/fetch`, etc.), not through WebSocket messages. WebSocket connections are primarily for receiving real-time status updates.
|
|
|
|
---
|
|
|
|
### `WS /api/v1/downloads`
|
|
|
|
- **What it does:** Real-time download queue status updates
|
|
- **Expected request:** WebSocket connection with authentication
|
|
|
|
#### Messages You Can Send to Server:
|
|
|
|
**Request current download status:**
|
|
```
|
|
STATUS
|
|
```
|
|
- **Expected Response from Server:**
|
|
```json
|
|
{
|
|
"status": "Started",
|
|
"queue": [
|
|
{
|
|
"mangaId": 1,
|
|
"chapterId": 100,
|
|
"chapterIndex": 100,
|
|
"mangaTitle": "One Piece",
|
|
"chapterTitle": "Chapter 100",
|
|
"state": "DOWNLOADING",
|
|
"progress": 50,
|
|
"tries": 0,
|
|
"downloadSpeed": 1024000,
|
|
"errorMessage": null
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**State values:** `Queued`, `Downloading`, `Completed`, `Error`
|
|
|
|
**Invalid command response:**
|
|
```
|
|
Invalid command.
|
|
Supported commands are:
|
|
- STATUS
|
|
sends the current download status
|
|
```
|
|
|
|
#### Messages Received from Server (Automatic Updates):
|
|
|
|
The server automatically sends status updates when:
|
|
- A download starts/completes/fails
|
|
- Queue changes (add/remove/reorder)
|
|
|
|
**Example update:**
|
|
```json
|
|
{
|
|
"status": "Started",
|
|
"queue": [
|
|
{
|
|
"mangaId": 1,
|
|
"chapterId": 100,
|
|
"chapterIndex": 100,
|
|
"mangaTitle": "One Piece",
|
|
"chapterTitle": "Chapter 100",
|
|
"state": "Completed",
|
|
"progress": 100,
|
|
"tries": 0,
|
|
"downloadSpeed": 0,
|
|
"errorMessage": null
|
|
}
|
|
],
|
|
"downloads": [
|
|
{
|
|
"downloadQueueItem": {
|
|
"mangaId": 1,
|
|
"chapterId": 101,
|
|
"chapterIndex": 101,
|
|
"mangaTitle": "One Piece",
|
|
"chapterTitle": "Chapter 101",
|
|
"state": "Downloading",
|
|
"progress": 25,
|
|
"tries": 0
|
|
},
|
|
"downloadSpeed": 1024000
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `WS /api/v1/update`
|
|
|
|
- **What it does:** Real-time library update progress
|
|
- **Expected request:** WebSocket connection with authentication
|
|
|
|
#### Messages You Can Send to Server:
|
|
|
|
**Request current update status:**
|
|
```
|
|
STATUS
|
|
```
|
|
- **Expected Response from Server:**
|
|
```json
|
|
{
|
|
"status": "Running",
|
|
"pending": 0,
|
|
"running": true,
|
|
"mangaDone": 5,
|
|
"mangaTotal": 100,
|
|
"chapterDone": 50,
|
|
"chapterAdded": 10,
|
|
"progress": {
|
|
"current": 5,
|
|
"total": 100
|
|
},
|
|
"errors": []
|
|
}
|
|
```
|
|
|
|
**Status values:** `Idle`, `Running`, `Completed`, `Stopped`
|
|
|
|
**Invalid command response:**
|
|
```
|
|
Invalid command.
|
|
Supported commands are:
|
|
- STATUS
|
|
sends the current update status
|
|
```
|
|
|
|
#### Messages Received from Server (Automatic Updates):
|
|
|
|
The server automatically sends status updates during library updates.
|
|
|
|
**Example update:**
|
|
```json
|
|
{
|
|
"status": "Running",
|
|
"pending": 95,
|
|
"running": true,
|
|
"mangaDone": 5,
|
|
"mangaTotal": 100,
|
|
"chapterDone": 50,
|
|
"chapterAdded": 10,
|
|
"progress": {
|
|
"current": 5,
|
|
"total": 100
|
|
},
|
|
"errors": []
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### `WS /api/v1/webview`
|
|
|
|
- **What it does:** Real-time webview communication for embedded browser functionality
|
|
- **Expected request:** WebSocket connection with authentication
|
|
|
|
#### Messages You Can Send to Server:
|
|
|
|
**Load a URL in the webview:**
|
|
```json
|
|
{
|
|
"type": "loadUrl",
|
|
"url": "https://example.com",
|
|
"width": 1920,
|
|
"height": 1080
|
|
}
|
|
```
|
|
- **Expected Response:** None (webview loads the URL)
|
|
|
|
**Resize the webview:**
|
|
```json
|
|
{
|
|
"type": "resize",
|
|
"width": 800,
|
|
"height": 600
|
|
}
|
|
```
|
|
- **Expected Response:** None
|
|
|
|
**Send a JavaScript event:**
|
|
```json
|
|
{
|
|
"type": "event",
|
|
"eventType": "click",
|
|
"clickX": 100.5,
|
|
"clickY": 200.75,
|
|
"button": 0,
|
|
"ctrlKey": false,
|
|
"shiftKey": false,
|
|
"altKey": false,
|
|
"metaKey": false
|
|
}
|
|
```
|
|
- **Expected Response:** None (event is sent to the webview)
|
|
|
|
**Keyboard event:**
|
|
```json
|
|
{
|
|
"type": "event",
|
|
"eventType": "keydown",
|
|
"key": "Enter",
|
|
"code": "Enter",
|
|
"ctrlKey": true
|
|
}
|
|
```
|
|
- **Expected Response:** None
|
|
|
|
**Scroll event:**
|
|
```json
|
|
{
|
|
"type": "event",
|
|
"eventType": "wheel",
|
|
"deltaY": -100,
|
|
"clientX": 500,
|
|
"clientY": 500
|
|
}
|
|
```
|
|
- **Expected Response:** None
|
|
|
|
**Paste text to webview:**
|
|
```json
|
|
{
|
|
"type": "paste",
|
|
"data": "pasted text content"
|
|
}
|
|
```
|
|
- **Expected Response:** None
|
|
|
|
**Copy from webview:**
|
|
```json
|
|
{
|
|
"type": "copy"
|
|
}
|
|
```
|
|
- **Expected Response:** None
|
|
|
|
**Ping to check connection:**
|
|
```json
|
|
{
|
|
"type": "ping"
|
|
}
|
|
```
|
|
- **Expected Response from Server:**
|
|
```json
|
|
{
|
|
"type": "pong"
|
|
}
|
|
```
|
|
|
|
#### Messages Received from Server:
|
|
|
|
The server sends various responses based on webview interactions:
|
|
|
|
**Pong response:**
|
|
```json
|
|
{
|
|
"type": "pong"
|
|
}
|
|
```
|
|
|
|
**JavaScript console output (example):**
|
|
```json
|
|
{
|
|
"type": "console",
|
|
"level": "log",
|
|
"message": "Page loaded successfully"
|
|
}
|
|
```
|
|
|
|
**Page load events:**
|
|
```json
|
|
{
|
|
"type": "loadStart",
|
|
"url": "https://example.com"
|
|
}
|
|
```
|
|
|
|
```json
|
|
{
|
|
"type": "loadFinish",
|
|
"url": "https://example.com",
|
|
"httpStatusCode": 200
|
|
}
|
|
```
|
|
|
|
**Error events:**
|
|
```json
|
|
{
|
|
"type": "error",
|
|
"description": "Failed to load resource",
|
|
"url": "https://example.com/broken-link"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## GraphQL Endpoint
|
|
|
|
**Base URL:** `http://localhost:4567/api/graphql`
|
|
|
|
The server also provides a GraphQL API for more flexible queries and subscriptions. See the GraphQL schema for available queries, mutations, and subscriptions.
|
|
|
|
---
|
|
|
|
## OPDS Endpoints
|
|
|
|
The OPDS API provides catalog feeds for integration with OPDS-compatible readers.
|
|
|
|
**Base URL:** `http://localhost:4567/api/opds/v1.2/`
|
|
|
|
### `GET /api/opds/v1.2/opds/v1.2`
|
|
|
|
- **What it does:** OPDS Catalog Root Feed (Navigation)
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
**Response XML Example:**
|
|
```xml
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:opds="http://opds-spec.org/2010/catalog">
|
|
<title>Suwayomi</title>
|
|
<link rel="start" href="/api/opds/v1.2/opds/v1.2" type="application/atom+xml"/>
|
|
<link rel="self" href="/api/opds/v1.2/opds/v1.2" type="application/atom+xml"/>
|
|
<entry>
|
|
<title>Library</title>
|
|
<link href="/api/opds/v1.2/library/series" type="application/atom+xml;profile=opds-catalog"/>
|
|
<content type="text">Your manga library</content>
|
|
</entry>
|
|
<entry>
|
|
<title>Explore</title>
|
|
<link href="/api/opds/v1.2/sources" type="application/atom+xml;profile=opds-catalog"/>
|
|
<content type="text">Browse sources</content>
|
|
</entry>
|
|
</feed>
|
|
```
|
|
|
|
### `GET /api/opds/v1.2/search`
|
|
|
|
- **What it does:** OPDS Search Description Feed
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
### `GET /api/opds/v1.2/explore`
|
|
|
|
- **What it does:** Explore Sources Navigation Feed
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
### `GET /api/opds/v1.2/history`
|
|
|
|
- **What it does:** Reading History Acquisition Feed
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
### `GET /api/opds/v1.2/library-updates`
|
|
|
|
- **What it does:** Library Updates Acquisition Feed
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
### `GET /api/opds/v1.2/library/series`
|
|
|
|
- **What it does:** All Series in Library / Search Results Feed
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
### `GET /api/opds/v1.2/library/sources`
|
|
|
|
- **What it does:** Library Sources Navigation Feed
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
### `GET /api/opds/v1.2/library/source/{sourceId}`
|
|
|
|
- **What it does:** Library Source-Specific Series Acquisition Feed
|
|
- **Expected request:** Path parameter: `sourceId` (long)
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
### `GET /api/opds/v1.2/library/categories`
|
|
|
|
- **What it does:** Library Categories Navigation Feed
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
### `GET /api/opds/v1.2/library/genres`
|
|
|
|
- **What it does:** Library Genres Navigation Feed
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
### `GET /api/opds/v1.2/library/statuses`
|
|
|
|
- **What it does:** Library Status Navigation Feed
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
### `GET /api/opds/v1.2/library/languages`
|
|
|
|
- **What it does:** Library Content Languages Navigation Feed
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
### `GET /api/opds/v1.2/sources`
|
|
|
|
- **What it does:** All Sources Navigation Feed (Explore)
|
|
- **Expected request:** No parameters required
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
### `GET /api/opds/v1.2/source/{sourceId}`
|
|
|
|
- **What it does:** Source-Specific Series Acquisition Feed (Explore)
|
|
- **Expected request:** Path parameter: `sourceId` (long)
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
### `GET /api/opds/v1.2/series/{seriesId}/chapters`
|
|
|
|
- **What it does:** Series Chapters Acquisition Feed
|
|
- **Expected request:** Path parameter: `seriesId` (int)
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
### `GET /api/opds/v1.2/series/{seriesId}/chapter/{chapterIndex}/metadata`
|
|
|
|
- **What it does:** Chapter Metadata Acquisition Feed
|
|
- **Expected request:** Path parameters: `seriesId` (int), `chapterIndex` (int)
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
### `GET /api/opds/v1.2/category/{categoryId}`
|
|
|
|
- **What it does:** Category-Specific Series Acquisition Feed
|
|
- **Expected request:** Path parameter: `categoryId` (int)
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
### `GET /api/opds/v1.2/genre/{genre}`
|
|
|
|
- **What it does:** Genre-Specific Series Acquisition Feed
|
|
- **Expected request:** Path parameter: `genre` (string)
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
### `GET /api/opds/v1.2/status/{statusId}`
|
|
|
|
- **What it does:** Status-Specific Series Acquisition Feed
|
|
- **Expected request:** Path parameter: `statusId` (int)
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
### `GET /api/opds/v1.2/language/{langCode}`
|
|
|
|
- **What it does:** Language-Specific Series Acquisition Feed
|
|
- **Expected request:** Path parameter: `langCode` (string)
|
|
- **Expected response:** XML OPDS feed (HTTP 200)
|
|
|
|
---
|
|
|
|
## Notes
|
|
|
|
- The server runs on port 4567 by default
|
|
- All JSON responses use UTF-8 encoding
|
|
- File uploads use multipart/form-data format
|
|
- WebSocket endpoints provide real-time updates for downloads, updates, and webview
|
|
- WebSocket messages are JSON formatted (except STATUS command which is plain text)
|
|
- Image responses include caching headers with 1-day max-age for thumbnails and pages
|
|
- OPDS feeds use Atom XML format for catalog navigation and acquisition
|
|
- Actions like start/stop for downloads and updates are done via HTTP endpoints, not WebSocket
|
|
- WebSocket endpoints only support "STATUS" command to query current status
|
|
- See [Authentication](#authentication) section for details on how to authenticate with the API |