Resumable mixed-media batches¶
A batch manifest runs maintained profiles through the same planner, preflight, executor, and receipt contracts used by one-off commands. Jobs can mix video, audio, subtitle, and archival work without embedding shell strings.
{
"schema_version": "1.1",
"policy": {
"max_workers": 2,
"max_retries": 1,
"max_input_bytes": "2GiB",
"per_job_timeout_seconds": 900
},
"jobs": [
{
"id": "web-video",
"profile": "web/mp4-compatible",
"input": "media/source.mov",
"output": "build/source.mp4"
},
{
"id": "podcast-audio",
"profile": "audio/podcast-speech",
"input": "media/episode.wav",
"output": "build/episode.m4a"
},
{
"id": "captioned-video",
"profile": "subtitles/accessibility",
"input": "media/lesson.mp4",
"output": "build/lesson-captioned.mp4",
"subtitle": "media/captions.srt",
"subtitle_language": "fra"
}
]
}
Paths are resolved relative to the manifest. Unknown fields, duplicate work,
duplicate IDs, case-insensitive output collisions, invalid profiles, and inputs
larger than the explicit resource limit fail before any job starts.
Accessibility-profile jobs require subtitle and accept optional
subtitle_language; omitted language retains the profile's und label.
Validate, preview, and run¶
pyffmpegcore batch validate batch.json --json
pyffmpegcore batch run batch.json --explain --plan-json
pyffmpegcore batch run batch.json \
--state .pyffmpegcore/batch-state.json \
--events .pyffmpegcore/batch-events.jsonl \
--receipt-dir .pyffmpegcore/receipts \
--result-json
max_workers is a hard concurrency bound from 1 to 32. max_input_bytes limits
each local input; it accepts an integer or a documented size such as 2GiB.
per_job_timeout_seconds applies the normal cancellation and cleanup policy to
every job. BatchRunner.run(..., policy=...) also applies this override to
direct Python API jobs; when it is unset, each plan keeps its own timeout.
The result keeps manifest order even when jobs finish out of order. Exit code
0 means every item succeeded, 6 means stable partial success, and the normal
environment, validation, and runtime categories apply when no item succeeds.
Events and receipts¶
--events writes one privacy-redacted JSON object per line. Each 1.0 event
has a monotonic sequence, job ID, attempt, and one of these states:
queuedstartedretryingsucceededfailedcancelledresumed
--receipt-dir writes one redacted run receipt for every executed item,
including deterministic failures. Content hashing remains opt-in with
--hash-content. Existing receipt files are preserved by default; use
--force or --resume to authorize replacement. The Python API accepts
overwrite_receipts=True. Receipt destinations that collide with media
outputs are rejected before jobs start.
State, event log, per-job receipts, and media outputs must use distinct paths;
the CLI rejects collisions before opening the event log.
Retry and resume safety¶
Retries are disabled by default. When enabled, only an explicit runtime transport or temporarily-unavailable diagnostic is retryable. Validation, unsupported capabilities, bad media, collisions, and missing executables are never retried blindly.
Pass --state FILE on the first run to persist successful job signatures
atomically. After interruption, add --resume: a job is skipped only when its
ID and exact plan signature match and every expected output still exists.
Changed plans or deleted outputs run again. The state stores signatures rather
than private paths. State destinations that collide with a media output or
generated receipt are rejected before jobs start, including through the
Python API. A fresh state path is claimed exclusively before the first job
starts, so a concurrent default run fails rather than replacing it. Existing
state files are preserved by default; use --force,
--resume, or overwrite_state=True in the Python API to replace or continue
one.
The complete schema and example are published under JSON schemas.