Risuko
Guides

Batch Downloads

Download multiple files efficiently with Risuko.

Per-URL Rename Directive

In the desktop app's Add Task dialog, append Rename: <filename> to any URL on its own line to override the output filename for just that link:

https://example.com/abc123/file.bin Rename: ubuntu.iso
https://example.com/xyz/raw?id=42  Rename: report.pdf
https://example.com/another.zip
  • The directive is matched case-insensitively at the end of a line and separated from the URL by whitespace.
  • Filenames may contain spaces; path separators (/, \) are rejected and the line is treated as a plain URL when one is present.
  • A per-line Rename: always wins over the form-level Rename field (which still supports the index expansion rule, e.g. file-(01+1).zip).
  • Magnet links and .torrent files are not affected by this directive (their output names come from the torrent metadata).

thunder:// links and curl ... paste-as-task lines are decoded first and the directive is applied to the resulting URL.

CLI Batch Downloads

From a URL List File

# urls.txt — one URL per line
while IFS= read -r url; do
  risuko download "$url" -d ~/Downloads
done < urls.txt

Parallel with Wait

# Download multiple files concurrently
risuko download https://example.com/file1.zip &
risuko download https://example.com/file2.zip &
risuko download https://example.com/file3.zip &
wait
echo "All downloads complete"

With JSON Scripting

# Get all GIDs, then wait for completion
for url in $(cat urls.txt); do
  risuko download "$url" --json 2>/dev/null &
done
wait

# Check final status
risuko status --json | jq '.[] | {gid, status, name: .files[0].path}'

Node.js Batch Downloads

Simple Batch

import { startEngine, addUri, onEvent, stopEngine } from "@risuko/risuko-js";

const urls = [
  "https://example.com/file1.zip",
  "https://example.com/file2.zip",
  "https://example.com/file3.zip",
];

await startEngine();

const gids = [];
for (const url of urls) {
  const gid = await addUri([url], { dir: "/downloads" });
  gids.push(gid);
}

console.log(`Started ${gids.length} downloads`);

With Concurrency Control

import { startEngine, changeGlobalOption, addUri, onEvent } from "@risuko/risuko-js";

await startEngine();

// Limit to 3 concurrent downloads
await changeGlobalOption({ "max-concurrent-downloads": "3" });

const urls = Array.from({ length: 20 }, (_, i) =>
  `https://example.com/file${i + 1}.zip`
);

let completed = 0;
onEvent((event) => {
  if (event === "risuko.onDownloadComplete") {
    completed++;
    console.log(`Progress: ${completed}/${urls.length}`);
  }
});

for (const url of urls) {
  await addUri([url], { dir: "/downloads" });
}

With Speed Limiting

import { startEngine, changeGlobalOption } from "@risuko/risuko-js";

await startEngine();

// Limit total bandwidth to 50 MB/s
await changeGlobalOption({
  "max-overall-download-limit": String(50 * 1024 * 1024),
});

Global Speed Limiting via CLI

# Set global speed limit
risuko config set max-overall-download-limit '"52428800"'  # 50 MB/s

# Set per-download connection count
risuko config set split '"8"'

On this page