# Media and voice commands

> Revoice tracks, burn in captions, build slideshows and overlays, process audio and plan edits with the voice, media, audio and edit commands of the Nodaro CLI.

Source: https://nodaro.ai/docs/developers/cli/media-commands

The **media and voice commands** of the Nodaro CLI work on audio, video and images directly. The `voice` group revoices tracks and designs voices, `media` imports, trims, captions and composes media, `audio` processes and transcribes sound, and `edit` plans and applies edits for podcasts and long videos. Each command runs the same engine as the matching node in the editor.

Every command that starts a job accepts `--watch` to wait for the result, `--poll-interval <ms>` to set the polling interval, and `--json`. See [Output and exit codes](https://nodaro.ai/docs/developers/cli/output).

## Voice

```bash
nodaro voice list [--clones] [--json]
nodaro voice changer --voice <id> --audio <url>|--video <url> [--model <id>] [--stability <0..1>] [--similarity <0..1>] [--style <0..1>] [--use-speaker-boost] [--seed <n>] [--remove-background-noise] [--watch] [--poll-interval <ms>] [--json]
nodaro voice recast --audio <url>|--video <url> --voices <v1,v2,...>|--voices-json <json> [--model <id>] [--output video|stems] [--analysis-json <json>|--analysis-file <path>] [--no-preserve-background] [--separation-quality fast|best] [--music-volume-mode match|normalize|manual] [--music-volume <0-200>] [--remove-background-noise] [--voice-fx <preset>] [--voice-fx-mix <0-100>] [--voice-fx-delay <20-2000>] [--voice-fx-decay <0-1>] [--watch] [--poll-interval <ms>] [--json]
nodaro voice analyze --audio <url>|--video <url> [--separation-quality fast|best] [--suggest-title] [--watch] [--poll-interval <ms>] [--json]
nodaro voice export --source <videoUrl> --tracks-json <json>|--tracks-file <path> [--voice-fx <preset>] [--voice-fx-mix <0-100>] [--voice-fx-delay <20-2000>] [--voice-fx-decay <0-1>] [--watch] [--poll-interval <ms>] [--json]
nodaro voice design --text <line> --description <desc> [--model <id>] [--loudness <-1..1>] [--guidance-scale <0-100>] [--seed <n>] [--quality <n>] [--enhance] [--user-prompt <text>] [--watch] [--poll-interval <ms>] [--json]
nodaro voice remix --text <text> --description <desc> [--user-prompt <text>] [--watch] [--poll-interval <ms>] [--json]
nodaro voice dub --audio <url> --target-language <code> [--source-language <code>] [--num-speakers <1-20>] [--disable-voice-cloning] [--drop-background-audio] [--watch] [--poll-interval <ms>] [--json]
nodaro voice clones list [--json]
nodaro voice clones delete <id> [--json]
```

| Command | What it does |
| --- | --- |
| `voice list` | Lists the premade voices, or your clones with `--clones`. Use their names or ids with `--voice` and `--voices`. |
| `voice changer` | Revoices one audio track or one talking video with a single voice, like the [Voice Changer](https://nodaro.ai/docs/nodes/audio/voice-changer) node. `voice change` is the same command. |
| `voice recast` | Revoices every speaker of a recording at once, like the [Voice Changer Pro](https://nodaro.ai/docs/nodes/audio/voice-changer-pro) node. `voice pro` is the same command. |
| `voice analyze` | Detects the speakers without recasting and prints the list with `--watch`. Nodaro Cloud only. |
| `voice export` | Renders the final video from a mixed set of tracks. Nodaro Cloud only. |
| `voice design` | Designs a new synthetic voice from a text description, like the [Voice Design](https://nodaro.ai/docs/nodes/audio/voice-design) node. |
| `voice remix` | Speaks a text in a described voice, without cloning, like the [Voice Remix](https://nodaro.ai/docs/nodes/audio/voice-remix) node. |
| `voice dub` | Dubs a recording into another language and keeps each speaker's voice, like the [Dubbing](https://nodaro.ai/docs/nodes/audio/dubbing) node. |
| `voice clones` | Lists and deletes voice clones made before cloning was retired. |

### Recast several speakers

`voice recast` runs on Nodaro Cloud. A self-hosted install runs it through its [connection to Nodaro Cloud](https://nodaro.ai/docs/self-hosting/cloud-connect).

- `--voices` maps voices to speakers in the order Nodaro detects them. The word `keep` keeps that speaker's original voice, as in `--voices Rachel,keep,Aria`.
- `--voices-json` takes the raw SDK array instead: voice ids, settings objects per voice, or `null` for a speaker who keeps the original voice.
- `--output stems` returns one dry track per speaker, for an interactive mix, instead of a finished video. Render the mix with `voice export`.
- `--analysis-file` reuses a saved `voice analyze` result, so the speakers are not detected again.

### The interactive recast flow

The one-step `voice recast` renders a finished video in a single call. The three-step flow lets you check the speakers first and mix the result before you render it:

```bash
# 1. Detect the speakers. Save the job's output_data for step 2.
nodaro voice analyze --video https://example.com/panel.mp4 --watch --json > analyze.json
jq .output_data analyze.json > analysis.json

# 2. Recast to dry stems, reusing the analysis (no second detection)
nodaro voice recast --video https://example.com/panel.mp4 --voices Rachel,keep,Aria \
  --analysis-file analysis.json --output stems --watch

# 3. Set the level and mute of each track, then render
nodaro voice export --source https://example.com/panel.mp4 --tracks-file mix.json \
  --voice-fx hall --voice-fx-mix 25 --watch
```

In step 3, each track in `mix.json` is an object with a `url`, a `gain` from 0 to 200, a `muted` flag and an optional `kind`, taken from the stems of step 2. The export copies the video stream unchanged; it is never encoded again.

## Media

```bash
nodaro media download <url> [--max-height <px>] [--section <a-b>] [--watch] [--json]
nodaro media metadata <url> [--json]
nodaro media trim-video --video <url> --start <sec> --end <sec>|--keep-first <sec>|--keep-last <sec> [--watch] [--poll-interval <ms>] [--json]
nodaro media trim-audio --video <url>|--audio <url> [--start <sec>] [--end <sec>] [--format mp3|wav|aac] [--watch] [--poll-interval <ms>] [--json]
nodaro media add-captions <videoUrl> [options, see below]
nodaro media still-to-video --image <url> --audio <url> [--motion none|zoom-in|zoom-out|pan-left|pan-right|ken-burns] [--intensity <1-10>] [--resolution 720p|1080p|4K] [--aspect-ratio <W:H>] [--fps 24|30] [--fit cover|contain] [--pad-color <hex>] [--watch] [--poll-interval <ms>] [--json]
nodaro media slideshow --images <url...> [--audio <url>] [--durations "10,auto,auto"] [--per-image <sec>] [--transition <id>] [--transition-duration <sec>] [--motion none|zoom-in|zoom-out|ken-burns|alternate] [--intensity <1-10>] [--resolution 720p|1080p|4K] [--aspect-ratio <W:H>] [--fps 24|30] [--fit cover|contain] [--pad-color <hex>] [--watch] [--json]
nodaro media collage <imageUrls...> [--sizes <0-3,...>] [--numbered] [--label <text>...] [--badge-position top-left|top-right] [--layout smart|grid] [--resolution 2K|4K] [--aspect-ratio <W:H>] [--gap <px>] [--background-color <hex>] [--watch] [--poll-interval <ms>] [--json]
nodaro media overlay <imageUrl> [layerUrls...] [--layers-file <path>] [--anchor <anchor>] [--x <%>] [--y <%>] [--width <%>] [--opacity <0-1>] [--platform <id>...] [--qr-text <text>] [--mask-mode none|layers|around|outside] [--mask-spread <px>] [--canvas <WxH>] [--base-fit contain|cover] [--background-color <hex>] [--output-format png|jpg|webp] [--watch] [--poll-interval <ms>] [--json]
nodaro media overlay-placement <imageUrl> [--intent <text>] [--aspect <ratio>] [--safe-area <x,y,w,h>] [--json]
nodaro media video-overlay <videoUrl> [layerUrls...] [--at <start[-end]>...] [--preset card|corner-badge|full-frame] [--corner top-left|top-right|bottom-left|bottom-right] [--layers-file <path>] [--aspect 16:9|9:16|1:1|4:5] [--base-fit cover|contain] [--background-color <hex>] [--watch] [--poll-interval <ms>] [--json]
nodaro media save <url> [--filename <name>] [--type image|video|audio] [--watch] [--poll-interval <ms>] [--json]
```

| Command | What it does |
| --- | --- |
| `media download` | Imports a video from YouTube, TikTok, Instagram, X or Facebook into your storage. `--section` fetches one time range, in seconds. `--watch` streams live progress, and there is no job to poll later. |
| `media metadata` | Reads the duration, dimensions and title of a media URL without downloading it. |
| `media trim-video` | Cuts a video by start and end time, or keeps its first or last seconds. |
| `media trim-audio` | Cuts the audio of a video or an audio file and saves it as MP3, WAV or AAC. |
| `media add-captions` | Burns captions into a video. See [Captions](#captions). |
| `media still-to-video` | Turns one still and one audio file into an MP4, for 0 credits. The video is as long as the audio, so there is no duration option. `--motion` animates the still. |
| `media slideshow` | Turns 2 to 100 images, with optional audio, into an MP4 slideshow, for 0 credits. |
| `media collage` | Composites 2 to 30 images into one large image. |
| `media overlay` | Places up to 12 layers on a base image, pixel-exact, without AI. |
| `media overlay-placement` | Asks a vision model where one layer should go. |
| `media video-overlay` | Places 1 to 20 timed image layers over a video, without AI, for 20 credits. |
| `media save` | Saves a media URL to your storage, as an image, a video or an audio file. |

### Slideshows

With audio, the audio sets the length of the slideshow. Durations you pinned with `--durations` are scaled in proportion, and the CLI tells you so. Without audio, the slideshow is silent and lasts the number of images times `--per-image`.

### Collages

- `--sizes` gives each image a relative size hint, in the order of the images: `0` automatic, `1` big (about twice as wide), `2` medium, `3` small (about half as wide). Size hints work with the smart layout only.
- `--numbered` stamps a sequence number, starting at 1, in a corner of each image, for storyboards.
- `--badge-position` sets that corner: `top-left`, the default, or `top-right`. It also places the labels.
- `--label` adds a caption after the number. Repeat it once per image, in order; an empty `""` skips one image.

### Image overlays

- Image URLs after the base image are image layers. They share `--anchor`, `--x`, `--y`, `--width` and `--opacity`, which suits a watermark.
- `--layers-file` takes the full JSON array of layers instead: options per layer, and the text, QR code and shape kinds.
- Placement is in percent of the base image, so one command fits a 1K preview and a 4K render.
- `--platform`, which you can repeat, also renders the composite at that platform's size. The base render costs 10 credits and each platform adds 2 credits. The job's output lists the extra renders as `variants`.
- `overlay-placement` answers in the same percent units: an anchor, `x`, `y`, `width` and a one-line reason. It answers at once, without a job to poll, and costs one image-to-text call.

### Video overlays

- Give one `--at` per image URL, in order. `3` means from 3 seconds to the end, and `1.2-2.6` means from 1.2 to 2.6 seconds.
- `--preset` and `--corner` apply to every image layer given as a URL.
- `--layers-file` takes the full layers array instead, with a box, opacity, animation and stacking order per layer.
- `--base-fit` and `--background-color` need `--aspect`.
- The audio of the base video is kept untouched.

See the [Video Overlay](https://nodaro.ai/docs/nodes/video/video-overlay) node for the layer options.

## Captions

```bash
nodaro media add-captions <videoUrl> [--text <text>] [--captions-file <file.json>] [--style subtitle|word-highlight|karaoke|tiktok-words|word-pop|bouncy] [--look outline|clean] [--position bottom|top|center] [--position-y <pct>] [--font-size <px>] [--font-family <name>] [--font-weight <100-900>] [--color <c>] [--background-color <c>] [--stroke-color <c>] [--stroke-width <px>] [--highlight-color <c>] [--uppercase|--no-uppercase] [--max-words-per-line <1-20>] [--animate|--no-animate] [--no-auto-transcribe] [--transcribe-provider elevenlabs-stt|incredibly-fast-whisper|whisper] [--segments-file <file.json>] [--watch] [--poll-interval <ms>] [--json]
```

`media add-captions` has two kinds of style, like the [Add Captions](https://nodaro.ai/docs/nodes/video/add-captions) node:

| Style | What it shows |
| --- | --- |
| `subtitle` | Static captions, without word animation. |
| `word-highlight`, `karaoke`, `tiktok-words`, `word-pop`, `bouncy` | Kinetic captions, animated word by word. `word-highlight`, `karaoke` and `bouncy` show one held line at a time. |

### The text of the captions

- On `subtitle`, `--text` is burned in as one static block for the whole video. It is never replaced by a transcription. Omit `--text` to caption the speech.
- On a kinetic style, `--text` is only the fallback when transcription returns nothing, or when you pass `--no-auto-transcribe`.
- `--captions-file` is a JSON array of word-timed entries, `[{ text, startMs, endMs }]`, one entry per word for the kinetic styles. The `words` of a `nodaro audio transcribe` result fit it as they are; pair the file with `--no-auto-transcribe`.
- `--segments-file` gives time ranges their own style, look and position. The ranges must not overlap.

### Styling

- The styling options also style a `subtitle`: `--look`, `--font-family`, `--font-weight`, `--stroke-color`, `--stroke-width`, `--uppercase`, `--position-y` and `--max-words-per-line`. A styled `subtitle` is billed at the kinetic price; a plain `subtitle` stays at the lower price.
- `--highlight-color` and `--animate` work on kinetic styles only. They are refused on `subtitle`.
- `--animate` is on by default. `--no-animate` stops the motion of each word, and keeps the grouping and the highlight color.
- Without `--look`, the kinetic styles render as `outline` and `subtitle` renders as `clean`.
- `--max-words-per-line` caps the number of words on one caption line, or on one page of `tiktok-words`, from 1 to 20. The frame width, sentence ends and pauses of 0.5 seconds or more also break lines. One or two words give a punchy, fast read; leave it unset to fill the width. On a `--text` subtitle, it only sets the line breaks, and it has no effect on `word-pop`.
- A kinetic or styled render keeps the frame rate of the source, as a whole number from 15 to 60 fps. A variable-frame-rate or very long source renders at 30 fps.

### Transcription engine

`--transcribe-provider` chooses the engine that transcribes the speech. A kinetic style needs word timings, from `incredibly-fast-whisper`, the default, or `elevenlabs-stt`. `subtitle` needs phrase timings only, so `whisper` also works there.

## Audio

```bash
nodaro audio separate --audio <url> [--mode vocal_instrumental|stems] [--quality auto|fast|best] [--watch] [--poll-interval <ms>] [--json]
nodaro audio isolate --audio <url> [--watch] [--poll-interval <ms>] [--json]
nodaro audio fx --audio <url> [--preset <preset>] [--mix <0-100>] [--delay <20-2000>] [--decay <0-1>] [--eq-low <db>] [--eq-high <db>] [--watch] [--poll-interval <ms>] [--json]
nodaro audio mix --audio <url> --audio <url> ... [--volumes <csv>] [--watch] [--poll-interval <ms>] [--json]
nodaro audio adjust-volume --audio <url>|--video <url> [--volume <0-200>] [--normalize] [--fade-in <sec>] [--fade-out <sec>] [--watch] [--poll-interval <ms>] [--json]
nodaro audio combine --segment <url[@a-b]> --segment ... [--watch] [--poll-interval <ms>] [--json]
nodaro audio transcribe --audio <url> [--provider elevenlabs-stt|incredibly-fast-whisper|whisper] [--language <code>] [--diarize] [--tag-audio-events] [--word-timestamps] [--watch] [--poll-interval <ms>] [--json]
```

| Command | What it does | Node |
| --- | --- | --- |
| `audio separate` | Splits vocals from the instrumental, or into stems. | [Audio Separation](https://nodaro.ai/docs/nodes/audio/audio-separation) |
| `audio isolate` | Keeps the voice and removes the rest. | [Voice Extractor](https://nodaro.ai/docs/nodes/audio/voice-extractor) |
| `audio fx` | Applies an effect preset, with mix, delay, decay and equalizer settings. | [Audio FX](https://nodaro.ai/docs/nodes/audio/audio-fx) |
| `audio mix` | Mixes several tracks, with one volume per track. | [Mix Audio](https://nodaro.ai/docs/nodes/audio/mix-audio) |
| `audio adjust-volume` | Changes the volume, normalizes, and fades in or out. | [Adjust Volume](https://nodaro.ai/docs/nodes/audio/adjust-volume) |
| `audio combine` | Joins segments one after another. `url@a-b` takes one time range of a file. | [Combine Audio](https://nodaro.ai/docs/nodes/audio/combine-audio) |
| `audio transcribe` | Turns speech into text. | [Transcribe](https://nodaro.ai/docs/nodes/audio/transcribe) |

These are the building blocks that Voice Changer Pro combines, available on their own.

### Transcription engines

| Engine | Word timings | Also supports |
| --- | --- | --- |
| `elevenlabs-stt` | Always | `--diarize` (who speaks when) and `--tag-audio-events` |
| `incredibly-fast-whisper` | With `--word-timestamps` | |
| `whisper` | None, phrase segments only; `--word-timestamps` is refused before any credits are spent | |

If you omit `--provider`, the `whisper` engine runs. Name an engine whenever you need word timings.

The completed job's `output_data` carries `text`, `words` (one entry per word, in milliseconds) and `json` (the normalized transcript, also in milliseconds). A top-level `segments` list, in seconds, exists only with `whisper` and `incredibly-fast-whisper`; `elevenlabs-stt` returns none, so read `words`. Pass `words` to `media add-captions --captions-file` for a kinetic render.

## Edit

The edit commands are editorial building blocks for podcasts and long videos.

```bash
nodaro edit silence-detect <audioUrl> [--threshold-db=-35] [--min-silence-ms <ms>] [--pad-ms <ms>] [--watch] [--poll-interval <ms>] [--json]
nodaro edit audio-sync (--source <[id=]url> ... | --sources-file <file.json>) [--reference <id>] [--watch] [--poll-interval <ms>] [--json]
nodaro edit apply-edl --edl <file.json> [--transcript <file.json>] [--source <url> ...] [--output video|audio] [--quality proxy|final] [--crossfade-ms <ms>] [--watch] [--poll-interval <ms>] [--json]
nodaro edit plan --mode tighten|clips|chapters --plan-tier economy|standard|premium --transcript <file.json> (--source <url[@audio|@video]> ... | --sources-file <file.json>) [--silence <file.json>] [--instructions <text>] [--style-guide <text>] [--count <n>] [--target-duration-sec <n>] [--target-aspect 16:9|9:16|1:1|4:5] [--platform <name>] [--watch] [--poll-interval <ms>] [--json]
```

| Command | What it does | Node |
| --- | --- | --- |
| `edit silence-detect` | Finds the silent passages of a recording. | [Silence Detect](https://nodaro.ai/docs/nodes/audio/silence-detect) |
| `edit audio-sync` | Aligns 2 to 6 recordings, audio or video, of the same event. | [Audio Sync](https://nodaro.ai/docs/nodes/audio/audio-sync) |
| `edit plan` | Plans an edit from a transcript: tighten the pace, cut clips or mark chapters. | [Edit Plan](https://nodaro.ai/docs/nodes/video/edit-plan) |
| `edit apply-edl` | Renders an edit decision list (EDL) as a video or an audio file. | [Apply EDL](https://nodaro.ai/docs/nodes/video/apply-edl) |

`edit audio-sync` names the recordings `source-1`, `source-2` and so on, unless you give an id as `id=url`. Its `output_data.json` holds three fields:

- `reference`: the recording the others are aligned to. Choose it with `--reference`.
- `offsets`: one entry per recording, with `sourceId`, `offsetMs`, `confidence` and `driftMsPerHour`.
- `notes`: remarks about the alignment.

A time in a recording converts to the reference with `referenceMs = sourceMs + offsetMs`.

## Frequently asked questions

### How do I recast several speakers in a video from the CLI?

Run nodaro voice recast with --video and --voices, one voice per speaker in the order they are detected. Write keep for a speaker who keeps the original voice, for example --voices Rachel,keep,Aria.

### Which transcription engine gives word timings?

elevenlabs-stt always returns word timings, and incredibly-fast-whisper returns them with --word-timestamps. whisper returns phrase segments only. If you omit --provider, the whisper engine runs, so name an engine whenever you need words.

### Do still-to-video and slideshow cost credits?

No. nodaro media still-to-video and nodaro media slideshow render the video without any AI model and cost 0 credits.

### How do I caption a video with words I corrected myself?

Transcribe the audio with a word-level engine, edit the words in the saved JSON file, then pass the file to nodaro media add-captions with --captions-file and --no-auto-transcribe.

### Which media commands need Nodaro Cloud?

voice analyze and voice export run on Nodaro Cloud only. voice recast runs on Nodaro Cloud, and a self-hosted install runs it through its connection to Nodaro Cloud.
