postprocess plugin - degoya/rDownloader GitHub Wiki

Writing a post-processing step

A post-processing step runs once a package has been downloaded, after cleanup and before a user script: checking, converting, renaming, tagging. It is switched on globally or per category, in an ordered list — installing one changes nothing until somebody enables it.

Scaffold rdownloader plugin new --type postprocess
plugin_type postprocess
World postprocess-plugin
Exports run
Template sdk/templates/postprocess
Contract Interface postprocess

What the host promises

  • You never name a file. A package handle plus the names in files is all there is, and both only mean anything inside this invocation. files holds every file of the package, folders walked, as relative paths (Film/film.mkv). A file may be renamed to a bare name in the folder it is in, never over an existing one.
  • Stopping is normal. Check should-stop and return stopped with a checkpoint; the host stores it and hands it back, so a service restart resumes instead of starting over.
  • You are told what is gone on purpose. removed names, like files, what post-processing removed before your step ran: unpacked archive volumes, PAR2 files, what the cleanup deleted. A checksum list that names one of them is not wrong; no need to guess from an extension.
  • A pass can say something. complete carries warnings next to the checkpoint: codes from your locales/, with parameters and an English fallback. The step is shown as completed with the warning on it — the place for "passed, but three listed files were not here".

Permissions

The scaffold asks for nothing: reading the package is part of the type, through source, which no manifest can ask for. Add net_http only for a step that has to reach a service.

[extension] claims stays empty: a step is switched on per category rather than matched against a link.

Ask for exactly what you use: the install preview shows every grant, and a component importing an interface its manifest does not grant cannot be instantiated. Every capability is listed under Capabilities.

Rules worth knowing first

Nothing to do is skipped, not failed — a failure would fail every package in a category the step is switched on for. Something worth saying about a pass is a warning, not a failure either. And the checkpoint holds everything a resumed run needs, not only an offset: the scaffold's keeps the file, the offset and the checksum so far.

Step by step

1. Scaffold it

plugin new reads its templates from sdk/templates, so run it from a checkout of the repository:

git clone https://github.com/degoya/rDownloader.git
cd rDownloader
rdownloader plugin new --type postprocess --out ../mystep
cd ../mystep

Without an installation of rDownloader, the packaging tool rd-pack — cargo build --profile release-test -p rd-pack in the checkout — takes the same arguments: target/release-test/rd-pack plugin new --type postprocess --out ../mystep.

The directory name becomes the crate name and the plugin's slug (--name sets another). The scaffold gets its own plugin id, its own copy of the contract in wit/rdownloader.wit and its own Ed25519 key pair: plugin-signing.key, whose public half is already in manifest.toml. Keep that file out of version control.

2. Make it yours

  • src/lib.rs holds the work and the checkpoint; the scaffold computes a CRC-32 per file, reading in chunks and stopping half-way without losing what was done.
  • src/guest.rs holds run.
  • manifest.toml: [limits] timeout_milliseconds — a step may run for minutes.
  • locales/en.json: the English text of every failure and warning code you report.

Change description and author under [metadata], and read the comment at the top of src/lib.rs: it states what the host promises this type.

3. Test it

cargo test

The unit tests need no WebAssembly toolchain: only src/guest.rs is wasm32-specific. Give every answer of your provider you read a test of its own.

4. Build the component

cargo build --release --target wasm32-unknown-unknown
wasm-tools component new target/wasm32-unknown-unknown/release/mystep.wasm -o target/mystep.wasm

This needs the wasm32-unknown-unknown target and wasm-tools 1.261.0, the version the bundled plugins are made with: cargo build makes a core module that carries the world src/guest.rs generates, and wasm-tools component new turns it into the component. The plugin is built without WASI: a component importing anything outside rdownloader:plugin is refused — see Building without WASI.

5. Package and sign it

rdownloader plugin package --manifest manifest.toml \
  --component target/mystep.wasm \
  --locales locales --key plugin-signing.key --output mystep.rdplug
rdownloader plugin conformance mystep.rdplug --json

conformance answers whether this application would run the package; it has to be clean before you publish. For a key that outlives the scaffold, rdownloader plugin keygen --role plugin --output ./keys writes a pair: the Base64 in the .pub file goes into public_key, and key_id gets a name of your own. In CI, RDOWNLOADER_PLUGIN_SIGNING_KEY holding the private key's PEM text replaces --key. Details: Packaging, signing and distribution.

6. Install and trust it

For a first try without signing, package with --development instead of --key and start rdownloader serve --plugin-development-mode, the only mode that accepts an unsigned package.

Install a signed package under Settings → Plugins → Add as an upload, or with rdownloader plugin install mystep.rdplug --root data/plugins. Review before installing shows every permission and the signing key; a key this installation has not seen asks to be trusted — compare its fingerprint. The message after installing says whether the plugin runs at once or after the next restart; see Installing and trust.

Enable the step under Settings → Post-processing → Scripts & upload, globally or for one category, and download a package into it; see Post-processing.

7. Publish it

Publish the .rdplug together with your key's fingerprint, or — so that people get your new versions in the Catalogue — in a plugin repository of your own: a signed index built with rdownloader plugin index build and a repository-role key. A repository only delivers: every package in it still needs your plugin key, approved by the person installing it. See A repository index and Running a plugin repository.

The SDK's reusable CI workflow, sdk/ci/plugin.yml, builds, checks the imports, packages and runs conformance on every push and pull request; it signs only on a push to the default branch or a tag, so a pull request never sees the key.

Read next

⚠️ **GitHub.com Fallback** ⚠️