Anime Upscaling video restoration

Anime Upscaling API

Go HTTP API for managing video upscaling and optimization jobs with video2x and FFmpeg.

See docs/ARCHITECTURE.md for the system design (trust boundary, queues, job lifecycle, GPU monitor).

Base URL: http://localhost:4751 when running the API directly. In the default Docker Compose stack, the API is private to the Compose network and the web app proxies browser requests to it.

Configuration

Setting Value
Port API_PORT, default 4751
Base directory PROCESS_DIR, default /data
Input directory {BaseDir}/input
Output directory {BaseDir}/output
Optimized directory {BaseDir}/optimized
Interpolated directory {BaseDir}/interpolated
Supported extensions .mkv, .mp4, .avi
CORS All origins (*), methods GET, POST, PUT, DELETE, OPTIONS. Keep the API on a trusted private network.

Endpoints

GET /api/files

List video files in a directory.

Query Parameters:

Param Type Default Description
dir string "input" One of input, output, interpolated, optimized

Response 200:

{
  "dir": "input",
  "files": ["video1.mkv", "video2.mp4"]
}

Response 400:

{ "error": "invalid dir: must be input, output, optimized, or interpolated" }

Example:

curl 'http://localhost:4751/api/files?dir=input'

GET /api/jobs

List all jobs.

Response 200:

[
  {
    "id": "j_1708540800_1a2b",
    "type": "upscale",
    "status": "running",
    "files": ["video1.mkv"],
    "progress": {
      "total": 1,
      "completed": 0,
      "failed": 0,
      "skipped": 0,
      "current": "Processing video1.mkv"
    },
    "created_at": "2024-02-21T12:00:00Z",
    "finished_at": null
  }
]

Example:

curl http://localhost:4751/api/jobs

POST /api/jobs

Create a new job.

Request Body:

Field Type Required Description
type string yes "upscale", "interpolate", "optimize", or "check"
files string[] no Filenames from the selected source. If empty, uses all videos in that source
source string no One of input, output, interpolated, optimized; defaults to input
frame_rate number no Optimize-only frame-rate divisor: 1 original, 2 half, or 4 quarter
{
  "type": "upscale",
  "files": ["video1.mkv", "video2.mp4"]
}

Response 201:

{
  "id": "j_1708540800_1a2b",
  "type": "upscale",
  "status": "queued",
  "files": ["video1.mkv", "video2.mp4"]
}

Response 400:

{ "error": "type must be upscale, optimize, check, or interpolate" }
{ "error": "no video files found in input/" }
{ "error": "file not found in input/: video1.mkv" }

Examples:

# Upscale specific files
curl -X POST http://localhost:4751/api/jobs \
  -H 'Content-Type: application/json' \
  -d '{"type": "upscale", "files": ["video1.mkv"]}'

# Optimize all files in input/
curl -X POST http://localhost:4751/api/jobs \
  -H 'Content-Type: application/json' \
  -d '{"type": "optimize"}'

# Check all files in optimized/
curl -X POST http://localhost:4751/api/jobs \
  -H 'Content-Type: application/json' \
  -d '{"type": "check", "source": "optimized"}'

GET /api/jobs/{id}

Get job details.

Path Parameters:

Param Type Description
id string Job ID (e.g. j_1708540800_1a2b)

Response 200:

{
  "id": "j_1708540800_1a2b",
  "type": "upscale",
  "status": "completed",
  "files": ["video1.mkv"],
  "progress": {
    "total": 1,
    "completed": 1,
    "failed": 0,
    "skipped": 0,
    "current": ""
  },
  "created_at": "2024-02-21T12:00:00Z",
  "finished_at": "2024-02-21T12:10:00Z"
}

Response 404:

{ "error": "job not found" }

Example:

curl http://localhost:4751/api/jobs/j_1708540800_1a2b

GET /api/jobs/{id}/logs

Return a snapshot of a job's logs. Clients poll this endpoint (the web app polls every ~1.5s) and pass ?since=<cursor> to fetch only entries newer than the cursor. It is plain JSON, not Server-Sent Events.

Path Parameters:

Param Type Description
id string Job ID

Query Parameters:

Param Type Default Description
since int 0 Return only log entries with array index >= this value

Response 200:

{
  "entries": [
    {
      "source": "GPU 0",
      "level": "INFO",
      "index": 1,
      "message": "Iniciando: video1.mkv",
      "time": "2024-02-21T12:00:05Z"
    }
  ],
  "total": 1,
  "running": true
}
Field Type Description
entries array Log entries with array index >= since
total int Current log length — send this back as the next since cursor
running bool true while the job is queued or running; clients stop polling when false

Each entry has these fields:

Field Type Description
source string Worker identifier ("GPU 0", "GPU 1", "FFMPEG", "PIPELINE")
level string Log level (see table below)
index int File index in the job
message string Log message
time string ISO 8601 timestamp

Response 404:

{ "error": "job not found" }

Example:

# Fetch all logs, then poll for new ones past the returned `total`.
curl 'http://localhost:4751/api/jobs/j_1708540800_1a2b/logs?since=0'

GET /api/health/gpu

Snapshot of the GPU health monitor. Probes nvidia-smi -L every 30s with an 8-second timeout; after 2 consecutive failures the GPU is marked unhealthy and new GPU job dispatch is paused until the probe succeeds again. For non-NVIDIA deployments the monitor stays disabled and always reports healthy.

Response 200:

{
  "enabled": true,
  "healthy": true,
  "last_check": "2026-05-04T20:30:00Z",
  "last_healthy": "2026-05-04T20:30:00Z",
  "consecutive_failures": 0
}

When unhealthy, last_error carries the probe error and queued GPU jobs block on Acquire until recovery. The monitor only stops dispatch; host-side recovery (PCI remove+rescan, restarting the container) is out of scope for this process and should be handled by your own host watchdog.

Example:

curl http://localhost:4751/api/health/gpu

POST /api/jobs/{id}/cancel

Cancel a running job.

Path Parameters:

Param Type Description
id string Job ID

Response 200:

{
  "id": "j_1708540800_1a2b",
  "status": "cancelled"
}

Response 404:

{ "error": "job not found" }

Example:

curl -X POST http://localhost:4751/api/jobs/j_1708540800_1a2b/cancel

Job Types

Type Description Workers
upscale Super-resolution using video2x GPU queue
interpolate Frame interpolation using video2x/RIFE GPU queue
optimize Compression/transcode using ffmpeg FFmpeg queue or GPU queue when hardware encode is enabled
check Integrity check using full ffmpeg decode FFmpeg queue

Upscale

Optimize

Saved Pipelines

Job Statuses

Status Description
running Job is currently executing
completed All files processed successfully
failed An error occurred during processing
cancelled Job was manually cancelled

Log Levels

Level Meaning Effect on Progress
INFO Informational Updates progress.current
OK File completed Increments progress.completed
ERRO File failed Increments progress.failed
SKIP File skipped (already exists) Increments progress.skipped
WARN Warning None

Error Response Format

All errors return JSON:

{ "error": "description of the error" }
Status Code Meaning
200 Success
201 Job created
204 CORS preflight
400 Invalid request
404 Job not found
405 Method not allowed
500 Internal server error

Edit this page on GitHub