Aniworld/docs/API.md

25 KiB

API Documentation

Document Purpose

This document provides comprehensive REST API and WebSocket reference for the Aniworld application.

Source: src/server/fastapi_app.py


1. API Overview

Base URL and Versioning

Environment Base URL
Local Development http://127.0.0.1:8000
API Documentation http://127.0.0.1:8000/api/docs
ReDoc Documentation http://127.0.0.1:8000/api/redoc

The API does not use versioning prefixes. All endpoints are available under /api/*.

Source: src/server/fastapi_app.py

Authentication

The API uses JWT Bearer Token authentication.

Header Format:

Authorization: Bearer <jwt_token>

Public Endpoints (no authentication required):

  • /api/auth/* - Authentication endpoints
  • /api/health - Health check endpoints
  • /api/docs, /api/redoc - API documentation
  • /static/* - Static files
  • /, /login, /setup, /queue - UI pages

Source: src/server/middleware/auth.py

Content Types

Direction Content-Type
Request application/json
Response application/json
WebSocket application/json (messages)

Common Headers

Header Required Description
Authorization Yes* Bearer token for protected endpoints
Content-Type Yes application/json for POST/PUT
Origin No Required for CORS preflight

*Not required for public endpoints listed above.


2. Authentication Endpoints

Prefix: /api/auth

Source: src/server/api/auth.py

POST /api/auth/setup

Initial setup endpoint to configure the master password. Can only be called once.

Request Body:

{
    "master_password": "string (min 8 chars, mixed case, number, special char)",
    "anime_directory": "string (optional, path to anime folder)"
}

Response (201 Created):

{
    "status": "ok"
}

Errors:

  • 400 Bad Request - Master password already configured or invalid password

Source: src/server/api/auth.py

POST /api/auth/login

Validate master password and return JWT token.

Request Body:

{
    "password": "string",
    "remember": false
}

Response (200 OK):

{
    "access_token": "eyJ...",
    "token_type": "bearer",
    "expires_at": "2025-12-14T10:30:00Z"
}

Errors:

  • 401 Unauthorized - Invalid credentials
  • 429 Too Many Requests - Account locked due to failed attempts

Source: src/server/api/auth.py

POST /api/auth/logout

Logout by revoking token.

Response (200 OK):

{
    "status": "ok",
    "message": "Logged out successfully"
}

Source: src/server/api/auth.py

GET /api/auth/status

Return whether master password is configured and if caller is authenticated.

Response (200 OK):

{
    "configured": true,
    "authenticated": true
}

Source: src/server/api/auth.py


3. Anime Endpoints

Prefix: /api/anime

Source: src/server/api/anime.py

Series Identifier Convention

The API uses two identifier fields:

Field Purpose Example
key Primary identifier - provider-assigned, URL-safe "attack-on-titan"
folder Metadata only - filesystem folder name "Attack on Titan (2013)"

Use key for all API operations. The folder field is for display purposes only.

GET /api/anime/status

Get anime library status information.

Authentication: Required

Response (200 OK):

{
    "directory": "/path/to/anime",
    "series_count": 42
}

Source: src/server/api/anime.py

GET /api/anime

List library series that have missing episodes.

Authentication: Required

Query Parameters:

Parameter Type Default Description
page int 1 Page number (must be positive)
per_page int 20 Items per page (max 1000)
sort_by string null Sort field: title, id, name, missing_episodes
filter string null Filter term

Response (200 OK):

[
    {
        "key": "beheneko-the-elf-girls-cat",
        "name": "Beheneko",
        "site": "aniworld.to",
        "folder": "beheneko the elf girls cat (2025)",
        "missing_episodes": { "1": [1, 2, 3, 4] },
        "link": ""
    }
]

Source: src/server/api/anime.py

GET /api/anime/search

Search the provider for anime series matching a query.

Authentication: Not required

Query Parameters:

Parameter Type Required Description
query string Yes Search term (max 200 chars)

Response (200 OK):

[
    {
        "key": "attack-on-titan",
        "name": "Attack on Titan",
        "site": "aniworld.to",
        "folder": "Attack on Titan (2013)",
        "missing_episodes": {},
        "link": "https://aniworld.to/anime/stream/attack-on-titan"
    }
]

Source: src/server/api/anime.py

POST /api/anime/search

Search via POST body.

Request Body:

{
    "query": "attack on titan"
}

Response: Same as GET /api/anime/search

Source: src/server/api/anime.py

POST /api/anime/add

Add a new series to the library with automatic database persistence, folder creation, and episode scanning.

Authentication: Required

Request Body:

{
    "link": "https://aniworld.to/anime/stream/attack-on-titan",
    "name": "Attack on Titan"
}

Response (200 OK):

{
    "status": "success",
    "message": "Successfully added series: Attack on Titan",
    "key": "attack-on-titan",
    "folder": "Attack on Titan",
    "db_id": 1,
    "missing_episodes": ["1-1", "1-2", "1-3"],
    "total_missing": 3
}

Enhanced Flow:

  1. Validates the request (link format, name)
  2. Creates Serie object with sanitized folder name
  3. Saves to database via AnimeDBService
  4. Creates folder using sanitized display name (not internal key)
  5. Performs targeted episode scan for this anime only
  6. Returns response with missing episodes count

Folder Name Sanitization:

  • Removes invalid filesystem characters: < > : " / \ | ? *
  • Trims leading/trailing whitespace and dots
  • Preserves Unicode characters (for Japanese titles)
  • Example: "Attack on Titan: Final Season""Attack on Titan Final Season"

Source: src/server/api/anime.py

POST /api/anime/rescan

Trigger a rescan of the local library.

Authentication: Required

Response (200 OK):

{
    "success": true,
    "message": "Rescan started successfully"
}

Source: src/server/api/anime.py

GET /api/anime/{anime_id}

Return detailed information about a specific series.

Authentication: Not required

Path Parameters:

Parameter Description
anime_id Series key (primary) or folder (deprecated fallback)

Response (200 OK):

{
    "key": "attack-on-titan",
    "title": "Attack on Titan",
    "folder": "Attack on Titan (2013)",
    "episodes": ["1-1", "1-2", "1-3"],
    "description": null
}

Source: src/server/api/anime.py


4. Download Queue Endpoints

Prefix: /api/queue

Source: src/server/api/download.py

GET /api/queue/status

Get current download queue status and statistics.

Authentication: Required

Response (200 OK):

{
    "status": {
        "is_running": false,
        "is_paused": false,
        "active_downloads": [],
        "pending_queue": [],
        "completed_downloads": [],
        "failed_downloads": []
    },
    "statistics": {
        "total_items": 5,
        "pending_count": 3,
        "active_count": 1,
        "completed_count": 1,
        "failed_count": 0,
        "total_downloaded_mb": 1024.5,
        "average_speed_mbps": 2.5,
        "estimated_time_remaining": 3600
    }
}

Source: src/server/api/download.py

POST /api/queue/add

Add episodes to the download queue.

Authentication: Required

Request Body:

{
    "serie_id": "attack-on-titan",
    "serie_folder": "Attack on Titan (2013)",
    "serie_name": "Attack on Titan",
    "episodes": [
        { "season": 1, "episode": 1, "title": "Episode 1" },
        { "season": 1, "episode": 2, "title": "Episode 2" }
    ],
    "priority": "NORMAL"
}

Priority Values: LOW, NORMAL, HIGH

Response (201 Created):

{
    "status": "success",
    "message": "Added 2 episode(s) to download queue",
    "added_items": ["uuid1", "uuid2"],
    "item_ids": ["uuid1", "uuid2"],
    "failed_items": []
}

Source: src/server/api/download.py

POST /api/queue/start

Start automatic queue processing.

Authentication: Required

Response (200 OK):

{
    "status": "success",
    "message": "Queue processing started"
}

Source: src/server/api/download.py

POST /api/queue/stop

Stop processing new downloads from queue.

Authentication: Required

Response (200 OK):

{
    "status": "success",
    "message": "Queue processing stopped (current download will continue)"
}

Source: src/server/api/download.py

POST /api/queue/pause

Pause queue processing (alias for stop).

Authentication: Required

Response (200 OK):

{
    "status": "success",
    "message": "Queue processing paused"
}

Source: src/server/api/download.py

DELETE /api/queue/{item_id}

Remove a specific item from the download queue.

Authentication: Required

Path Parameters:

Parameter Description
item_id Download item UUID

Response (204 No Content)

Source: src/server/api/download.py

DELETE /api/queue

Remove multiple items from the download queue.

Authentication: Required

Request Body:

{
    "item_ids": ["uuid1", "uuid2"]
}

Response (204 No Content)

Source: src/server/api/download.py

DELETE /api/queue/completed

Clear completed downloads from history.

Authentication: Required

Response (200 OK):

{
    "status": "success",
    "message": "Cleared 5 completed item(s)",
    "count": 5
}

Source: src/server/api/download.py

DELETE /api/queue/failed

Clear failed downloads from history.

Authentication: Required

Response (200 OK):

{
    "status": "success",
    "message": "Cleared 2 failed item(s)",
    "count": 2
}

Source: src/server/api/download.py

DELETE /api/queue/pending

Clear all pending downloads from the queue.

Authentication: Required

Response (200 OK):

{
    "status": "success",
    "message": "Removed 10 pending item(s)",
    "count": 10
}

Source: src/server/api/download.py

POST /api/queue/reorder

Reorder items in the pending queue.

Authentication: Required

Request Body:

{
    "item_ids": ["uuid3", "uuid1", "uuid2"]
}

Response (200 OK):

{
    "status": "success",
    "message": "Queue reordered with 3 items"
}

Source: src/server/api/download.py

POST /api/queue/retry

Retry failed downloads.

Authentication: Required

Request Body:

{
    "item_ids": ["uuid1", "uuid2"]
}

Pass empty item_ids array to retry all failed items.

Response (200 OK):

{
    "status": "success",
    "message": "Retrying 2 failed item(s)",
    "retried_count": 2,
    "retried_ids": ["uuid1", "uuid2"]
}

Source: src/server/api/download.py


5. Configuration Endpoints

Prefix: /api/config

Source: src/server/api/config.py

GET /api/config

Return current application configuration.

Authentication: Required

Response (200 OK):

{
    "name": "Aniworld",
    "data_dir": "data",
    "scheduler": {
        "enabled": true,
        "interval_minutes": 60
    },
    "logging": {
        "level": "INFO",
        "file": null,
        "max_bytes": null,
        "backup_count": 3
    },
    "backup": {
        "enabled": false,
        "path": "data/backups",
        "keep_days": 30
    },
    "other": {}
}

Source: src/server/api/config.py

PUT /api/config

Apply an update to the configuration.

Authentication: Required

Request Body:

{
    "scheduler": {
        "enabled": true,
        "interval_minutes": 30
    },
    "logging": {
        "level": "DEBUG"
    }
}

Response (200 OK): Updated configuration object

Source: src/server/api/config.py

POST /api/config/validate

Validate a configuration without applying it.

Authentication: Required

Request Body: Full AppConfig object

Response (200 OK):

{
    "valid": true,
    "errors": []
}

Source: src/server/api/config.py

GET /api/config/backups

List all available configuration backups.

Authentication: Required

Response (200 OK):

[
    {
        "name": "config_backup_20251213_090130.json",
        "size": 1024,
        "created": "2025-12-13T09:01:30Z"
    }
]

Source: src/server/api/config.py

POST /api/config/backups

Create a backup of the current configuration.

Authentication: Required

Query Parameters:

Parameter Type Required Description
name string No Custom backup name

Response (200 OK):

{
    "name": "config_backup_20251213_090130.json",
    "message": "Backup created successfully"
}

Source: src/server/api/config.py

POST /api/config/backups/{backup_name}/restore

Restore configuration from a backup.

Authentication: Required

Response (200 OK): Restored configuration object

Source: src/server/api/config.py

DELETE /api/config/backups/{backup_name}

Delete a configuration backup.

Authentication: Required

Response (200 OK):

{
    "message": "Backup 'config_backup_20251213.json' deleted successfully"
}

Source: src/server/api/config.py

POST /api/config/directory

Update anime directory configuration.

Authentication: Required

Request Body:

{
    "directory": "/path/to/anime"
}

Response (200 OK):

{
    "message": "Anime directory updated successfully",
    "synced_series": 15
}

Source: src/server/api/config.py


6. Scheduler Endpoints

Prefix: /api/scheduler

Source: src/server/api/scheduler.py

GET /api/scheduler/config

Get current scheduler configuration.

Authentication: Required

Response (200 OK):

{
    "enabled": true,
    "interval_minutes": 60
}

Source: src/server/api/scheduler.py

POST /api/scheduler/config

Update scheduler configuration.

Authentication: Required

Request Body:

{
    "enabled": true,
    "interval_minutes": 30
}

Response (200 OK): Updated scheduler configuration

Source: src/server/api/scheduler.py

POST /api/scheduler/trigger-rescan

Manually trigger a library rescan.

Authentication: Required

Response (200 OK):

{
    "success": true,
    "message": "Rescan started successfully"
}

Source: src/server/api/scheduler.py


7. Health Check Endpoints

Prefix: /health

Source: src/server/api/health.py

GET /health

Basic health check endpoint.

Authentication: Not required

Response (200 OK):

{
    "status": "healthy",
    "timestamp": "2025-12-13T10:30:00.000Z",
    "version": "1.0.0"
}

Source: src/server/api/health.py

GET /health/detailed

Comprehensive health check with database, filesystem, and system metrics.

Authentication: Not required

Response (200 OK):

{
    "status": "healthy",
    "timestamp": "2025-12-13T10:30:00.000Z",
    "version": "1.0.0",
    "dependencies": {
        "database": {
            "status": "healthy",
            "connection_time_ms": 1.5,
            "message": "Database connection successful"
        },
        "filesystem": {
            "status": "healthy",
            "data_dir_writable": true,
            "logs_dir_writable": true
        },
        "system": {
            "cpu_percent": 25.0,
            "memory_percent": 45.0,
            "memory_available_mb": 8192.0,
            "disk_percent": 60.0,
            "disk_free_mb": 102400.0,
            "uptime_seconds": 86400.0
        }
    },
    "startup_time": "2025-12-13T08:00:00.000Z"
}

Source: src/server/api/health.py


8. WebSocket Protocol

Endpoint: /ws/connect

Source: src/server/api/websocket.py

Connection

URL: ws://127.0.0.1:8000/ws/connect

Query Parameters:

Parameter Required Description
token No JWT token for authenticated access

Message Types

Type Direction Description
connected Server -> Client Connection confirmation
ping Client -> Server Keepalive request
pong Server -> Client Keepalive response
download_progress Server -> Client Download progress update
download_complete Server -> Client Download completed
download_failed Server -> Client Download failed
download_added Server -> Client Item added to queue
download_removed Server -> Client Item removed from queue
queue_status Server -> Client Queue status update
queue_started Server -> Client Queue processing started
queue_stopped Server -> Client Queue processing stopped
scan_progress Server -> Client Library scan progress
scan_complete Server -> Client Library scan completed
system_info Server -> Client System information message
error Server -> Client Error message

Source: src/server/models/websocket.py

Room Subscriptions

Clients can join/leave rooms to receive specific updates.

Join Room:

{
    "action": "join",
    "data": { "room": "downloads" }
}

Leave Room:

{
    "action": "leave",
    "data": { "room": "downloads" }
}

Available Rooms:

  • downloads - Download progress and status updates

Server Message Format

{
    "type": "download_progress",
    "timestamp": "2025-12-13T10:30:00.000Z",
    "data": {
        "download_id": "uuid-here",
        "key": "attack-on-titan",
        "folder": "Attack on Titan (2013)",
        "percent": 45.2,
        "speed_mbps": 2.5,
        "eta_seconds": 180
    }
}

WebSocket Status Endpoint

GET /ws/status

Returns WebSocket service status.

Response (200 OK):

{
    "status": "operational",
    "active_connections": 5,
    "supported_message_types": [
        "download_progress",
        "download_complete",
        "download_failed",
        "queue_status",
        "connected",
        "ping",
        "pong",
        "error"
    ]
}

Source: src/server/api/websocket.py


9. Data Models

Download Item

{
    "id": "uuid-string",
    "serie_id": "attack-on-titan",
    "serie_folder": "Attack on Titan (2013)",
    "serie_name": "Attack on Titan",
    "episode": {
        "season": 1,
        "episode": 1,
        "title": "To You, in 2000 Years"
    },
    "status": "pending",
    "priority": "NORMAL",
    "added_at": "2025-12-13T10:00:00Z",
    "started_at": null,
    "completed_at": null,
    "progress": null,
    "error": null,
    "retry_count": 0,
    "source_url": null
}

Status Values: pending, downloading, paused, completed, failed, cancelled

Priority Values: LOW, NORMAL, HIGH

Source: src/server/models/download.py

Episode Identifier

{
    "season": 1,
    "episode": 1,
    "title": "Episode Title"
}

Source: src/server/models/download.py

Download Progress

{
    "percent": 45.2,
    "downloaded_mb": 256.0,
    "total_mb": 512.0,
    "speed_mbps": 2.5,
    "eta_seconds": 180
}

Source: src/server/models/download.py


10. Error Handling

HTTP Status Codes

Code Meaning When Used
200 OK Successful request
201 Created Resource created
204 No Content Successful deletion
400 Bad Request Invalid request body/parameters
401 Unauthorized Missing or invalid authentication
403 Forbidden Insufficient permissions
404 Not Found Resource does not exist
422 Unprocessable Entity Validation error
429 Too Many Requests Rate limit exceeded
500 Internal Server Error Server-side error

Error Response Format

{
    "success": false,
    "error": "VALIDATION_ERROR",
    "message": "Human-readable error message",
    "details": {
        "field": "Additional context"
    },
    "request_id": "uuid-for-tracking"
}

Source: src/server/middleware/error_handler.py

Common Error Codes

Error Code HTTP Status Description
AUTHENTICATION_ERROR 401 Invalid or missing credentials
AUTHORIZATION_ERROR 403 Insufficient permissions
VALIDATION_ERROR 422 Request validation failed
NOT_FOUND_ERROR 404 Resource not found
CONFLICT_ERROR 409 Resource conflict
RATE_LIMIT_ERROR 429 Rate limit exceeded

11. Rate Limiting

Authentication Endpoints

Endpoint Limit Window
POST /api/auth/login 5 requests 60 seconds
POST /api/auth/setup 5 requests 60 seconds

Source: src/server/middleware/auth.py

Origin-Based Limiting

All endpoints from the same origin are limited to 60 requests per minute per origin.

Source: src/server/middleware/auth.py

Rate Limit Response

{
    "detail": "Too many authentication attempts, try again later"
}

HTTP Status: 429 Too Many Requests


12. Pagination

The anime list endpoint supports pagination.

Query Parameters:

Parameter Default Max Description
page 1 - Page number (1-indexed)
per_page 20 1000 Items per page

Example:

GET /api/anime?page=2&per_page=50

Source: src/server/api/anime.py