Processor API

Processor is a standalone node module that will be required/loaded by a Drovp thread.

It runs in its own raw Node.js process, and it's responsibility is to accept an operation payload, and return a promise that resolves when the operation has been processed.

The function has to be exported as a default export using CommonJS. ESModules are not supported yet (#2).

Example module
module.exports = async (payload, utils) => {
    const {input, options} = payload;

    // ... do what needs to be done to the input

    // Optionally emit outputs

    // Use node's built-in `console.*` methods for debugging/logging
    console.time('log time');
    console.timeEnd('log time');


If you want to log some stuff for debugging, use node's built-in console.* methods, but maybe read up on the non-standard logging environment documented in the log utility below. If you want to prevent the issues described there, you can just use the utils.log() instead, but this is not necessary in most cases.

These logs can then be seen in the operations Logs section.


Type: (operation: Operation, utils: ProcessorUtils) => Promise<void>

Processor is a simple async function that accepts operation payload, some utilities, and resolves when everything is done.


Type: Operation

The operation payload. See Operation below for more details.


Type: ProcessorUtils

The operation utilities. You can use these to report progress, access Drovp dependencies, emit outputs, ...

See ProcessorUtils API below for more details.


Promise that resolves when operation is done. Any resolved value is ignored.

If you want to emit an output item, use utils.output API.

If the promise throws, it's the same as calling utils.output.error(message) and resolving right afterwards.


interface Payload {
    id: string;
    options?: object;
    inputs: Item[];
    input: Item; // convenience getter for the 1st item in the `items` array

Operation payload with these properties:


Type: string

Operation ID.


Type: object

Processor's options schema generated and user configured options of the profile into which the item(s) were dropped into.

If processor doesn't have an options schema, this is undefined.


For options schema that looks like this:

    {name: 'foo', type: 'boolean', default: false},
    {name: 'bar', type: 'number', default: 0},

And assuming the user has kept all of the profile options on their default values, you'll get this options object:

{foo: false, bar: 0}


Type: Item | Item[]

If processor config doesn't allow bulking (default behavior), operation will always have a single Item in it's inputs array. If bulking is enabled, there will be as many items in this array as user has dropped into the profile.

input is just a convenience getter for the 1st item in the inputs array. Useful if you only expect one input per operation.


Type: any

Processor can also configure an operation preparator, which can modify the operation payload however it sees fit, in which case the payload will also have other properties you decided to add to it.


Type: ItemFile | ItemDirectory | ItemBlob | ItemString | ItemUrl

Depending on processor's accepts.* configuration, Item can be one of:


interface ItemFile {
    kind: 'file';
    type: string; // Lowercase extension without the dot
    path: string; // Path to the file
    size: number; // File size


interface ItemDirectory {
    kind: 'directory';
    path: string; // Path to the directory


interface ItemBlob {
    kind: 'blob';
    mime: string; // Blob mime type
    contents: Buffer; // BLob contents as a Buffer


interface ItemString {
    kind: 'string';
    type: string; // String type, e.g. 'text/plain'
    contents: string; // String contents


interface ItemUrl {
    kind: 'url';
    url: string; // URL path


interface ProcessorUtils {
    dependencies: {[key: string]: any};
    output: OutputEmitters;
    progress: ProgressUtil;
    title: (value: string | undefined | null) => void;
    stage: (name: string) => void;
    log: (...args: any[]) => void;
    appVersion: string;


Type: {[key: string]: any}

A map of dependency names and their exports. Usually the exports are paths to binaries, but it can be any serializable value. See each dependency's documentation for what is being exported.

Each dependency export can be accessed with its short, and full no-collision name.


If you depend on @drovp/ffmpeg:ffprobe, your dependencies map will look like this:

    ffprobe: '/path/to/ffprobe/binary',
    '@drovp/ffmpeg:ffprobe': '/path/to/ffprobe/binary',


Type: OutputEmitters

Utilities for emitting output items. See OutputEmitters for details.

Quick example
output.warning('Something of interest.');
output.error(new Error('Something went wrong.'));
output.error('Something went wrong.');
// Attaching flair and/or badge
output.file('/path/to/file', {
    flair: {variant: 'warning', title: 'foo', description: 'This item food the bad'},
    badge: {variant: 'warning', icon: 'warning', title: 'This item food the bad'},


Type: Progress

A progress reporting utility. See Progress.

Quick example
// using `progress()` method always sets all 3 values
// `total` and `indeterminate` parameters are always optional,
// and set to undefined when omitted
progress(completed, total, indeterminate);
progress(null); // reset all
progress({completed: 1, total: 10, indeterminate: true}); // object format

// using `progress.X` only updates concerned property
progress.completed = 1; = 10;
progress.indeterminate = true;


Type: (value: string | undefined | null) => void

Sets or deletes operation title. By default, operation titles are constructed from its payload (file paths, domains, etc), but if you have something more descriptive or relevant, you can use this to overwrite it.


Type: (name: string) => void

Used to name the stage the operation is currently in. This is just to provide an extra piece of information to the user.

The name should be 20 characters and less.

For example, if the operation downloads something and then extracts it, you'd set it to downloading, than extracting.

Setting a stage logs STAGE: ${name} to the operation log.


Type: (...args: any[]) => void

Logs one or multiple values into the current operations Logs section.

This is the actual utility responsible for sending operation logs. The global console.log is replaced with it for the duration of the operation. This is necessary because all messaging (utils.output.*, utils.stage, ...) is handled through IPC channel, while console.log outputs to stdout, is batched, and therefore not reliably in sync with other stuff. This would often cause operation logs to be out of sync/order with progress/stage/etc reporting, or even cause debugging issues where stuff that is logged just before the operation resolves is nowhere to be seen.

You can continue using console.log, as it's definitely more comfortable (you don't have to be passing the log utility to all dependencies), but just be aware that even thought it's replaced with the immediate IPC version, there is still an issue where if something in your operation reports AFTER the operation resolved (some hanging unresolved async calls you forgot to await for), it'll either be logged in the logs of the operation that came after it, or if the process is idle, logged in the Drovp's developer console as "Thread stdout with no job in progress" error. If preventing this is a high priority, you can of course just use this log() instead of console.log() directly, as it's scoped to the current operation.

Note: console.log is the only replaced console.* method. Everything else still reports through stdout/err, and has the aforementioned caveats.


Type: string

Current Drovp app version.