dvr¶
The missing CLI and Python library for DaVinci Resolve.
Declarative. Scriptable. LLM-friendly. No more silent None returns.
$ dvr timeline inspect
{
"name": "Edit_v2",
"fps": 24.0,
"duration_frames": 86400,
"tracks": {
"video": [{"index": 1, "name": "V1", "clips": 1, "enabled": true}, ...],
"audio": [{"index": 1, "name": "A1", "clips": 4, "subtype": "stereo"}, ...]
},
"marker_count": 12
}
Why dvr exists¶
DaVinci Resolve has a powerful Python scripting API. It's also painful:
- Silent failures everywhere.
AddRenderJob()returnsNoneon success or failure — good luck. - String-keyed settings with undocumented valid values.
- No batch operators. You loop everything.
- macOS connection footguns. Resolve binds to LAN IP; vanilla
scriptapp('Resolve')returnsNone. - Chain navigation. Every
.Get*()call can returnNone. One typo and you're traversing nothing. - 20+ export formats behind magic enum constants.
dvr wraps the API with a clean object model, idempotent operations, decoded errors, structured I/O, and a CLI that's pleasant for humans and parseable by LLM agents.
Three ways to use it¶
from dvr import Resolve
r = Resolve() # auto-connects, handles macOS LAN-IP quirk
with r.project.use("MyShow"):
tl = r.timeline.current
print(tl.inspect()) # one call, full state
bad = tl.clips().where(lambda c: c.duration < 12)
for clip in bad:
clip.add_marker(color="red", note="too short")
job = r.render.submit(target_dir="/Volumes/out", preset="delivery")
job.wait() # blocks with progress
print(job.output_path)
dvr project ensure MyShow
dvr timeline inspect | jq '.tracks.video[].clips'
dvr render submit --target-dir /Volumes/out --preset delivery --wait --stream
# newline-delimited JSON status events:
# {"job_id": "abc", "status": "rendering", "pct": 12, "eta_s": 240}
# {"job_id": "abc", "status": "complete", "output_path": "/Volumes/out/MyShow.mov"}
Five things that make it fundamentally better than the raw API¶
- One
inspect()call replaces ten API calls. Full structured state in a single round-trip. - Idempotent operations.
project.ensure(),timeline.ensure(),bin.ensure()— re-run anything safely. - Decoded errors. Every failure carries
cause,fix, andstate. No moreNone. - Declarative specs.
dvr apply project.dvr.yamlreconciles state. kubectl apply for DaVinci. - Persistent connection.
dvr servekeeps Resolve warm — sequential commands run in <100 ms.
Requirements¶
- Python 3.10+
- DaVinci Resolve Studio 18.5+ — external scripting is a Studio-only feature. Blackmagic sells Studio as a $295 perpetual license or through Blackmagic Cloud at $30/month per seat. The free edition of Resolve cannot be scripted from outside the app (restricted in v19.1+).
- macOS, Windows, or Linux
Status¶
Stable from 1.0. Breaking changes ship with a deprecation cycle and a major version bump; new features land as minor releases. See the CHANGELOG.
License¶
MIT — see the LICENSE.
dvris an independent open-source project. It is not affiliated with, endorsed by, or sponsored by Blackmagic Design. "DaVinci" and "DaVinci Resolve" are trademarks of Blackmagic Design Pty Ltd.