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 — the directive is stripped from the line and the URL is used without a rename. - 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
.torrentfiles are not affected by this directive (their output names come from the torrent metadata).
For thunder:// links and curl ... paste-as-task lines, the directive is
parsed off the line first; the remaining link or command is decoded
afterwards.
Scheduled Starts
The desktop app can hold URI tasks until a future time. In the Add Task dialog,
set Time before submitting the batch; Risuko stores the Unix timestamp as
the risuko-start-at task option and creates each non-torrent item with status
scheduled.
- Scheduled items live in the Scheduled list until their
startAttime. - Torrent items ignore the schedule field and start immediately.
- Existing non-torrent tasks can be scheduled, rescheduled, or started now from the task action menu.
- If the app misses the start time by more than 5 minutes, the task remains
scheduled with
scheduleMissed: trueand the desktop app offers to start the missed tasks manually.
Queue Order And Concurrency
Drag task rows, or use the keyboard reorder handle, to move tasks in the All, Active, Waiting, and Scheduled lists when default sorting is active and no filter is applied. The order is persisted through the engine session.
For non-torrent tasks, max-concurrent-downloads is a strict queue cap. When a
higher-priority waiting or due scheduled task should run, the engine preempts a
lower-priority active worker back to waiting and restarts it later. BitTorrent
tasks are managed by the torrent engine and are not preempted by this cap.
CLI Batch Downloads
Passing multiple URLs to a single risuko download does not batch: the URLs
are treated as HTTP mirrors of one file. Run one download per file instead.
From a URL List File
# urls.txt — one URL per line
while IFS= read -r url; do
risuko download "$url" -d ~/Downloads
done < urls.txtParallel 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"Start an engine before running downloads in parallel (the desktop app, or
risuko serve in another terminal). When no engine is running, download
starts a temporary in-process engine and shuts it down as soon as its own
download finishes — killing any sibling downloads that attached to it.
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}'Managing a Batch
risuko global-stat # overall speeds and active/waiting/stopped counts
risuko pause-all
risuko resume-all
risuko purge # clear completed/error/removed resultsNode.js Batch Downloads
Simple Batch
import { startEngine, addUri } 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((eventName, gid) => {
if (eventName === "risuko.onDownloadComplete") {
completed++;
console.log(`Progress: ${completed}/${urls.length} (${gid})`);
}
});
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
Engine-wide keys set from the CLI must go inside the engine-overrides
object — risuko config set writes to the user config, and the engine only
reads keys like max-overall-download-limit from there via
engine-overrides. The value is picked up the next time the engine starts.
# Set global speed limit (K/M suffixes supported)
risuko config set engine-overrides '{"max-overall-download-limit": "50M"}'
# Connection count is per download (default 16)
risuko download https://example.com/file.zip -t 8