Risuko
Architecture

RPC Protocol

The JSON-RPC interface used by the CLI and external clients.

Risuko exposes a JSON-RPC 2.0 server over HTTP. The CLI uses this interface, and you can also build custom clients.

Connection

The RPC server listens on http://127.0.0.1:16800/jsonrpc by default. Host, port, and secret come from the rpc-host, rpc-listen-port, and rpc-secret config keys.

Besides POST, the same endpoint accepts GET /jsonrpc?method=<name>&id=<id>&params=<base64(JSON array)>. An optional jsoncallback query parameter wraps the response in JSONP. A GET with an Upgrade: websocket header opens a WebSocket instead (see below).

Request Format

{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "risuko.addUri",
  "params": [
    ["https://example.com/file.zip"],
    { "split": "16", "dir": "/downloads" }
  ]
}

params must be a positional array; named (object) params are rejected with -32602. The body may also be a batch array of request objects.

Response Format

{
  "jsonrpc": "2.0",
  "id": "1",
  "result": "a1b2c3d4e5f6"
}

Available Methods

Task Management

MethodParametersReturns
risuko.addUri[uris[], options?]GID string
risuko.addTorrent[base64Data, uris[], options?]GID string
risuko.addMetalink[base64MetalinkData, options?]GID string
risuko.addNzb[base64NzbData, options?]GID string
risuko.addEd2k[uri, options?]GID string
risuko.addMedia[url, options?]GID string
risuko.pause[gid]GID string
risuko.unpause[gid]GID string
risuko.remove[gid]GID string
risuko.forcePause[gid]GID string
risuko.forceRemove[gid]GID string
risuko.pauseAll"OK"
risuko.unpauseAll"OK"
risuko.forcePauseAll"OK"
risuko.changePosition[gid, pos?, how?]New position
risuko.updateTask[gid, patch]{ restarted, trackersAdded, progressPreserved }

risuko.addMedia accepts URLs from supported media sites (downloaded via yt-dlp). Other URLs are rejected with "Not a supported media URL" unless the force-ytdlp option is set. Methods that take a gid also accept a unique GID prefix of at least 4 characters.

risuko.addMetalink accepts a standard-base64 Metalink document (.meta4 / .metalink). risuko.updateTask applies a { uris, dir, out, trackers, options } patch; see updateTask.

risuko.addNzb accepts a standard-base64 NZB document, not a URL. It creates one Usenet task from the parsed manifest. The options object may select a non-secret provider reference or cleanup policy, but it must not contain provider credentials or archive passwords. Configure those in the desktop app's Provider Profiles editor instead.

{
  "jsonrpc": "2.0",
  "id": "nzb-1",
  "method": "risuko.addNzb",
  "params": [
    "PD94bWwgdmVyc2lvbj0iMS4wIj8+Li4u",
    {
      "dir": "/downloads",
      "usenet-profile-id": "primary",
      "usenet-cleanup-mode": "keep-all"
    }
  ]
}

Queries

MethodParametersReturns
risuko.tellStatus[gid, keys?]Status object
risuko.tellActive[keys?]Status object array
risuko.tellWaiting[offset?, num?, keys?]Status object array
risuko.tellStopped[offset?, num?, keys?]Status object array
risuko.getGlobalStatStat object
risuko.getFiles[gid]File array
risuko.getPeers[gid]Peer array
risuko.setBtPeerBlocklist[entries[]]{ revision, ruleCount, disconnectedPeers, removedPeers }
risuko.getUris[gid]URI array
risuko.getServers[gid]Server array
risuko.getVersionVersion object
risuko.getSessionInfoSession info object

risuko.tellWaiting returns waiting and paused tasks. Scheduled tasks are a desktop/Tauri list (tell_scheduled), not a JSON-RPC method. risuko.getGlobalStat does count scheduled tasks in numWaiting, matching aria2's broad "not active yet" bucket.

risuko.setBtPeerBlocklist full-replaces the process-wide BitTorrent IP/CIDR blocklist. Each string is a plain IP (1.2.3.4, 2001:db8::1) or CIDR (10.0.0.0/8, 2001:db8::/32); invalid entries are ignored. Connected peers that match are disconnected and dropped from the swarm. PeerBanHelper drives this method through the Aria2Next-compat listener (see below).

Options

MethodParametersReturns
risuko.getOption[gid]Options object
risuko.getGlobalOptionOptions object
risuko.changeOption[gid, options]"OK"
risuko.changeGlobalOption[options]"OK"

