dvr 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dvr-0.1.0/.gitignore +70 -0
- dvr-0.1.0/CHANGELOG.md +28 -0
- dvr-0.1.0/LICENSE +21 -0
- dvr-0.1.0/PKG-INFO +174 -0
- dvr-0.1.0/README.md +128 -0
- dvr-0.1.0/dvr/__init__.py +55 -0
- dvr-0.1.0/dvr/__main__.py +8 -0
- dvr-0.1.0/dvr/_version.py +24 -0
- dvr-0.1.0/dvr/_wrap.py +68 -0
- dvr-0.1.0/dvr/audio.py +139 -0
- dvr-0.1.0/dvr/cli/__init__.py +6 -0
- dvr-0.1.0/dvr/cli/commands/__init__.py +1 -0
- dvr-0.1.0/dvr/cli/commands/apply.py +77 -0
- dvr-0.1.0/dvr/cli/commands/mcp.py +26 -0
- dvr-0.1.0/dvr/cli/commands/media.py +148 -0
- dvr-0.1.0/dvr/cli/commands/project.py +126 -0
- dvr-0.1.0/dvr/cli/commands/render.py +159 -0
- dvr-0.1.0/dvr/cli/commands/serve.py +88 -0
- dvr-0.1.0/dvr/cli/commands/timeline.py +104 -0
- dvr-0.1.0/dvr/cli/main.py +168 -0
- dvr-0.1.0/dvr/cli/output.py +142 -0
- dvr-0.1.0/dvr/color.py +331 -0
- dvr-0.1.0/dvr/connection.py +378 -0
- dvr-0.1.0/dvr/daemon.py +367 -0
- dvr-0.1.0/dvr/errors.py +140 -0
- dvr-0.1.0/dvr/gallery.py +150 -0
- dvr-0.1.0/dvr/interchange.py +147 -0
- dvr-0.1.0/dvr/mcp/__init__.py +20 -0
- dvr-0.1.0/dvr/mcp/server.py +397 -0
- dvr-0.1.0/dvr/media.py +603 -0
- dvr-0.1.0/dvr/project.py +286 -0
- dvr-0.1.0/dvr/py.typed +0 -0
- dvr-0.1.0/dvr/render.py +331 -0
- dvr-0.1.0/dvr/resolve.py +180 -0
- dvr-0.1.0/dvr/spec.py +323 -0
- dvr-0.1.0/dvr/timeline.py +762 -0
- dvr-0.1.0/pyproject.toml +152 -0
- dvr-0.1.0/tests/__init__.py +0 -0
- dvr-0.1.0/tests/test_errors.py +62 -0
- dvr-0.1.0/tests/test_imports.py +52 -0
- dvr-0.1.0/tests/test_output.py +53 -0
dvr-0.1.0/.gitignore
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
share/python-wheels/
|
|
20
|
+
*.egg-info/
|
|
21
|
+
.installed.cfg
|
|
22
|
+
*.egg
|
|
23
|
+
MANIFEST
|
|
24
|
+
|
|
25
|
+
# Virtual environments
|
|
26
|
+
.venv/
|
|
27
|
+
venv/
|
|
28
|
+
env/
|
|
29
|
+
ENV/
|
|
30
|
+
|
|
31
|
+
# Hatch / generated version file
|
|
32
|
+
dvr/_version.py
|
|
33
|
+
|
|
34
|
+
# Testing & coverage
|
|
35
|
+
.pytest_cache/
|
|
36
|
+
.coverage
|
|
37
|
+
.coverage.*
|
|
38
|
+
htmlcov/
|
|
39
|
+
.tox/
|
|
40
|
+
.nox/
|
|
41
|
+
coverage.xml
|
|
42
|
+
*.cover
|
|
43
|
+
.hypothesis/
|
|
44
|
+
|
|
45
|
+
# Type checking
|
|
46
|
+
.mypy_cache/
|
|
47
|
+
.ruff_cache/
|
|
48
|
+
.pyre/
|
|
49
|
+
.pytype/
|
|
50
|
+
|
|
51
|
+
# IDE
|
|
52
|
+
.idea/
|
|
53
|
+
.vscode/
|
|
54
|
+
*.swp
|
|
55
|
+
*.swo
|
|
56
|
+
*~
|
|
57
|
+
|
|
58
|
+
# OS
|
|
59
|
+
.DS_Store
|
|
60
|
+
Thumbs.db
|
|
61
|
+
|
|
62
|
+
# Project-local
|
|
63
|
+
*.log
|
|
64
|
+
.env
|
|
65
|
+
.env.local
|
|
66
|
+
scratch/
|
|
67
|
+
local/
|
|
68
|
+
|
|
69
|
+
# Docs
|
|
70
|
+
site/
|
dvr-0.1.0/CHANGELOG.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `dvr` are documented here.
|
|
4
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- Media domain: `MediaPool`, `Asset` / `MediaPoolItem`, `Bin`, `MediaStorage` with bins, import, relink, proxy linking, auto-sync
|
|
11
|
+
- Color domain: `ColorOps` (CDL, LUT export, magic mask, stabilization, smart reframe, versions), `NodeGraph`, `ColorGroup`
|
|
12
|
+
- Audio domain: voice isolation, channel mapping introspection, Fairlight presets, audio insertion
|
|
13
|
+
- Gallery domain: still albums, PowerGrade albums, import/export
|
|
14
|
+
- Fusion (per-clip): `ClipFusion` for add / load / import / export / rename / delete comps
|
|
15
|
+
- Takes: `Takes` for take/variant management on a clip
|
|
16
|
+
- Interchange: unified import/export covering 21 formats — AAF, EDL (+ CDL/SDL/missing), FCP7 XML, FCPXML 1.8/1.9/1.10, DRT, OTIO, CSV, TAB, ALE, ALE-CDL, Dolby Vision 2.9/4.0/5.1, HDR10 A/B
|
|
17
|
+
- Daemon: `dvr serve start/stop/status/methods` with newline-delimited JSON over a Unix socket
|
|
18
|
+
- MCP server: `dvr mcp serve` exposes the library as typed tools for LLM agents
|
|
19
|
+
- Declarative specs: `dvr plan` and `dvr apply` reconcile YAML/JSON specs against live state, with built-in HDR color presets
|
|
20
|
+
- CLI sub-apps for every domain: `dvr media`, `dvr serve`, `dvr mcp`, `dvr plan`, `dvr apply`
|
|
21
|
+
- Docs site: mkdocs-material with concept guides, CLI reference, library tour, daemon and MCP guides, declarative-spec walkthrough, auto-generated API reference
|
|
22
|
+
|
|
23
|
+
## [0.1.0] - 2026-04-24
|
|
24
|
+
|
|
25
|
+
### Added
|
|
26
|
+
- Initial scaffold: connection layer, error system, Resolve / Project / Timeline / Render core classes
|
|
27
|
+
- CLI entry point with structured output (JSON / table / YAML)
|
|
28
|
+
- Inspection-first object model
|
dvr-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 M Hadi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
dvr-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dvr
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The missing CLI and Python library for DaVinci Resolve. Declarative, scriptable, LLM-friendly.
|
|
5
|
+
Project-URL: Homepage, https://github.com/mhadifilms/dvr
|
|
6
|
+
Project-URL: Documentation, https://mhadifilms.github.io/dvr
|
|
7
|
+
Project-URL: Repository, https://github.com/mhadifilms/dvr
|
|
8
|
+
Project-URL: Issues, https://github.com/mhadifilms/dvr/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/mhadifilms/dvr/blob/main/CHANGELOG.md
|
|
10
|
+
Author-email: M Hadi <mhadifilms@gmail.com>
|
|
11
|
+
License: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: automation,cli,color-grading,davinci-resolve,edl,fcpxml,post-production,vfx,video-editing
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Environment :: Console
|
|
16
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: MacOS
|
|
19
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
20
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
26
|
+
Classifier: Topic :: Multimedia :: Video
|
|
27
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
28
|
+
Classifier: Typing :: Typed
|
|
29
|
+
Requires-Python: >=3.10
|
|
30
|
+
Requires-Dist: pyyaml>=6.0
|
|
31
|
+
Requires-Dist: rich>=13.7
|
|
32
|
+
Requires-Dist: typer>=0.12
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
35
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
38
|
+
Requires-Dist: types-pyyaml; extra == 'dev'
|
|
39
|
+
Provides-Extra: docs
|
|
40
|
+
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
|
|
41
|
+
Requires-Dist: mkdocs>=1.6; extra == 'docs'
|
|
42
|
+
Requires-Dist: mkdocstrings[python]>=0.25; extra == 'docs'
|
|
43
|
+
Provides-Extra: mcp
|
|
44
|
+
Requires-Dist: mcp>=1.0; extra == 'mcp'
|
|
45
|
+
Description-Content-Type: text/markdown
|
|
46
|
+
|
|
47
|
+
# dvr
|
|
48
|
+
|
|
49
|
+
**The missing CLI and Python library for DaVinci Resolve.**
|
|
50
|
+
|
|
51
|
+
Declarative. Scriptable. LLM-friendly. No more silent `None` returns.
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
pip install dvr
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
$ dvr timeline inspect
|
|
59
|
+
{
|
|
60
|
+
"name": "MyShow_207_R2",
|
|
61
|
+
"fps": 24.0,
|
|
62
|
+
"duration_frames": 86400,
|
|
63
|
+
"tracks": {
|
|
64
|
+
"video": [{"index": 1, "name": "V1", "clips": 1, "enabled": true}, ...],
|
|
65
|
+
"audio": [{"index": 1, "name": "A1", "clips": 4, "subtype": "stereo"}, ...]
|
|
66
|
+
},
|
|
67
|
+
"markers": [...],
|
|
68
|
+
"color": {"science": "DaVinci YRGB Color Managed v2", "input": "Rec.2020", ...}
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Why this exists
|
|
75
|
+
|
|
76
|
+
DaVinci Resolve has a powerful Python scripting API. It's also painful:
|
|
77
|
+
|
|
78
|
+
- **Silent failures everywhere.** `AddRenderJob()` returns `None` on success or failure — good luck.
|
|
79
|
+
- **String-keyed settings** with undocumented valid values.
|
|
80
|
+
- **No batch operators.** You loop everything.
|
|
81
|
+
- **macOS connection footguns.** Resolve binds to LAN IP; vanilla `scriptapp('Resolve')` returns `None`.
|
|
82
|
+
- **Chain navigation.** Every `.Get*()` can return `None`. One typo and you're traversing nothing.
|
|
83
|
+
- **20+ export formats** behind magic enum constants.
|
|
84
|
+
|
|
85
|
+
`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.
|
|
86
|
+
|
|
87
|
+
## Three ways to use it
|
|
88
|
+
|
|
89
|
+
### 1. Python library
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from dvr import Resolve
|
|
93
|
+
|
|
94
|
+
r = Resolve() # auto-connects, handles macOS LAN-IP quirk
|
|
95
|
+
|
|
96
|
+
with r.project.use("MyShow_207"):
|
|
97
|
+
tl = r.timeline.current
|
|
98
|
+
print(tl.inspect()) # one call, full state
|
|
99
|
+
|
|
100
|
+
# Query language operates on inspected state
|
|
101
|
+
bad = tl.clips.where(lambda c: c.duration < 12)
|
|
102
|
+
for clip in bad:
|
|
103
|
+
clip.add_marker(color="red", note="too short")
|
|
104
|
+
|
|
105
|
+
job = r.render.submit(preset="delivery")
|
|
106
|
+
job.wait() # blocks with progress
|
|
107
|
+
print(job.output_path)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 2. CLI
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
$ dvr project ensure MyShow_207 --color rec2020_pq_4000 --fps 24
|
|
114
|
+
$ dvr timeline inspect | jq '.tracks.video[].clips'
|
|
115
|
+
$ dvr render submit --preset delivery --wait --stream
|
|
116
|
+
{"job_id": "abc", "status": "rendering", "pct": 12, "eta_s": 240}
|
|
117
|
+
{"job_id": "abc", "status": "rendering", "pct": 24, "eta_s": 210}
|
|
118
|
+
{"job_id": "abc", "status": "complete", "output": "/path/out.mov"}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 3. MCP server (for LLM agents)
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
$ dvr mcp serve # exposes the library as MCP tools
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
LLM agents call typed tools directly — no shell parsing, no silent failures.
|
|
128
|
+
|
|
129
|
+
## Five things that make it fundamentally better than the raw API
|
|
130
|
+
|
|
131
|
+
1. **One `inspect()` call replaces ten API calls.** Full structured state in a single round-trip.
|
|
132
|
+
2. **Idempotent operations.** `project.ensure()`, `timeline.ensure()`, `bin.ensure()` — re-run anything safely.
|
|
133
|
+
3. **Decoded errors.** Every failure carries `cause`, `fix`, and `state`. No more `None`.
|
|
134
|
+
4. **Declarative specs.** `dvr apply project.dvr.yaml` reconciles state. `kubectl apply` for DaVinci.
|
|
135
|
+
5. **Persistent connection.** `dvr serve` keeps Resolve warm — sequential commands run in <100ms.
|
|
136
|
+
|
|
137
|
+
## Install
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
# stable
|
|
141
|
+
pip install dvr
|
|
142
|
+
|
|
143
|
+
# with MCP server for LLM agents
|
|
144
|
+
pip install "dvr[mcp]"
|
|
145
|
+
|
|
146
|
+
# from source
|
|
147
|
+
git clone https://github.com/mhadifilms/dvr
|
|
148
|
+
cd dvr
|
|
149
|
+
pip install -e ".[dev]"
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Requirements
|
|
153
|
+
|
|
154
|
+
- **Python 3.10+** (matches Resolve's embedded Python on current versions)
|
|
155
|
+
- **DaVinci Resolve 18.5+** (Studio or Free)
|
|
156
|
+
- **macOS, Windows, or Linux**
|
|
157
|
+
|
|
158
|
+
`dvr` auto-discovers Resolve's scripting library on each platform. No environment variables needed for typical installs.
|
|
159
|
+
|
|
160
|
+
## Status
|
|
161
|
+
|
|
162
|
+
Pre-1.0. The public API may change. See [CHANGELOG.md](CHANGELOG.md) for breaking changes.
|
|
163
|
+
|
|
164
|
+
## License
|
|
165
|
+
|
|
166
|
+
MIT — see [LICENSE](LICENSE).
|
|
167
|
+
|
|
168
|
+
## Contributing
|
|
169
|
+
|
|
170
|
+
Issues and pull requests welcome. The project's API surface is large; contributions covering edge cases on Windows / Linux are especially valuable. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup and conventions.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
> `dvr` is 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.
|
dvr-0.1.0/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# dvr
|
|
2
|
+
|
|
3
|
+
**The missing CLI and Python library for DaVinci Resolve.**
|
|
4
|
+
|
|
5
|
+
Declarative. Scriptable. LLM-friendly. No more silent `None` returns.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install dvr
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
$ dvr timeline inspect
|
|
13
|
+
{
|
|
14
|
+
"name": "MyShow_207_R2",
|
|
15
|
+
"fps": 24.0,
|
|
16
|
+
"duration_frames": 86400,
|
|
17
|
+
"tracks": {
|
|
18
|
+
"video": [{"index": 1, "name": "V1", "clips": 1, "enabled": true}, ...],
|
|
19
|
+
"audio": [{"index": 1, "name": "A1", "clips": 4, "subtype": "stereo"}, ...]
|
|
20
|
+
},
|
|
21
|
+
"markers": [...],
|
|
22
|
+
"color": {"science": "DaVinci YRGB Color Managed v2", "input": "Rec.2020", ...}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Why this exists
|
|
29
|
+
|
|
30
|
+
DaVinci Resolve has a powerful Python scripting API. It's also painful:
|
|
31
|
+
|
|
32
|
+
- **Silent failures everywhere.** `AddRenderJob()` returns `None` on success or failure — good luck.
|
|
33
|
+
- **String-keyed settings** with undocumented valid values.
|
|
34
|
+
- **No batch operators.** You loop everything.
|
|
35
|
+
- **macOS connection footguns.** Resolve binds to LAN IP; vanilla `scriptapp('Resolve')` returns `None`.
|
|
36
|
+
- **Chain navigation.** Every `.Get*()` can return `None`. One typo and you're traversing nothing.
|
|
37
|
+
- **20+ export formats** behind magic enum constants.
|
|
38
|
+
|
|
39
|
+
`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.
|
|
40
|
+
|
|
41
|
+
## Three ways to use it
|
|
42
|
+
|
|
43
|
+
### 1. Python library
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
from dvr import Resolve
|
|
47
|
+
|
|
48
|
+
r = Resolve() # auto-connects, handles macOS LAN-IP quirk
|
|
49
|
+
|
|
50
|
+
with r.project.use("MyShow_207"):
|
|
51
|
+
tl = r.timeline.current
|
|
52
|
+
print(tl.inspect()) # one call, full state
|
|
53
|
+
|
|
54
|
+
# Query language operates on inspected state
|
|
55
|
+
bad = tl.clips.where(lambda c: c.duration < 12)
|
|
56
|
+
for clip in bad:
|
|
57
|
+
clip.add_marker(color="red", note="too short")
|
|
58
|
+
|
|
59
|
+
job = r.render.submit(preset="delivery")
|
|
60
|
+
job.wait() # blocks with progress
|
|
61
|
+
print(job.output_path)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 2. CLI
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
$ dvr project ensure MyShow_207 --color rec2020_pq_4000 --fps 24
|
|
68
|
+
$ dvr timeline inspect | jq '.tracks.video[].clips'
|
|
69
|
+
$ dvr render submit --preset delivery --wait --stream
|
|
70
|
+
{"job_id": "abc", "status": "rendering", "pct": 12, "eta_s": 240}
|
|
71
|
+
{"job_id": "abc", "status": "rendering", "pct": 24, "eta_s": 210}
|
|
72
|
+
{"job_id": "abc", "status": "complete", "output": "/path/out.mov"}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 3. MCP server (for LLM agents)
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
$ dvr mcp serve # exposes the library as MCP tools
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
LLM agents call typed tools directly — no shell parsing, no silent failures.
|
|
82
|
+
|
|
83
|
+
## Five things that make it fundamentally better than the raw API
|
|
84
|
+
|
|
85
|
+
1. **One `inspect()` call replaces ten API calls.** Full structured state in a single round-trip.
|
|
86
|
+
2. **Idempotent operations.** `project.ensure()`, `timeline.ensure()`, `bin.ensure()` — re-run anything safely.
|
|
87
|
+
3. **Decoded errors.** Every failure carries `cause`, `fix`, and `state`. No more `None`.
|
|
88
|
+
4. **Declarative specs.** `dvr apply project.dvr.yaml` reconciles state. `kubectl apply` for DaVinci.
|
|
89
|
+
5. **Persistent connection.** `dvr serve` keeps Resolve warm — sequential commands run in <100ms.
|
|
90
|
+
|
|
91
|
+
## Install
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# stable
|
|
95
|
+
pip install dvr
|
|
96
|
+
|
|
97
|
+
# with MCP server for LLM agents
|
|
98
|
+
pip install "dvr[mcp]"
|
|
99
|
+
|
|
100
|
+
# from source
|
|
101
|
+
git clone https://github.com/mhadifilms/dvr
|
|
102
|
+
cd dvr
|
|
103
|
+
pip install -e ".[dev]"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Requirements
|
|
107
|
+
|
|
108
|
+
- **Python 3.10+** (matches Resolve's embedded Python on current versions)
|
|
109
|
+
- **DaVinci Resolve 18.5+** (Studio or Free)
|
|
110
|
+
- **macOS, Windows, or Linux**
|
|
111
|
+
|
|
112
|
+
`dvr` auto-discovers Resolve's scripting library on each platform. No environment variables needed for typical installs.
|
|
113
|
+
|
|
114
|
+
## Status
|
|
115
|
+
|
|
116
|
+
Pre-1.0. The public API may change. See [CHANGELOG.md](CHANGELOG.md) for breaking changes.
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
MIT — see [LICENSE](LICENSE).
|
|
121
|
+
|
|
122
|
+
## Contributing
|
|
123
|
+
|
|
124
|
+
Issues and pull requests welcome. The project's API surface is large; contributions covering edge cases on Windows / Linux are especially valuable. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup and conventions.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
> `dvr` is 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.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""dvr — the missing CLI and Python library for DaVinci Resolve.
|
|
2
|
+
|
|
3
|
+
This package exposes a small, stable public API. Internal modules are
|
|
4
|
+
prefixed with ``_`` and may change between releases. The two things you
|
|
5
|
+
almost always want are:
|
|
6
|
+
|
|
7
|
+
from dvr import Resolve, errors
|
|
8
|
+
|
|
9
|
+
Open a connection with ``r = Resolve()`` and navigate from there.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from . import audio, errors, gallery, interchange, spec
|
|
15
|
+
from .color import ColorGroup, ColorOps, NodeGraph
|
|
16
|
+
from .media import Asset, Bin, MediaPool, MediaPoolItem, MediaStorage
|
|
17
|
+
from .project import Project, ProjectNamespace
|
|
18
|
+
from .render import RenderJob, RenderNamespace
|
|
19
|
+
from .resolve import App, Resolve
|
|
20
|
+
from .timeline import Clip, ClipFusion, ClipQuery, Takes, Timeline, TimelineNamespace, Track
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
from ._version import __version__
|
|
24
|
+
except ImportError: # pragma: no cover - generated at build time
|
|
25
|
+
__version__ = "0.0.0+local"
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"App",
|
|
29
|
+
"Asset",
|
|
30
|
+
"Bin",
|
|
31
|
+
"Clip",
|
|
32
|
+
"ClipFusion",
|
|
33
|
+
"ClipQuery",
|
|
34
|
+
"ColorGroup",
|
|
35
|
+
"ColorOps",
|
|
36
|
+
"MediaPool",
|
|
37
|
+
"MediaPoolItem",
|
|
38
|
+
"MediaStorage",
|
|
39
|
+
"NodeGraph",
|
|
40
|
+
"Project",
|
|
41
|
+
"ProjectNamespace",
|
|
42
|
+
"RenderJob",
|
|
43
|
+
"RenderNamespace",
|
|
44
|
+
"Resolve",
|
|
45
|
+
"Takes",
|
|
46
|
+
"Timeline",
|
|
47
|
+
"TimelineNamespace",
|
|
48
|
+
"Track",
|
|
49
|
+
"__version__",
|
|
50
|
+
"audio",
|
|
51
|
+
"errors",
|
|
52
|
+
"gallery",
|
|
53
|
+
"interchange",
|
|
54
|
+
"spec",
|
|
55
|
+
]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '0.1.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 1, 0)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = None
|
dvr-0.1.0/dvr/_wrap.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Internal helpers shared by every domain wrapper.
|
|
2
|
+
|
|
3
|
+
The Resolve API is famously inconsistent: methods can return ``None`` for
|
|
4
|
+
"not found", "wrong page", "no current project", or genuine errors — with
|
|
5
|
+
no way to distinguish. The helpers here let domain wrappers collapse those
|
|
6
|
+
cases into a structured ``DvrError`` with a useful diagnosis.
|
|
7
|
+
|
|
8
|
+
Nothing here is part of the public API.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from collections.abc import Callable
|
|
14
|
+
from typing import Any, TypeVar
|
|
15
|
+
|
|
16
|
+
from . import errors
|
|
17
|
+
|
|
18
|
+
T = TypeVar("T")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def require(
|
|
22
|
+
value: T | None,
|
|
23
|
+
*,
|
|
24
|
+
error: type[errors.DvrError] = errors.DvrError,
|
|
25
|
+
message: str,
|
|
26
|
+
cause: str | None = None,
|
|
27
|
+
fix: str | None = None,
|
|
28
|
+
state: dict[str, Any] | None = None,
|
|
29
|
+
) -> T:
|
|
30
|
+
"""Assert ``value is not None`` or raise a structured error.
|
|
31
|
+
|
|
32
|
+
Use this around any raw API call that can return ``None`` to signal
|
|
33
|
+
failure. ``cause``/``fix``/``state`` flow into the resulting exception.
|
|
34
|
+
"""
|
|
35
|
+
if value is None:
|
|
36
|
+
raise error(message, cause=cause, fix=fix, state=state)
|
|
37
|
+
return value
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def safe_call(
|
|
41
|
+
fn: Callable[[], T],
|
|
42
|
+
*,
|
|
43
|
+
error: type[errors.DvrError] = errors.DvrError,
|
|
44
|
+
message: str,
|
|
45
|
+
cause: str | None = None,
|
|
46
|
+
fix: str | None = None,
|
|
47
|
+
state: dict[str, Any] | None = None,
|
|
48
|
+
) -> T:
|
|
49
|
+
"""Run a raw API call and translate exceptions into a ``DvrError``.
|
|
50
|
+
|
|
51
|
+
The Resolve API occasionally raises bare ``RuntimeError`` from C++.
|
|
52
|
+
Catch broadly and re-surface with diagnostic context.
|
|
53
|
+
"""
|
|
54
|
+
try:
|
|
55
|
+
result = fn()
|
|
56
|
+
except errors.DvrError:
|
|
57
|
+
raise
|
|
58
|
+
except Exception as exc:
|
|
59
|
+
raise error(
|
|
60
|
+
message,
|
|
61
|
+
cause=cause or f"underlying API raised {type(exc).__name__}: {exc}",
|
|
62
|
+
fix=fix,
|
|
63
|
+
state=state,
|
|
64
|
+
) from exc
|
|
65
|
+
return require(result, error=error, message=message, cause=cause, fix=fix, state=state)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
__all__ = ["require", "safe_call"]
|