1196 lines
21 KiB
Markdown
1196 lines
21 KiB
Markdown
# Transcriptarr REST API
|
|
|
|
Complete documentation for the Transcriptarr backend REST API.
|
|
|
|
## Table of Contents
|
|
|
|
- [Quick Start](#quick-start)
|
|
- [System Endpoints](#system-endpoints)
|
|
- [Workers API](#workers-api)
|
|
- [Jobs API](#jobs-api)
|
|
- [Scan Rules API](#scan-rules-api)
|
|
- [Scanner API](#scanner-api)
|
|
- [Settings API](#settings-api)
|
|
- [System Resources API](#system-resources-api)
|
|
- [Filesystem API](#filesystem-api)
|
|
- [Setup Wizard API](#setup-wizard-api)
|
|
- [Bazarr Provider API](#bazarr-provider-api-in-development)
|
|
- [Error Codes](#error-codes)
|
|
- [Examples](#examples)
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
### Running the Server
|
|
|
|
```bash
|
|
# Using the CLI
|
|
python backend/cli.py server --host 0.0.0.0 --port 8000
|
|
|
|
# With auto-reload (development)
|
|
python backend/cli.py server --reload
|
|
|
|
# With multiple workers (production)
|
|
python backend/cli.py server --workers 4
|
|
```
|
|
|
|
### Interactive Documentation
|
|
|
|
Once the server is running:
|
|
- **Swagger UI**: http://localhost:8000/docs
|
|
- **ReDoc**: http://localhost:8000/redoc
|
|
|
|
---
|
|
|
|
## System Endpoints
|
|
|
|
### `GET /`
|
|
|
|
Root endpoint - API info or frontend (if built).
|
|
|
|
**Response (API mode):**
|
|
```json
|
|
{
|
|
"name": "Transcriptarr API",
|
|
"version": "1.0.0",
|
|
"status": "running",
|
|
"message": "Frontend not built. Access API docs at /docs"
|
|
}
|
|
```
|
|
|
|
### `GET /health`
|
|
|
|
Health check for monitoring systems.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"status": "healthy",
|
|
"database": "connected",
|
|
"workers": 2,
|
|
"queue_size": 5
|
|
}
|
|
```
|
|
|
|
### `GET /api/status`
|
|
|
|
Complete system status overview.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"system": {
|
|
"status": "running",
|
|
"uptime_seconds": 3600.5
|
|
},
|
|
"workers": {
|
|
"total_workers": 2,
|
|
"cpu_workers": 1,
|
|
"gpu_workers": 1,
|
|
"idle_workers": 1,
|
|
"busy_workers": 1,
|
|
"total_jobs_completed": 42,
|
|
"total_jobs_failed": 2
|
|
},
|
|
"queue": {
|
|
"total_jobs": 100,
|
|
"queued": 5,
|
|
"processing": 2,
|
|
"completed": 90,
|
|
"failed": 3,
|
|
"cancelled": 0
|
|
},
|
|
"scanner": {
|
|
"scheduler_enabled": true,
|
|
"scheduler_running": true,
|
|
"next_scan_time": "2025-01-13T02:00:00",
|
|
"watcher_enabled": true,
|
|
"watcher_running": true
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Workers API
|
|
|
|
Base path: `/api/workers`
|
|
|
|
### `GET /api/workers`
|
|
|
|
List all workers and their status.
|
|
|
|
**Response:**
|
|
```json
|
|
[
|
|
{
|
|
"worker_id": "worker-cpu-0",
|
|
"worker_type": "cpu",
|
|
"device_id": null,
|
|
"status": "busy",
|
|
"current_job_id": "abc123",
|
|
"jobs_completed": 10,
|
|
"jobs_failed": 0,
|
|
"uptime_seconds": 3600.5,
|
|
"current_job_progress": 45.2,
|
|
"current_job_eta": 120
|
|
}
|
|
]
|
|
```
|
|
|
|
### `GET /api/workers/stats`
|
|
|
|
Get worker pool statistics.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"total_workers": 2,
|
|
"cpu_workers": 1,
|
|
"gpu_workers": 1,
|
|
"idle_workers": 1,
|
|
"busy_workers": 1,
|
|
"stopped_workers": 0,
|
|
"error_workers": 0,
|
|
"total_jobs_completed": 42,
|
|
"total_jobs_failed": 2,
|
|
"uptime_seconds": 3600.5,
|
|
"is_running": true
|
|
}
|
|
```
|
|
|
|
### `GET /api/workers/{worker_id}`
|
|
|
|
Get specific worker status.
|
|
|
|
**Path Parameters:**
|
|
- `worker_id` (string): Worker ID
|
|
|
|
**Response:** Worker status object (same as list item)
|
|
|
|
**Errors:**
|
|
- `404`: Worker not found
|
|
|
|
### `POST /api/workers`
|
|
|
|
Add a new worker to the pool.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"worker_type": "gpu",
|
|
"device_id": 0
|
|
}
|
|
```
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| worker_type | string | Yes | `cpu` or `gpu` |
|
|
| device_id | integer | GPU only | GPU device ID (required for GPU workers) |
|
|
|
|
**Response:** Created worker status (201)
|
|
|
|
**Errors:**
|
|
- `400`: Invalid worker type or missing device_id for GPU
|
|
|
|
### `DELETE /api/workers/{worker_id}`
|
|
|
|
Remove a worker from the pool.
|
|
|
|
**Path Parameters:**
|
|
- `worker_id` (string): Worker ID to remove
|
|
|
|
**Query Parameters:**
|
|
- `timeout` (float, default=30.0): Timeout in seconds
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"message": "Worker worker-cpu-0 removed successfully"
|
|
}
|
|
```
|
|
|
|
**Errors:**
|
|
- `404`: Worker not found
|
|
|
|
### `POST /api/workers/pool/start`
|
|
|
|
Start the worker pool with specified workers.
|
|
|
|
**Query Parameters:**
|
|
- `cpu_workers` (int, default=0): Number of CPU workers
|
|
- `gpu_workers` (int, default=0): Number of GPU workers
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"message": "Worker pool started: 1 CPU workers, 1 GPU workers"
|
|
}
|
|
```
|
|
|
|
### `POST /api/workers/pool/stop`
|
|
|
|
Stop all workers in the pool.
|
|
|
|
**Query Parameters:**
|
|
- `timeout` (float, default=30.0): Timeout per worker
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"message": "Worker pool stopped successfully"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Jobs API
|
|
|
|
Base path: `/api/jobs`
|
|
|
|
### `GET /api/jobs`
|
|
|
|
List jobs with pagination and filtering.
|
|
|
|
**Query Parameters:**
|
|
- `status_filter` (string, optional): Filter by status (`queued`, `processing`, `completed`, `failed`, `cancelled`)
|
|
- `page` (int, default=1): Page number (1-based)
|
|
- `page_size` (int, default=50, max=500): Items per page
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"jobs": [
|
|
{
|
|
"id": "abc123",
|
|
"file_path": "/media/anime/episode.mkv",
|
|
"file_name": "episode.mkv",
|
|
"job_type": "transcription",
|
|
"status": "completed",
|
|
"priority": 10,
|
|
"source_lang": "jpn",
|
|
"target_lang": "spa",
|
|
"quality_preset": "fast",
|
|
"transcribe_or_translate": "transcribe",
|
|
"progress": 100.0,
|
|
"current_stage": "finalizing",
|
|
"eta_seconds": null,
|
|
"created_at": "2025-01-12T10:00:00",
|
|
"started_at": "2025-01-12T10:00:05",
|
|
"completed_at": "2025-01-12T10:05:30",
|
|
"output_path": "/media/anime/episode.spa.srt",
|
|
"segments_count": 245,
|
|
"error": null,
|
|
"retry_count": 0,
|
|
"worker_id": "worker-gpu-0",
|
|
"vram_used_mb": 4096,
|
|
"processing_time_seconds": 325.5,
|
|
"model_used": "large-v3",
|
|
"device_used": "cuda:0"
|
|
}
|
|
],
|
|
"total": 100,
|
|
"page": 1,
|
|
"page_size": 50
|
|
}
|
|
```
|
|
|
|
### `GET /api/jobs/stats`
|
|
|
|
Get queue statistics.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"total_jobs": 100,
|
|
"queued": 5,
|
|
"processing": 2,
|
|
"completed": 90,
|
|
"failed": 3,
|
|
"cancelled": 0
|
|
}
|
|
```
|
|
|
|
### `GET /api/jobs/{job_id}`
|
|
|
|
Get specific job details.
|
|
|
|
**Path Parameters:**
|
|
- `job_id` (string): Job ID
|
|
|
|
**Response:** Job object (same as list item)
|
|
|
|
**Errors:**
|
|
- `404`: Job not found
|
|
|
|
### `POST /api/jobs`
|
|
|
|
Create a new transcription job.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"file_path": "/media/anime/Attack on Titan S04E01.mkv",
|
|
"file_name": "Attack on Titan S04E01.mkv",
|
|
"source_lang": "jpn",
|
|
"target_lang": "spa",
|
|
"quality_preset": "fast",
|
|
"transcribe_or_translate": "transcribe",
|
|
"priority": 10,
|
|
"is_manual_request": true
|
|
}
|
|
```
|
|
|
|
| Field | Type | Required | Description |
|
|
|-------|------|----------|-------------|
|
|
| file_path | string | Yes | Full path to media file |
|
|
| file_name | string | Yes | File name |
|
|
| source_lang | string | No | Source language (ISO 639-2) |
|
|
| target_lang | string | Yes | Target subtitle language (ISO 639-2) |
|
|
| quality_preset | string | No | `fast`, `balanced`, or `best` |
|
|
| transcribe_or_translate | string | No | `transcribe` or `translate` |
|
|
| priority | int | No | Higher = processed first |
|
|
| is_manual_request | bool | No | Default: true |
|
|
|
|
**Response:** Created job (201)
|
|
|
|
**Errors:**
|
|
- `400`: Invalid quality preset
|
|
- `409`: Job already exists for this file
|
|
|
|
### `POST /api/jobs/{job_id}/retry`
|
|
|
|
Retry a failed job.
|
|
|
|
**Path Parameters:**
|
|
- `job_id` (string): Job ID to retry
|
|
|
|
**Response:** Updated job object
|
|
|
|
**Errors:**
|
|
- `404`: Job not found
|
|
- `400`: Job cannot be retried (not in failed status)
|
|
|
|
### `DELETE /api/jobs/{job_id}`
|
|
|
|
Cancel a job.
|
|
|
|
**Path Parameters:**
|
|
- `job_id` (string): Job ID to cancel
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"message": "Job abc123 cancelled successfully"
|
|
}
|
|
```
|
|
|
|
**Errors:**
|
|
- `404`: Job not found
|
|
- `400`: Job already in terminal state
|
|
|
|
### `POST /api/jobs/{job_id}/cancel`
|
|
|
|
Cancel a job (POST alias for DELETE).
|
|
|
|
### `POST /api/jobs/queue/clear`
|
|
|
|
Clear all completed jobs from the queue.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"message": "Cleared 42 completed jobs"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Scan Rules API
|
|
|
|
Base path: `/api/scan-rules`
|
|
|
|
### `GET /api/scan-rules`
|
|
|
|
List all scan rules.
|
|
|
|
**Query Parameters:**
|
|
- `enabled_only` (bool, default=false): Only return enabled rules
|
|
|
|
**Response:**
|
|
```json
|
|
[
|
|
{
|
|
"id": 1,
|
|
"name": "Japanese anime without Spanish subs",
|
|
"enabled": true,
|
|
"priority": 10,
|
|
"conditions": {
|
|
"audio_language_is": "jpn",
|
|
"audio_language_not": null,
|
|
"audio_track_count_min": null,
|
|
"has_embedded_subtitle_lang": null,
|
|
"missing_embedded_subtitle_lang": "spa",
|
|
"missing_external_subtitle_lang": "spa",
|
|
"file_extension": ".mkv,.mp4"
|
|
},
|
|
"action": {
|
|
"action_type": "transcribe",
|
|
"target_language": "spa",
|
|
"quality_preset": "fast",
|
|
"job_priority": 5
|
|
},
|
|
"created_at": "2025-01-12T10:00:00",
|
|
"updated_at": null
|
|
}
|
|
]
|
|
```
|
|
|
|
### `GET /api/scan-rules/{rule_id}`
|
|
|
|
Get specific scan rule.
|
|
|
|
**Path Parameters:**
|
|
- `rule_id` (int): Rule ID
|
|
|
|
**Response:** Rule object (same as list item)
|
|
|
|
**Errors:**
|
|
- `404`: Rule not found
|
|
|
|
### `POST /api/scan-rules`
|
|
|
|
Create a new scan rule.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"name": "Japanese anime without Spanish subs",
|
|
"enabled": true,
|
|
"priority": 10,
|
|
"conditions": {
|
|
"audio_language_is": "jpn",
|
|
"missing_embedded_subtitle_lang": "spa",
|
|
"missing_external_subtitle_lang": "spa",
|
|
"file_extension": ".mkv,.mp4"
|
|
},
|
|
"action": {
|
|
"action_type": "transcribe",
|
|
"target_language": "spa",
|
|
"quality_preset": "fast",
|
|
"job_priority": 5
|
|
}
|
|
}
|
|
```
|
|
|
|
**Conditions Fields:**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| audio_language_is | string | Audio must be this language (ISO 639-2) |
|
|
| audio_language_not | string | Audio must NOT be (comma-separated) |
|
|
| audio_track_count_min | int | Minimum audio tracks |
|
|
| has_embedded_subtitle_lang | string | Must have embedded subtitle |
|
|
| missing_embedded_subtitle_lang | string | Must NOT have embedded subtitle |
|
|
| missing_external_subtitle_lang | string | Must NOT have external .srt |
|
|
| file_extension | string | File extensions (comma-separated) |
|
|
|
|
**Action Fields:**
|
|
|
|
| Field | Type | Description |
|
|
|-------|------|-------------|
|
|
| action_type | string | `transcribe` or `translate` |
|
|
| target_language | string | Target language (ISO 639-2) |
|
|
| quality_preset | string | `fast`, `balanced`, `best` |
|
|
| job_priority | int | Priority for created jobs |
|
|
|
|
**Response:** Created rule (201)
|
|
|
|
**Errors:**
|
|
- `409`: Rule with same name exists
|
|
|
|
### `PUT /api/scan-rules/{rule_id}`
|
|
|
|
Update a scan rule (partial update supported).
|
|
|
|
**Path Parameters:**
|
|
- `rule_id` (int): Rule ID
|
|
|
|
**Request:** Same fields as POST (all optional)
|
|
|
|
**Response:** Updated rule
|
|
|
|
**Errors:**
|
|
- `404`: Rule not found
|
|
- `409`: Name already exists
|
|
|
|
### `DELETE /api/scan-rules/{rule_id}`
|
|
|
|
Delete a scan rule.
|
|
|
|
**Path Parameters:**
|
|
- `rule_id` (int): Rule ID
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"message": "Scan rule 1 deleted successfully"
|
|
}
|
|
```
|
|
|
|
**Errors:**
|
|
- `404`: Rule not found
|
|
|
|
### `POST /api/scan-rules/{rule_id}/toggle`
|
|
|
|
Toggle rule enabled/disabled.
|
|
|
|
**Path Parameters:**
|
|
- `rule_id` (int): Rule ID
|
|
|
|
**Response:** Updated rule object
|
|
|
|
**Errors:**
|
|
- `404`: Rule not found
|
|
|
|
---
|
|
|
|
## Scanner API
|
|
|
|
Base path: `/api/scanner`
|
|
|
|
### `GET /api/scanner/status`
|
|
|
|
Get scanner status.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"scheduler_enabled": true,
|
|
"scheduler_running": true,
|
|
"next_scan_time": "2025-01-13T02:00:00",
|
|
"watcher_enabled": true,
|
|
"watcher_running": true,
|
|
"watched_paths": ["/media/anime", "/media/movies"],
|
|
"last_scan_time": "2025-01-12T02:00:00",
|
|
"total_scans": 1523
|
|
}
|
|
```
|
|
|
|
### `POST /api/scanner/scan`
|
|
|
|
Trigger a manual scan.
|
|
|
|
**Request (optional):**
|
|
```json
|
|
{
|
|
"paths": ["/media/anime", "/media/movies"],
|
|
"recursive": true
|
|
}
|
|
```
|
|
|
|
If no request body, uses `library_paths` from settings.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"scanned_files": 150,
|
|
"matched_files": 25,
|
|
"jobs_created": 25,
|
|
"skipped_files": 125,
|
|
"paths_scanned": ["/media/anime", "/media/movies"]
|
|
}
|
|
```
|
|
|
|
**Errors:**
|
|
- `400`: No library paths configured
|
|
|
|
### `POST /api/scanner/scheduler/start`
|
|
|
|
Start the scheduled scanner.
|
|
|
|
**Request (optional):**
|
|
```json
|
|
{
|
|
"enabled": true,
|
|
"cron_expression": "0 2 * * *",
|
|
"paths": ["/media/anime"],
|
|
"recursive": true
|
|
}
|
|
```
|
|
|
|
If no request body, uses settings from database.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"message": "Scheduler started successfully (every 360 minutes)"
|
|
}
|
|
```
|
|
|
|
### `POST /api/scanner/scheduler/stop`
|
|
|
|
Stop the scheduled scanner.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"message": "Scheduler stopped successfully"
|
|
}
|
|
```
|
|
|
|
### `POST /api/scanner/watcher/start`
|
|
|
|
Start the file watcher.
|
|
|
|
**Request (optional):**
|
|
```json
|
|
{
|
|
"enabled": true,
|
|
"paths": ["/media/anime"],
|
|
"recursive": true
|
|
}
|
|
```
|
|
|
|
If no request body, uses settings from database.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"message": "File watcher started successfully"
|
|
}
|
|
```
|
|
|
|
**Errors:**
|
|
- `400`: No library paths configured
|
|
|
|
### `POST /api/scanner/watcher/stop`
|
|
|
|
Stop the file watcher.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"message": "File watcher stopped successfully"
|
|
}
|
|
```
|
|
|
|
### `POST /api/scanner/analyze`
|
|
|
|
Analyze a single file with ffprobe.
|
|
|
|
**Query Parameters:**
|
|
- `file_path` (string, required): Path to file
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"file_path": "/media/anime/episode.mkv",
|
|
"audio_tracks": [
|
|
{
|
|
"index": 0,
|
|
"codec": "aac",
|
|
"language": "jpn",
|
|
"channels": 2
|
|
}
|
|
],
|
|
"embedded_subtitles": [],
|
|
"external_subtitles": [
|
|
{
|
|
"path": "/media/anime/episode.en.srt",
|
|
"language": "eng"
|
|
}
|
|
],
|
|
"duration_seconds": 1440.5,
|
|
"is_video": true
|
|
}
|
|
```
|
|
|
|
**Errors:**
|
|
- `400`: Path is not a file
|
|
- `404`: File not found
|
|
|
|
---
|
|
|
|
## Settings API
|
|
|
|
Base path: `/api/settings`
|
|
|
|
### `GET /api/settings`
|
|
|
|
Get all settings or filter by category.
|
|
|
|
**Query Parameters:**
|
|
- `category` (string, optional): Filter by category (`general`, `workers`, `transcription`, `scanner`, `bazarr`)
|
|
|
|
**Response:**
|
|
```json
|
|
[
|
|
{
|
|
"id": 1,
|
|
"key": "worker_cpu_count",
|
|
"value": "1",
|
|
"description": "Number of CPU workers",
|
|
"category": "workers",
|
|
"value_type": "integer",
|
|
"created_at": "2025-01-12T10:00:00",
|
|
"updated_at": "2025-01-12T12:00:00"
|
|
}
|
|
]
|
|
```
|
|
|
|
### `GET /api/settings/{key}`
|
|
|
|
Get a specific setting.
|
|
|
|
**Path Parameters:**
|
|
- `key` (string): Setting key
|
|
|
|
**Response:** Setting object (same as list item)
|
|
|
|
**Errors:**
|
|
- `404`: Setting not found
|
|
|
|
### `PUT /api/settings/{key}`
|
|
|
|
Update a setting value.
|
|
|
|
**Path Parameters:**
|
|
- `key` (string): Setting key
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"value": "2"
|
|
}
|
|
```
|
|
|
|
**Response:** Updated setting object
|
|
|
|
**Errors:**
|
|
- `404`: Setting not found
|
|
|
|
### `POST /api/settings/bulk-update`
|
|
|
|
Update multiple settings at once.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"settings": {
|
|
"worker_cpu_count": "2",
|
|
"worker_gpu_count": "1",
|
|
"scanner_enabled": "true"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"message": "Updated 3 settings successfully"
|
|
}
|
|
```
|
|
|
|
### `POST /api/settings`
|
|
|
|
Create a new setting.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"key": "custom_setting",
|
|
"value": "value",
|
|
"description": "Custom setting description",
|
|
"category": "general",
|
|
"value_type": "string"
|
|
}
|
|
```
|
|
|
|
**Response:** Created setting (201)
|
|
|
|
**Errors:**
|
|
- `409`: Setting already exists
|
|
|
|
### `DELETE /api/settings/{key}`
|
|
|
|
Delete a setting.
|
|
|
|
**Path Parameters:**
|
|
- `key` (string): Setting key
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"message": "Setting 'custom_setting' deleted successfully"
|
|
}
|
|
```
|
|
|
|
**Errors:**
|
|
- `404`: Setting not found
|
|
|
|
### `POST /api/settings/init-defaults`
|
|
|
|
Initialize all default settings (safe to call multiple times).
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"message": "Default settings initialized successfully"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## System Resources API
|
|
|
|
Base path: `/api/system`
|
|
|
|
### `GET /api/system/resources`
|
|
|
|
Get all system resources (CPU, RAM, GPU).
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"cpu": {
|
|
"usage_percent": 25.5,
|
|
"count_logical": 16,
|
|
"count_physical": 8,
|
|
"frequency_mhz": 3600.0
|
|
},
|
|
"memory": {
|
|
"total_gb": 32.0,
|
|
"used_gb": 12.5,
|
|
"free_gb": 19.5,
|
|
"usage_percent": 39.1
|
|
},
|
|
"gpus": [
|
|
{
|
|
"id": 0,
|
|
"name": "NVIDIA GeForce RTX 3080",
|
|
"memory_total_mb": 10240,
|
|
"memory_used_mb": 2048,
|
|
"memory_free_mb": 8192,
|
|
"utilization_percent": 15
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### `GET /api/system/cpu`
|
|
|
|
Get CPU information only.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"usage_percent": 25.5,
|
|
"count_logical": 16,
|
|
"count_physical": 8,
|
|
"frequency_mhz": 3600.0
|
|
}
|
|
```
|
|
|
|
### `GET /api/system/memory`
|
|
|
|
Get memory information only.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"total_gb": 32.0,
|
|
"used_gb": 12.5,
|
|
"free_gb": 19.5,
|
|
"usage_percent": 39.1
|
|
}
|
|
```
|
|
|
|
### `GET /api/system/gpus`
|
|
|
|
Get all GPUs information.
|
|
|
|
**Response:**
|
|
```json
|
|
[
|
|
{
|
|
"id": 0,
|
|
"name": "NVIDIA GeForce RTX 3080",
|
|
"memory_total_mb": 10240,
|
|
"memory_used_mb": 2048,
|
|
"memory_free_mb": 8192,
|
|
"utilization_percent": 15
|
|
}
|
|
]
|
|
```
|
|
|
|
### `GET /api/system/gpu/{device_id}`
|
|
|
|
Get specific GPU information.
|
|
|
|
**Path Parameters:**
|
|
- `device_id` (int): GPU device ID
|
|
|
|
**Response:** GPU object (same as list item)
|
|
|
|
---
|
|
|
|
## Filesystem API
|
|
|
|
Base path: `/api/filesystem`
|
|
|
|
### `GET /api/filesystem/browse`
|
|
|
|
Browse filesystem directories.
|
|
|
|
**Query Parameters:**
|
|
- `path` (string, default="/"): Path to browse
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"current_path": "/media",
|
|
"parent_path": "/",
|
|
"items": [
|
|
{
|
|
"name": "anime",
|
|
"path": "/media/anime",
|
|
"is_directory": true,
|
|
"is_readable": true
|
|
},
|
|
{
|
|
"name": "movies",
|
|
"path": "/media/movies",
|
|
"is_directory": true,
|
|
"is_readable": true
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Errors:**
|
|
- `400`: Path is not a directory
|
|
- `403`: Permission denied
|
|
- `404`: Path does not exist
|
|
|
|
### `GET /api/filesystem/common-paths`
|
|
|
|
Get list of common starting paths.
|
|
|
|
**Response:**
|
|
```json
|
|
[
|
|
{
|
|
"name": "/",
|
|
"path": "/",
|
|
"is_directory": true,
|
|
"is_readable": true
|
|
},
|
|
{
|
|
"name": "/media",
|
|
"path": "/media",
|
|
"is_directory": true,
|
|
"is_readable": true
|
|
}
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
## Setup Wizard API
|
|
|
|
Base path: `/api/setup`
|
|
|
|
### `GET /api/setup/status`
|
|
|
|
Check setup status.
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"is_first_run": true,
|
|
"setup_completed": false
|
|
}
|
|
```
|
|
|
|
### `POST /api/setup/standalone`
|
|
|
|
Configure standalone mode.
|
|
|
|
**Request:**
|
|
```json
|
|
{
|
|
"library_paths": ["/media/anime", "/media/movies"],
|
|
"scan_rules": [
|
|
{
|
|
"name": "Japanese to Spanish",
|
|
"audio_language_is": "jpn",
|
|
"missing_external_subtitle_lang": "spa",
|
|
"target_language": "spa",
|
|
"action_type": "transcribe"
|
|
}
|
|
],
|
|
"worker_config": {
|
|
"count": 1,
|
|
"type": "cpu"
|
|
},
|
|
"scanner_config": {
|
|
"interval_minutes": 360
|
|
}
|
|
}
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Standalone mode configured successfully",
|
|
"bazarr_info": null
|
|
}
|
|
```
|
|
|
|
### `POST /api/setup/bazarr-slave`
|
|
|
|
Configure Bazarr slave mode (generates API key).
|
|
|
|
**Request:** (empty body)
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Bazarr slave mode configured successfully",
|
|
"bazarr_info": {
|
|
"mode": "bazarr_slave",
|
|
"host": "127.0.0.1",
|
|
"port": 8000,
|
|
"api_key": "generated_api_key_here",
|
|
"provider_url": "http://127.0.0.1:8000"
|
|
}
|
|
}
|
|
```
|
|
|
|
### `POST /api/setup/skip`
|
|
|
|
Skip setup wizard (for advanced users).
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"message": "Setup wizard skipped"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Bazarr Provider API (In Development)
|
|
|
|
> **Note:** These endpoints are functional but the full Bazarr integration is still in development.
|
|
|
|
### `POST /asr`
|
|
|
|
Transcription/translation endpoint (Bazarr compatibility).
|
|
|
|
### `POST /detect-language`
|
|
|
|
Language detection endpoint.
|
|
|
|
### `GET /status`
|
|
|
|
Provider status.
|
|
|
|
---
|
|
|
|
## Error Codes
|
|
|
|
| Code | Description |
|
|
|------|-------------|
|
|
| 200 | Success |
|
|
| 201 | Resource created |
|
|
| 400 | Bad request (invalid parameters) |
|
|
| 403 | Forbidden (permission denied) |
|
|
| 404 | Resource not found |
|
|
| 409 | Conflict (duplicate resource) |
|
|
| 500 | Internal server error |
|
|
|
|
---
|
|
|
|
## Examples
|
|
|
|
### cURL Examples
|
|
|
|
```bash
|
|
# Get system status
|
|
curl http://localhost:8000/api/status
|
|
|
|
# Create a transcription job
|
|
curl -X POST http://localhost:8000/api/jobs \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"file_path": "/media/anime/episode.mkv",
|
|
"file_name": "episode.mkv",
|
|
"target_lang": "spa",
|
|
"quality_preset": "fast"
|
|
}'
|
|
|
|
# Add a GPU worker
|
|
curl -X POST http://localhost:8000/api/workers \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"worker_type": "gpu",
|
|
"device_id": 0
|
|
}'
|
|
|
|
# Trigger manual scan
|
|
curl -X POST http://localhost:8000/api/scanner/scan
|
|
|
|
# Update a setting
|
|
curl -X PUT http://localhost:8000/api/settings/worker_cpu_count \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"value": "2"}'
|
|
```
|
|
|
|
### Python Example
|
|
|
|
```python
|
|
import requests
|
|
|
|
BASE_URL = "http://localhost:8000"
|
|
|
|
# Create a job
|
|
response = requests.post(
|
|
f"{BASE_URL}/api/jobs",
|
|
json={
|
|
"file_path": "/media/anime/episode.mkv",
|
|
"file_name": "episode.mkv",
|
|
"target_lang": "spa",
|
|
"quality_preset": "fast"
|
|
}
|
|
)
|
|
|
|
job = response.json()
|
|
print(f"Job created: {job['id']}")
|
|
|
|
# Check job status
|
|
response = requests.get(f"{BASE_URL}/api/jobs/{job['id']}")
|
|
status = response.json()
|
|
print(f"Job status: {status['status']} - {status['progress']}%")
|
|
|
|
# Get system resources
|
|
response = requests.get(f"{BASE_URL}/api/system/resources")
|
|
resources = response.json()
|
|
print(f"CPU: {resources['cpu']['usage_percent']}%")
|
|
print(f"RAM: {resources['memory']['usage_percent']}%")
|
|
```
|
|
|
|
---
|
|
|
|
## Notes
|
|
|
|
- All dates are in ISO 8601 UTC format
|
|
- Languages use ISO 639-2 (3-letter codes): `jpn`, `eng`, `spa`, `fra`, etc.
|
|
- Pagination uses 1-based indexing (first page = 1)
|
|
- Worker IDs are auto-generated unique strings
|
|
- Jobs are deduplicated by `file_path` (no duplicate jobs for same file)
|