Session

MethodParametersReturns
risuko.saveSession"OK"
risuko.purgeDownloadResult"OK"
risuko.removeDownloadResult[gid]"OK"
risuko.shutdown"OK"
risuko.forceShutdown"OK"

shutdown saves the session before stopping the engine; forceShutdown skips the save.

Task Routing

Pattern-based rules that override the download directory and assign a tag based on the inferred output filename. See the Task Routing guide.

MethodParametersReturns
risuko.listRoutingRulesRule array
risuko.addRoutingRule[rule]The rule, with id filled in if omitted
risuko.updateRoutingRule[rule]"OK"
risuko.removeRoutingRule[ruleId]"OK"
risuko.resolveRouting[filename]{ tag, dir } decision preview against the current rules

A rule has the shape:

{
  "id": "rule-videos",
  "label": "Videos",
  "pattern": "*.mkv",
  "dir": "/downloads/videos",
  "enabled": true
}

pattern is a case-insensitive glob (glob crate syntax) matched against the inferred filename only — not the URL or directory.

Example: curl

# Add a download
curl -X POST http://localhost:16800/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": "1",
    "method": "risuko.addUri",
    "params": [["https://example.com/file.zip"], {"split": "16"}]
  }'

# Check status
curl -X POST http://localhost:16800/jsonrpc \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": "2",
    "method": "risuko.tellActive",
    "params": []
  }'

Error Responses

{
  "jsonrpc": "2.0",
  "id": "1",
  "error": {
    "code": 1,
    "message": "Task a1b2c3d4 not found"
  }
}

Protocol errors use the standard JSON-RPC codes: -32700 (parse error), -32600 (invalid request), -32601 (method not found), -32602 (invalid params). Application errors — including failed authentication — use code 1.

aria2 Compatibility

The RPC server accepts both risuko.* and aria2.* method prefixes. For example, aria2.addUri is treated as risuko.addUri. This makes it compatible with existing aria2 RPC clients. system.listMethods returns every method under both prefixes.

PeerBanHelper / Aria2Next listener

When pbh-enable is true, the engine starts a second JSON-RPC server on pbh-listen-port (default 16801), bound to the same rpc-host as the primary RPC. That listener uses Aria2Next compatibility mode:

  • GET/POST / is accepted in addition to /jsonrpc (PeerBanHelper posts to the root)
  • aria2.getVersion reports { version: "1.37.0", product: "aria2-next", rpcVersion: "1", enabledFeatures: [...] } instead of the Risuko engine version
  • aria2.getPeers includes the extra Aria2Next fields listed in getPeers
  • aria2.setBtPeerBlocklist applies the IP/CIDR blocklist described above

In PeerBanHelper, add an Aria2Next downloader pointed at http://127.0.0.1:16801/jsonrpc (or the configured port) and set the RPC token to pbh-rpc-secret. These keys are startup-only.

Authentication

When rpc-secret is set, every call must prefix its params array with "token:<secret>":

{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "risuko.addUri",
  "params": ["token:my-secret", ["https://example.com/file.zip"]]
}

The token is stripped from params before dispatch. When rpc-secret is empty, the token: prefix is still accepted (and stripped) for compatibility with aria2 clients that always send one.

system.multicall

Batch any number of calls into a single round-trip. Per aria2 convention, the outer params array is not authenticated; each nested call is authenticated independently and must carry its own "token:<secret>" prefix when rpc-secret is set.

{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "system.multicall",
  "params": [[
    { "methodName": "risuko.tellActive", "params": ["token:my-secret"] },
    { "methodName": "risuko.getGlobalStat", "params": ["token:my-secret"] }
  ]]
}

Returns an array where each element is either [result] (success) or { "code", "message" } (per-call error). The legacy ["token:...", [calls]] shape is also accepted, but the outer token is never trusted as authentication.

WebSocket Subscribe

The server upgrades GET /jsonrpc requests with a Connection: Upgrade / Upgrade: websocket header to a WebSocket. Once connected, the engine streams JSON-RPC notifications for every task transition: risuko.onDownloadStart, risuko.onDownloadPause, risuko.onDownloadStop, risuko.onDownloadComplete, risuko.onDownloadError, risuko.onBtDownloadComplete. Pushed notifications always use the risuko. prefix, even though system.listNotifications lists each name under both prefixes. Each notification carries params: [{"gid": "<gid>"}] and no id. Regular request/response calls also work over the same socket.

On this page