davinci-resolve-mcp 2.57.1 → 2.57.3
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.
- package/AGENTS.md +4 -0
- package/CHANGELOG.md +43 -0
- package/README.md +1 -1
- package/docs/process/release-process.md +6 -0
- package/docs/reference/api-coverage.md +6 -0
- package/docs/reference/api-limitations.md +208 -0
- package/install.py +1 -1
- package/package.json +1 -1
- package/scripts/gen_api_limitations.py +137 -0
- package/src/granular/common.py +1 -1
- package/src/server.py +1 -1
- package/src/utils/api_truth.py +194 -0
package/AGENTS.md
CHANGED
|
@@ -69,6 +69,10 @@ semantics.
|
|
|
69
69
|
- Release checklist and validation rules: `docs/process/release-process.md`
|
|
70
70
|
- Kernel workflow support maps: `docs/kernels/`
|
|
71
71
|
- API coverage and live-test status: `docs/reference/api-coverage.md`
|
|
72
|
+
- Blackmagic-facing API gaps/bugs (generated from `api_truth`):
|
|
73
|
+
`docs/reference/api-limitations.md` — when you document a new Resolve API
|
|
74
|
+
limitation, add a `submit`-tagged entry to `src/utils/api_truth.py` and
|
|
75
|
+
regenerate with `scripts/gen_api_limitations.py` (a drift guard enforces it)
|
|
72
76
|
- Bundled Resolve API text: `docs/reference/resolve_scripting_api.txt`
|
|
73
77
|
|
|
74
78
|
## Key Paths
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,49 @@
|
|
|
2
2
|
|
|
3
3
|
Release history for the DaVinci Resolve MCP Server. The latest release is summarized in the root README; older entries live here to keep the README focused.
|
|
4
4
|
|
|
5
|
+
## What's New in v2.57.3
|
|
6
|
+
|
|
7
|
+
Expanded the API-limitations catalogue with a live surface audit.
|
|
8
|
+
|
|
9
|
+
- **Added** 8 newly-catalogued **missing capabilities** to
|
|
10
|
+
`docs/reference/api-limitations.md`, found by a `dir()` audit of the live
|
|
11
|
+
Resolve 21.0.0 API objects diffed against the UI feature set: timeline-item
|
|
12
|
+
trim/move/re-time (getters only, no setters), razor/blade/split, clip
|
|
13
|
+
speed/retime ratio & ramps, color node-graph editing + primary grade values,
|
|
14
|
+
Fairlight audio levels/pan/EQ/automation/FairlightFX, proxy/optimized-media
|
|
15
|
+
generation, insert/overwrite/replace/fit-to-fill edit modes, and Smart/Power
|
|
16
|
+
Bin creation. The report now lists 14 missing capabilities + 9 bugs.
|
|
17
|
+
- **Verified** the four previously-doc-derived entries (per-clip audio
|
|
18
|
+
stereo↔mono, native multicam creation, transitions, cloud list/export/user)
|
|
19
|
+
against the live API surface; all confirmed absent.
|
|
20
|
+
- **Changed** the generated report to carry an explicit **Scope & completeness**
|
|
21
|
+
note — it is not guaranteed exhaustive (surface audit + incident log; misses
|
|
22
|
+
parameters that exist-but-misbehave and untested capabilities).
|
|
23
|
+
|
|
24
|
+
## What's New in v2.57.2
|
|
25
|
+
|
|
26
|
+
Consolidated, submittable list of Resolve scripting-API limitations.
|
|
27
|
+
|
|
28
|
+
- **Added** `docs/reference/api-limitations.md` — a curated, behaviorally-verified
|
|
29
|
+
catalogue of Resolve scripting-API gaps and bugs, split into **Missing
|
|
30
|
+
Capabilities** (please add) and **Bugs / Unreliable Behavior** (please fix),
|
|
31
|
+
formatted for submission to Blackmagic Design's developer feedback. First cut:
|
|
32
|
+
6 missing capabilities (Source Track Selector / insert `trackIndex`, per-clip
|
|
33
|
+
audio stereo↔mono, native multicam-clip creation, transition create/copy,
|
|
34
|
+
`GetTimelineByName`, cloud project list/export/user management) and 9
|
|
35
|
+
bugs/unreliable behaviors (enum-key silent failures in `AutoSyncAudio`,
|
|
36
|
+
`CreateSubtitlesFromAudio`, CloudProject family, and `Timeline.Export`; flaky
|
|
37
|
+
`DeleteProject`; `Composition.Paste` bridge failure; `FlowView` unreliable
|
|
38
|
+
returns; truncated `Transcription` property; automation-blocking `CreateProject`
|
|
39
|
+
modal).
|
|
40
|
+
- **Added** `scripts/gen_api_limitations.py` — the report is generated from the
|
|
41
|
+
`submit`-tagged entries in the `api_truth` ledger (single source of truth, also
|
|
42
|
+
queryable at runtime via `resolve_control api_truth`), so it never drifts.
|
|
43
|
+
- **Changed** the release process and CI to keep it current: a new
|
|
44
|
+
`tests.test_api_limitations_doc` drift guard (added to the publish workflow)
|
|
45
|
+
fails if the doc is stale, and `docs/process/release-process.md` now requires
|
|
46
|
+
regenerating it whenever a `submit`-tagged entry changes.
|
|
47
|
+
|
|
5
48
|
## What's New in v2.57.1
|
|
6
49
|
|
|
7
50
|
Investigation outcome for community feature request #74 — no behavior change.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# DaVinci Resolve MCP Server
|
|
2
2
|
|
|
3
|
-
[](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
|
|
4
4
|
[](https://www.npmjs.com/package/davinci-resolve-mcp)
|
|
5
5
|
[](docs/reference/api-coverage.md)
|
|
6
6
|
[-blue.svg)](#server-modes)
|
|
@@ -29,6 +29,11 @@ Every release bump must update all version surfaces:
|
|
|
29
29
|
- README version badge
|
|
30
30
|
- README current stats or latest-release summary when they changed
|
|
31
31
|
- `CHANGELOG.md` latest release entry
|
|
32
|
+
- `docs/reference/api-limitations.md` when any `submit`-tagged entry in
|
|
33
|
+
`src/utils/api_truth.py` was added or changed (a newly documented Resolve API
|
|
34
|
+
gap/bug, a closed won't-fix issue, etc.). Regenerate it — do not hand-edit:
|
|
35
|
+
`venv/bin/python scripts/gen_api_limitations.py`. The
|
|
36
|
+
`tests.test_api_limitations_doc` drift guard fails the suite if it is stale.
|
|
32
37
|
- `docs/SKILL.md` when tool discovery, examples, or behavior changed
|
|
33
38
|
- `docs/guides/control-panel.md` when the control panel UI changed, plus
|
|
34
39
|
regenerated screenshots: start the panel against a project with analysis
|
|
@@ -48,6 +53,7 @@ Always run static checks before release:
|
|
|
48
53
|
```bash
|
|
49
54
|
venv/bin/python tests/test_import.py
|
|
50
55
|
venv/bin/python scripts/audit_api_parity.py
|
|
56
|
+
venv/bin/python scripts/gen_api_limitations.py --check
|
|
51
57
|
venv/bin/python -m unittest tests.test_static_undefined_names tests.test_action_list_drift tests.test_panel_docs_drift
|
|
52
58
|
node bin/davinci-resolve-mcp.mjs --help
|
|
53
59
|
node bin/davinci-resolve-mcp.mjs --version
|
|
@@ -57,6 +57,12 @@ a track via `MediaPool.AppendToTimeline`'s clipInfo `trackIndex` (exposed as
|
|
|
57
57
|
in the verified `api_truth` ledger (query `resolve_control api_truth "track"`);
|
|
58
58
|
see issue #74.
|
|
59
59
|
|
|
60
|
+
The full catalogue of verified scripting-API gaps and bugs — curated for
|
|
61
|
+
submission to Blackmagic Design's developer feedback — lives in
|
|
62
|
+
[api-limitations.md](api-limitations.md). It is generated from the `submit`-tagged
|
|
63
|
+
`api_truth` entries (`scripts/gen_api_limitations.py`) and kept in sync by a drift
|
|
64
|
+
guard, so it never goes stale.
|
|
65
|
+
|
|
60
66
|
| Class | Methods | Tools | Description |
|
|
61
67
|
|-------|---------|-------|-------------|
|
|
62
68
|
| Resolve | 22 | 22 | App control, pages, layout presets, render/burn-in presets, keyframe mode |
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# DaVinci Resolve Scripting API — Limitations & Feedback
|
|
2
|
+
|
|
3
|
+
<!-- GENERATED FILE — do not edit by hand.
|
|
4
|
+
Source: src/utils/api_truth.py (entries tagged `submit`).
|
|
5
|
+
Regenerate: venv/bin/python scripts/gen_api_limitations.py -->
|
|
6
|
+
|
|
7
|
+
This is a curated, behaviorally-verified list of DaVinci Resolve scripting
|
|
8
|
+
API gaps and bugs encountered while building this MCP server, intended for
|
|
9
|
+
submission to Blackmagic Design's developer feedback. Every item was
|
|
10
|
+
observed against live Resolve; each entry notes the current workaround (or
|
|
11
|
+
that none exists).
|
|
12
|
+
|
|
13
|
+
**Verified on:** DaVinci Resolve Studio 21.0.0
|
|
14
|
+
|
|
15
|
+
**Totals:** 14 missing capabilities, 9 bugs / unreliable behaviors.
|
|
16
|
+
|
|
17
|
+
The authoritative source is the runtime-queryable `api_truth` ledger
|
|
18
|
+
(`resolve_control api_truth "<query>"`); this document is generated from
|
|
19
|
+
it and stays in sync via a drift guard.
|
|
20
|
+
|
|
21
|
+
### Scope & completeness
|
|
22
|
+
|
|
23
|
+
This list is **not guaranteed exhaustive.** It combines (a) issues hit
|
|
24
|
+
while building this MCP server and (b) a `dir()` surface audit of the live
|
|
25
|
+
Resolve API objects (ProjectManager, Project, MediaPool, MediaPoolItem,
|
|
26
|
+
Timeline, TimelineItem, Graph) diffed against Resolve's UI feature set.
|
|
27
|
+
That catches absent methods and documented constraints, but not subtler
|
|
28
|
+
issues: parameters that exist yet misbehave, version-specific regressions,
|
|
29
|
+
or capabilities we simply never exercised. New findings are added as
|
|
30
|
+
`submit`-tagged `api_truth` entries and this document is regenerated.
|
|
31
|
+
|
|
32
|
+
## Missing Capabilities (please add)
|
|
33
|
+
|
|
34
|
+
Functionality that exists in the Resolve UI but has no scripting API
|
|
35
|
+
equivalent, blocking full automation.
|
|
36
|
+
|
|
37
|
+
### Timeline.GetTimelineByName
|
|
38
|
+
|
|
39
|
+
- **Object:** `Project`
|
|
40
|
+
- **Behavior:** Does not exist. Timelines are looked up by index.
|
|
41
|
+
- **Workaround / current handling:** Iterate GetTimelineByIndex(1..GetTimelineCount()).
|
|
42
|
+
- **Tags:** missing-method, timeline
|
|
43
|
+
|
|
44
|
+
### Source Track Selector / destination track for Insert*IntoTimeline
|
|
45
|
+
|
|
46
|
+
- **Object:** `Timeline`
|
|
47
|
+
- **Behavior:** There is no API to read or set the Source/Auto Track Selector (the Edit-page patch panel that picks the destination track). InsertTitleIntoTimeline, InsertFusionTitleIntoTimeline, InsertGeneratorIntoTimeline, InsertFusionGeneratorIntoTimeline, InsertOFXGeneratorIntoTimeline and InsertFusionCompositionIntoTimeline take no trackIndex and always drop the clip on the selector's current target (V1 in practice). Locking lower video tracks does NOT redirect the insert — verified live on 21.0.0: locking V1 makes the insert FAIL rather than land on V2. Titles/generators also can't be moved afterward (no MediaPoolItem, so AppendToTimeline clipInfo and MoveClips don't apply).
|
|
48
|
+
- **Workaround / current handling:** Accept the limitation for titles/generators (insert lands on V1). For clips that DO have a MediaPoolItem, target a track with MediaPool.AppendToTimeline's clipInfo 'trackIndex' instead (exposed as media_pool append_to_timeline clip_infos). See issue #74.
|
|
49
|
+
- **Reference:** [issue #74](https://github.com/samuelgursky/davinci-resolve-mcp/issues/74)
|
|
50
|
+
- **Tags:** missing-method, timeline, title, generator, track
|
|
51
|
+
|
|
52
|
+
### Per-clip audio channel-format conversion (Stereo<->Mono)
|
|
53
|
+
|
|
54
|
+
- **Object:** `MediaPoolItem / TimelineItem`
|
|
55
|
+
- **Behavior:** No scripting method converts an individual clip's audio channel format. ConvertTimelineToStereo is timeline-wide, and CreateStereoClip builds a 3D *visual* stereoscopic clip, not an audio mono->stereo change. The Edit-page 'Clip Attributes > Audio' channel mapping is UI-only.
|
|
56
|
+
- **Workaround / current handling:** Use the supported surface: timeline add_track with audioType (create mono/stereo tracks), get_track_sub_type (query format), convert_to_stereo (timeline-wide), and timeline_item get_source_audio_channel_mapping. Per-clip conversion is not possible. See issue #73.
|
|
57
|
+
- **Reference:** [issue #73](https://github.com/samuelgursky/davinci-resolve-mcp/issues/73)
|
|
58
|
+
- **Tags:** missing-method, audio, channel
|
|
59
|
+
|
|
60
|
+
### Native multicam clip creation
|
|
61
|
+
|
|
62
|
+
- **Object:** `MediaPool`
|
|
63
|
+
- **Behavior:** There is no method to create a native multicam clip from a set of angles. Angles can be stacked onto tracks programmatically, but the multicam-clip conversion is a UI-only step.
|
|
64
|
+
- **Workaround / current handling:** Prepare a stacked timeline (media_pool setup_multicam_timeline) and finish the multicam-clip conversion in the Resolve UI.
|
|
65
|
+
- **Tags:** missing-method, media-pool, multicam
|
|
66
|
+
|
|
67
|
+
### Transition create / copy / clone
|
|
68
|
+
|
|
69
|
+
- **Object:** `Timeline / TimelineItem`
|
|
70
|
+
- **Behavior:** The scripting API exposes no method to add, read, copy, or clone an edit transition (cross-dissolve, etc.). Transitions applied in the UI are invisible to and unmodifiable by scripts.
|
|
71
|
+
- **Workaround / current handling:** Apply/duplicate transitions in the Resolve UI; no scripted equivalent exists.
|
|
72
|
+
- **Tags:** missing-method, timeline, transition
|
|
73
|
+
|
|
74
|
+
### Cloud project enumeration / export / user management
|
|
75
|
+
|
|
76
|
+
- **Object:** `ProjectManager`
|
|
77
|
+
- **Behavior:** Only CreateCloudProject, LoadCloudProject, ImportCloudProject and RestoreCloudProject exist. There is no GetCloudProjectList (list available cloud projects), no ExportToCloud, and no Add/RemoveUserToCloudProject — so cloud collaboration can't be fully automated.
|
|
78
|
+
- **Workaround / current handling:** Drive cloud project listing, export, and collaborator management from the Resolve UI; only create/load/import/restore are scriptable.
|
|
79
|
+
- **Tags:** missing-method, project, cloud
|
|
80
|
+
|
|
81
|
+
### TimelineItem trim / move / re-time (no position setters)
|
|
82
|
+
|
|
83
|
+
- **Object:** `TimelineItem`
|
|
84
|
+
- **Behavior:** TimelineItem exposes GetStart, GetEnd, GetDuration, GetLeftOffset, GetRightOffset and GetSourceStart/EndFrame, but NO matching setters. A clip cannot be trimmed, slipped, slid, rolled, moved to another time/track, or have its duration changed once it is on the timeline. Verified via dir() on Resolve 21.0.0 (getters only).
|
|
85
|
+
- **Workaround / current handling:** Do edit-point adjustments in the Resolve UI, or rebuild the timeline from MediaPool.AppendToTimeline clipInfos with the desired startFrame/endFrame/recordFrame.
|
|
86
|
+
- **Tags:** missing-method, timeline, edit, trim
|
|
87
|
+
|
|
88
|
+
### Razor / blade / split a timeline item
|
|
89
|
+
|
|
90
|
+
- **Object:** `Timeline / TimelineItem`
|
|
91
|
+
- **Behavior:** There is no method to split/cut/blade a clip at a given frame. Verified absent on Timeline and TimelineItem (dir(), 21.0.0).
|
|
92
|
+
- **Workaround / current handling:** Split in the Resolve UI, or construct the cut up-front by appending two clipInfos with the desired in/out points.
|
|
93
|
+
- **Tags:** missing-method, timeline, edit
|
|
94
|
+
|
|
95
|
+
### Clip speed / retime ratio and speed ramps
|
|
96
|
+
|
|
97
|
+
- **Object:** `TimelineItem`
|
|
98
|
+
- **Behavior:** SetProperty exposes only retime *quality* (RetimeProcess, MotionEstimation) and transform/crop/composite/opacity keys — not the speed value itself. There is no way to set a clip to a given % speed, reverse it, or author a speed ramp. Verified against the documented SetProperty key list (21.0.0).
|
|
99
|
+
- **Workaround / current handling:** Set clip speed/retime in the Resolve UI; no scripted equivalent exists.
|
|
100
|
+
- **Tags:** missing-method, timeline, retime, speed
|
|
101
|
+
|
|
102
|
+
### Color node graph editing and primary grade values
|
|
103
|
+
|
|
104
|
+
- **Object:** `Graph / TimelineItem`
|
|
105
|
+
- **Behavior:** The Graph object exposes node enable/label/count, LUT get/set, cache mode, ResetAllGrades, ApplyGradeFromDRX and ApplyArriCdlLut; TimelineItem adds SetCDL, CopyGrades and color versions. But you cannot add, delete, or connect nodes, and you cannot read or write primary grade values (lift/gamma/gain/offset/contrast/curves/qualifiers/power windows). Grading is limited to CDL, whole-grade DRX/LUT application and copying.
|
|
106
|
+
- **Workaround / current handling:** Build node trees and dial grades in the Resolve UI or via DRX/CDL/LUT import; per-parameter grade control is not scriptable.
|
|
107
|
+
- **Tags:** missing-method, color, grade, node
|
|
108
|
+
|
|
109
|
+
### Fairlight audio levels / pan / EQ / automation / FairlightFX
|
|
110
|
+
|
|
111
|
+
- **Object:** `TimelineItem / Timeline`
|
|
112
|
+
- **Behavior:** There is no API to set clip or track volume, pan, EQ, audio automation, or to add/configure FairlightFX. SetProperty covers video transform only; the audio surface is read-only (GetSourceAudioChannelMapping, GetAudioMapping, voice isolation). Verified via dir() + SetProperty docs (21.0.0).
|
|
113
|
+
- **Workaround / current handling:** Mix in the Fairlight UI; only voice-isolation state and channel-mapping reads are scriptable.
|
|
114
|
+
- **Tags:** missing-method, audio, fairlight
|
|
115
|
+
|
|
116
|
+
### Proxy / optimized-media generation
|
|
117
|
+
|
|
118
|
+
- **Object:** `MediaPoolItem`
|
|
119
|
+
- **Behavior:** Only LinkProxyMedia, UnlinkProxyMedia and LinkFullResolutionMedia exist (attach/detach EXISTING proxies). There is no method to generate proxies or optimized media. Verified via MediaPoolItem dir() (21.0.0).
|
|
120
|
+
- **Workaround / current handling:** Trigger proxy/optimized-media generation from the Resolve UI; scripting can only link/unlink already-rendered proxies.
|
|
121
|
+
- **Tags:** missing-method, media-pool, proxy
|
|
122
|
+
|
|
123
|
+
### Insert / Overwrite / Replace / Fit-to-Fill edit modes
|
|
124
|
+
|
|
125
|
+
- **Object:** `MediaPool / Timeline`
|
|
126
|
+
- **Behavior:** MediaPool.AppendToTimeline (with optional recordFrame positioning) is the only programmatic placement. The standard edit modes — insert (ripple), overwrite, replace, fit-to-fill, place-on-top — have no API. Verified via dir() (21.0.0).
|
|
127
|
+
- **Workaround / current handling:** Position clips with AppendToTimeline clipInfo recordFrame, or perform insert/overwrite/replace edits in the Resolve UI.
|
|
128
|
+
- **Tags:** missing-method, timeline, edit
|
|
129
|
+
|
|
130
|
+
### Smart Bins / Power Bins creation
|
|
131
|
+
|
|
132
|
+
- **Object:** `MediaPool`
|
|
133
|
+
- **Behavior:** Only AddSubFolder (a regular bin) exists. Smart Bins (rule-based) and Power Bins (cross-project) cannot be created or configured. Verified via MediaPool dir() (21.0.0).
|
|
134
|
+
- **Workaround / current handling:** Create Smart/Power Bins in the Resolve UI; only regular bins are scriptable.
|
|
135
|
+
- **Tags:** missing-method, media-pool, bins
|
|
136
|
+
|
|
137
|
+
## Bugs / Unreliable Behavior (please fix)
|
|
138
|
+
|
|
139
|
+
Methods that exist but misbehave — silent failures, unreliable return
|
|
140
|
+
values, or automation-hostile modal prompts.
|
|
141
|
+
|
|
142
|
+
### MediaPool.AutoSyncAudio
|
|
143
|
+
|
|
144
|
+
- **Object:** `MediaPool`
|
|
145
|
+
- **Signature:** `(clips, settings) -> bool`
|
|
146
|
+
- **Behavior:** The boolean return does not reflect whether clips actually linked, and string enum keys in `settings` are silently rejected (the call returns False).
|
|
147
|
+
- **Workaround / current handling:** Resolve the AUDIO_SYNC_* enum constants via the live resolve handle, and verify by reading each clip's 'Synced Audio' property (see verify_by_readback).
|
|
148
|
+
- **Tags:** unreliable-return, silent-failure, audio, enum
|
|
149
|
+
|
|
150
|
+
### Timeline.CreateSubtitlesFromAudio
|
|
151
|
+
|
|
152
|
+
- **Object:** `Timeline`
|
|
153
|
+
- **Signature:** `(autoCaptionSettings) -> bool`
|
|
154
|
+
- **Behavior:** Same failure mode as AutoSyncAudio: the autoCaptionSettings dict is keyed by resolve.SUBTITLE_* enum constants with resolve.AUTO_CAPTION_* enum values, so plain string keys like {'language': 'korean'} are silently rejected (returns False, no subtitle track created). The boolean is also unreliable.
|
|
155
|
+
- **Workaround / current handling:** Resolve the SUBTITLE_*/AUTO_CAPTION_* constants via the live resolve handle (server._normalize_auto_caption_settings) and verify by reading the timeline's subtitle track count before/after (server._safe_create_subtitles).
|
|
156
|
+
- **Tags:** unreliable-return, silent-failure, subtitle, enum
|
|
157
|
+
|
|
158
|
+
### ProjectManager CloudProject family (Create/Load/Import/RestoreCloudProject)
|
|
159
|
+
|
|
160
|
+
- **Object:** `ProjectManager`
|
|
161
|
+
- **Signature:** `(..., cloudSettings) -> Project | bool`
|
|
162
|
+
- **Behavior:** All four take an enum-keyed {cloudSettings} dict (resolve.CLOUD_SETTING_* keys, resolve.CLOUD_SYNC_* sync-mode values). Plain string keys are silently rejected, so a settings dict built from human-readable keys yields no project / False.
|
|
163
|
+
- **Workaround / current handling:** Resolve the CLOUD_SETTING_*/CLOUD_SYNC_* constants via the live resolve handle (server._normalize_cloud_settings) before calling, and treat the bool return from Import/RestoreCloudProject as advisory.
|
|
164
|
+
- **Tags:** silent-failure, project, cloud, enum
|
|
165
|
+
|
|
166
|
+
### Timeline.Export
|
|
167
|
+
|
|
168
|
+
- **Object:** `Timeline`
|
|
169
|
+
- **Signature:** `(fileName, exportType, exportSubtype) -> bool`
|
|
170
|
+
- **Behavior:** exportType/exportSubtype must be resolve.EXPORT_* enum *values* resolved from the live handle. A JSON/MCP caller cannot pass a live enum, and a plain string ('fcpxml', or even the constant name 'EXPORT_FCPXML_1_10') is silently rejected with no file written.
|
|
171
|
+
- **Workaround / current handling:** Map a friendly format/subtype to the EXPORT_* constant and resolve it against the live handle (server._timeline_export_spec) before calling; verify the output file exists afterward.
|
|
172
|
+
- **Tags:** silent-failure, timeline, export, enum
|
|
173
|
+
|
|
174
|
+
### ProjectManager.DeleteProject
|
|
175
|
+
|
|
176
|
+
- **Object:** `ProjectManager`
|
|
177
|
+
- **Signature:** `(projectName) -> bool`
|
|
178
|
+
- **Behavior:** Returns False (no deletion) when the target project is, or recently was, the current project, and is flaky on the first attempt — so a single bool() call leaves the project undeleted with no useful error.
|
|
179
|
+
- **Workaround / current handling:** Load/close away from the target first, then retry; use src/utils/project_cleanup.py:delete_project_safely.
|
|
180
|
+
- **Tags:** unreliable-return, project, flaky
|
|
181
|
+
|
|
182
|
+
### Composition.Paste
|
|
183
|
+
|
|
184
|
+
- **Object:** `Fusion Composition`
|
|
185
|
+
- **Behavior:** Passing tool.SaveSettings()'s in-memory table to Paste() / LoadSettings() fails across the Python bridge with an OrderedDict/null-argument error and creates no node, while reporting nothing useful.
|
|
186
|
+
- **Workaround / current handling:** Duplicate via AddTool(RegID) + SaveSettings(path)/LoadSettings(path) through a temp .setting FILE, which round-trips reliably. Identify the new node by name diff.
|
|
187
|
+
- **Tags:** fusion, bridge, silent-failure
|
|
188
|
+
|
|
189
|
+
### FlowView.SetPos / FlowView.GetPosTable
|
|
190
|
+
|
|
191
|
+
- **Object:** `Fusion FlowView (comp.CurrentFrame.FlowView)`
|
|
192
|
+
- **Behavior:** Node positions are read/written through the FlowView, not the tool. SetPos returns nothing reliable; GetPosTable returns a 1-indexed table (or dict/tuple depending on bridge).
|
|
193
|
+
- **Workaround / current handling:** Use comp.CurrentFrame.FlowView.SetPos(tool, x, y); confirm with GetPosTable and a liberal position parser.
|
|
194
|
+
- **Tags:** fusion, unreliable-return
|
|
195
|
+
|
|
196
|
+
### MediaPoolItem.GetClipProperty('Transcription')
|
|
197
|
+
|
|
198
|
+
- **Object:** `MediaPoolItem`
|
|
199
|
+
- **Behavior:** Returns a PREVIEW of the transcription that ends in an ellipsis when the full transcript is longer than the property exposes.
|
|
200
|
+
- **Workaround / current handling:** Treat a trailing ellipsis as truncation (see media_pool_item get_transcription's `truncated` flag).
|
|
201
|
+
- **Tags:** transcription, truncation
|
|
202
|
+
|
|
203
|
+
### ProjectManager.CreateProject (with a dirty Untitled project)
|
|
204
|
+
|
|
205
|
+
- **Object:** `ProjectManager`
|
|
206
|
+
- **Behavior:** Returns None and pops a modal 'Save Current Project' dialog when the current unsaved/Untitled project blocks the switch. SaveProject() on an Untitled project re-triggers the same modal.
|
|
207
|
+
- **Workaround / current handling:** CloseProject(current) to discard the untitled project without a prompt, then CreateProject; restore with LoadProject afterward.
|
|
208
|
+
- **Tags:** project, modal, silent-failure
|
package/install.py
CHANGED
|
@@ -35,7 +35,7 @@ from src.utils.update_check import (
|
|
|
35
35
|
|
|
36
36
|
# ─── Version ──────────────────────────────────────────────────────────────────
|
|
37
37
|
|
|
38
|
-
VERSION = "2.57.
|
|
38
|
+
VERSION = "2.57.3"
|
|
39
39
|
# Only hard floor: mcp[cli] requires Python 3.10+. There is no upper bound —
|
|
40
40
|
# Resolve's scripting bridge loads into newer interpreters on recent builds
|
|
41
41
|
# (Python 3.14 verified against Resolve Studio 20.3.2). Older Resolve builds
|
package/package.json
CHANGED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Generate the Blackmagic-facing DaVinci Resolve API limitations report.
|
|
3
|
+
|
|
4
|
+
The single source of truth is the ``submit``-tagged entries in
|
|
5
|
+
``src/utils/api_truth.py`` (see ``submittable_limitations``). This script renders
|
|
6
|
+
them into ``docs/reference/api-limitations.md`` — a curated, behaviorally-verified
|
|
7
|
+
list that can be submitted to Blackmagic Design's developer feedback, split into
|
|
8
|
+
capabilities they should *add* and behaviors they should *fix*.
|
|
9
|
+
|
|
10
|
+
The output is deterministic (no timestamps) so ``tests.test_api_limitations_doc``
|
|
11
|
+
can assert the committed file matches. Regenerate after editing any ``submit``
|
|
12
|
+
entry:
|
|
13
|
+
|
|
14
|
+
venv/bin/python scripts/gen_api_limitations.py
|
|
15
|
+
|
|
16
|
+
Run with ``--check`` to fail (exit 1) when the committed doc is stale.
|
|
17
|
+
"""
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import sys
|
|
21
|
+
from pathlib import Path
|
|
22
|
+
|
|
23
|
+
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
24
|
+
if str(REPO_ROOT) not in sys.path:
|
|
25
|
+
sys.path.insert(0, str(REPO_ROOT))
|
|
26
|
+
|
|
27
|
+
from src.utils.api_truth import ( # noqa: E402
|
|
28
|
+
VERIFIED_ON,
|
|
29
|
+
submittable_limitations,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
DOC_PATH = REPO_ROOT / "docs" / "reference" / "api-limitations.md"
|
|
33
|
+
ISSUE_URL = "https://github.com/samuelgursky/davinci-resolve-mcp/issues"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _render_entry(entry: dict) -> str:
|
|
37
|
+
lines = [f"### {entry['symbol']}", ""]
|
|
38
|
+
obj = entry.get("object")
|
|
39
|
+
if obj:
|
|
40
|
+
lines.append(f"- **Object:** `{obj}`")
|
|
41
|
+
sig = entry.get("signature")
|
|
42
|
+
if sig:
|
|
43
|
+
lines.append(f"- **Signature:** `{sig}`")
|
|
44
|
+
lines.append(f"- **Behavior:** {entry['reality']}")
|
|
45
|
+
rec = entry.get("recommended")
|
|
46
|
+
if rec:
|
|
47
|
+
lines.append(f"- **Workaround / current handling:** {rec}")
|
|
48
|
+
issue = entry.get("issue")
|
|
49
|
+
if issue is not None:
|
|
50
|
+
lines.append(f"- **Reference:** [issue #{issue}]({ISSUE_URL}/{issue})")
|
|
51
|
+
tags = entry.get("tags")
|
|
52
|
+
if tags:
|
|
53
|
+
lines.append(f"- **Tags:** {', '.join(tags)}")
|
|
54
|
+
lines.append("")
|
|
55
|
+
return "\n".join(lines)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def render() -> str:
|
|
59
|
+
groups = submittable_limitations()
|
|
60
|
+
missing = groups["missing"]
|
|
61
|
+
bugs = groups["bug"]
|
|
62
|
+
|
|
63
|
+
out = [
|
|
64
|
+
"# DaVinci Resolve Scripting API — Limitations & Feedback",
|
|
65
|
+
"",
|
|
66
|
+
"<!-- GENERATED FILE — do not edit by hand.",
|
|
67
|
+
" Source: src/utils/api_truth.py (entries tagged `submit`).",
|
|
68
|
+
" Regenerate: venv/bin/python scripts/gen_api_limitations.py -->",
|
|
69
|
+
"",
|
|
70
|
+
"This is a curated, behaviorally-verified list of DaVinci Resolve scripting",
|
|
71
|
+
"API gaps and bugs encountered while building this MCP server, intended for",
|
|
72
|
+
"submission to Blackmagic Design's developer feedback. Every item was",
|
|
73
|
+
"observed against live Resolve; each entry notes the current workaround (or",
|
|
74
|
+
"that none exists).",
|
|
75
|
+
"",
|
|
76
|
+
f"**Verified on:** {VERIFIED_ON}",
|
|
77
|
+
"",
|
|
78
|
+
f"**Totals:** {len(missing)} missing capabilities, {len(bugs)} bugs / "
|
|
79
|
+
"unreliable behaviors.",
|
|
80
|
+
"",
|
|
81
|
+
"The authoritative source is the runtime-queryable `api_truth` ledger",
|
|
82
|
+
"(`resolve_control api_truth \"<query>\"`); this document is generated from",
|
|
83
|
+
"it and stays in sync via a drift guard.",
|
|
84
|
+
"",
|
|
85
|
+
"### Scope & completeness",
|
|
86
|
+
"",
|
|
87
|
+
"This list is **not guaranteed exhaustive.** It combines (a) issues hit",
|
|
88
|
+
"while building this MCP server and (b) a `dir()` surface audit of the live",
|
|
89
|
+
"Resolve API objects (ProjectManager, Project, MediaPool, MediaPoolItem,",
|
|
90
|
+
"Timeline, TimelineItem, Graph) diffed against Resolve's UI feature set.",
|
|
91
|
+
"That catches absent methods and documented constraints, but not subtler",
|
|
92
|
+
"issues: parameters that exist yet misbehave, version-specific regressions,",
|
|
93
|
+
"or capabilities we simply never exercised. New findings are added as",
|
|
94
|
+
"`submit`-tagged `api_truth` entries and this document is regenerated.",
|
|
95
|
+
"",
|
|
96
|
+
"## Missing Capabilities (please add)",
|
|
97
|
+
"",
|
|
98
|
+
"Functionality that exists in the Resolve UI but has no scripting API",
|
|
99
|
+
"equivalent, blocking full automation.",
|
|
100
|
+
"",
|
|
101
|
+
]
|
|
102
|
+
for entry in missing:
|
|
103
|
+
out.append(_render_entry(entry))
|
|
104
|
+
|
|
105
|
+
out += [
|
|
106
|
+
"## Bugs / Unreliable Behavior (please fix)",
|
|
107
|
+
"",
|
|
108
|
+
"Methods that exist but misbehave — silent failures, unreliable return",
|
|
109
|
+
"values, or automation-hostile modal prompts.",
|
|
110
|
+
"",
|
|
111
|
+
]
|
|
112
|
+
for entry in bugs:
|
|
113
|
+
out.append(_render_entry(entry))
|
|
114
|
+
|
|
115
|
+
return "\n".join(out).rstrip() + "\n"
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def main(argv: list[str]) -> int:
|
|
119
|
+
content = render()
|
|
120
|
+
if "--check" in argv:
|
|
121
|
+
current = DOC_PATH.read_text() if DOC_PATH.exists() else ""
|
|
122
|
+
if current != content:
|
|
123
|
+
print(
|
|
124
|
+
f"STALE: {DOC_PATH.relative_to(REPO_ROOT)} is out of date.\n"
|
|
125
|
+
"Run: venv/bin/python scripts/gen_api_limitations.py",
|
|
126
|
+
file=sys.stderr,
|
|
127
|
+
)
|
|
128
|
+
return 1
|
|
129
|
+
print(f"OK: {DOC_PATH.relative_to(REPO_ROOT)} is up to date.")
|
|
130
|
+
return 0
|
|
131
|
+
DOC_PATH.write_text(content)
|
|
132
|
+
print(f"Wrote {DOC_PATH.relative_to(REPO_ROOT)}")
|
|
133
|
+
return 0
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
if __name__ == "__main__":
|
|
137
|
+
raise SystemExit(main(sys.argv[1:]))
|
package/src/granular/common.py
CHANGED
|
@@ -80,7 +80,7 @@ if not logging.getLogger().handlers:
|
|
|
80
80
|
handlers=[logging.StreamHandler()],
|
|
81
81
|
)
|
|
82
82
|
|
|
83
|
-
VERSION = "2.57.
|
|
83
|
+
VERSION = "2.57.3"
|
|
84
84
|
logger = logging.getLogger("davinci-resolve-mcp")
|
|
85
85
|
logger.info(f"Starting DaVinci Resolve MCP Server v{VERSION}")
|
|
86
86
|
logger.info(f"Detected platform: {get_platform()}")
|
package/src/server.py
CHANGED
package/src/utils/api_truth.py
CHANGED
|
@@ -10,6 +10,19 @@ Each entry is a small dict. Grow it opportunistically — every readback recipe
|
|
|
10
10
|
every fix that uncovers a surprising behavior should add an entry. Facts are
|
|
11
11
|
stamped with the Resolve build they were verified on so drift is visible when a
|
|
12
12
|
new version ships.
|
|
13
|
+
|
|
14
|
+
Optional keys on an entry feed the Blackmagic-facing limitations report
|
|
15
|
+
(``docs/reference/api-limitations.md``, generated by
|
|
16
|
+
``scripts/gen_api_limitations.py``):
|
|
17
|
+
|
|
18
|
+
- ``submit``: ``"missing"`` (a capability Blackmagic should add) or ``"bug"``
|
|
19
|
+
(a behavior Blackmagic should fix). Entries without ``submit`` are internal
|
|
20
|
+
quirks/tips and stay out of the report.
|
|
21
|
+
- ``issue``: GitHub issue number (int) that drove the finding, for cross-ref.
|
|
22
|
+
|
|
23
|
+
When you add or change a ``submit``-tagged entry, regenerate the report
|
|
24
|
+
(``venv/bin/python scripts/gen_api_limitations.py``) or the
|
|
25
|
+
``tests.test_api_limitations_doc`` drift guard fails.
|
|
13
26
|
"""
|
|
14
27
|
from typing import Any, Dict, List, Optional
|
|
15
28
|
|
|
@@ -28,6 +41,7 @@ API_TRUTH: List[Dict[str, Any]] = [
|
|
|
28
41
|
"resolve handle, and verify by reading each clip's "
|
|
29
42
|
"'Synced Audio' property (see verify_by_readback).",
|
|
30
43
|
"tags": ["unreliable-return", "silent-failure", "audio", "enum"],
|
|
44
|
+
"submit": "bug",
|
|
31
45
|
"mitigation": ["_normalize_auto_sync_settings", "_safe_auto_sync_audio"],
|
|
32
46
|
},
|
|
33
47
|
{
|
|
@@ -44,6 +58,7 @@ API_TRUTH: List[Dict[str, Any]] = [
|
|
|
44
58
|
"and verify by reading the timeline's subtitle track count "
|
|
45
59
|
"before/after (server._safe_create_subtitles).",
|
|
46
60
|
"tags": ["unreliable-return", "silent-failure", "subtitle", "enum"],
|
|
61
|
+
"submit": "bug",
|
|
47
62
|
"mitigation": ["_normalize_auto_caption_settings", "_safe_create_subtitles"],
|
|
48
63
|
},
|
|
49
64
|
{
|
|
@@ -59,6 +74,7 @@ API_TRUTH: List[Dict[str, Any]] = [
|
|
|
59
74
|
"before calling, and treat the bool return from "
|
|
60
75
|
"Import/RestoreCloudProject as advisory.",
|
|
61
76
|
"tags": ["silent-failure", "project", "cloud", "enum"],
|
|
77
|
+
"submit": "bug",
|
|
62
78
|
"mitigation": ["_normalize_cloud_settings"],
|
|
63
79
|
},
|
|
64
80
|
{
|
|
@@ -75,6 +91,7 @@ API_TRUTH: List[Dict[str, Any]] = [
|
|
|
75
91
|
"(server._timeline_export_spec) before calling; verify the "
|
|
76
92
|
"output file exists afterward.",
|
|
77
93
|
"tags": ["silent-failure", "timeline", "export", "enum"],
|
|
94
|
+
"submit": "bug",
|
|
78
95
|
"mitigation": ["_timeline_export_spec", "_timeline_export_value"],
|
|
79
96
|
},
|
|
80
97
|
{
|
|
@@ -88,6 +105,7 @@ API_TRUTH: List[Dict[str, Any]] = [
|
|
|
88
105
|
"recommended": "Load/close away from the target first, then retry; use "
|
|
89
106
|
"src/utils/project_cleanup.py:delete_project_safely.",
|
|
90
107
|
"tags": ["unreliable-return", "project", "flaky"],
|
|
108
|
+
"submit": "bug",
|
|
91
109
|
},
|
|
92
110
|
{
|
|
93
111
|
"symbol": "Composition.Paste",
|
|
@@ -100,6 +118,7 @@ API_TRUTH: List[Dict[str, Any]] = [
|
|
|
100
118
|
"LoadSettings(path) through a temp .setting FILE, which "
|
|
101
119
|
"round-trips reliably. Identify the new node by name diff.",
|
|
102
120
|
"tags": ["fusion", "bridge", "silent-failure"],
|
|
121
|
+
"submit": "bug",
|
|
103
122
|
},
|
|
104
123
|
{
|
|
105
124
|
"symbol": "FlowView.SetPos / FlowView.GetPosTable",
|
|
@@ -110,6 +129,7 @@ API_TRUTH: List[Dict[str, Any]] = [
|
|
|
110
129
|
"recommended": "Use comp.CurrentFrame.FlowView.SetPos(tool, x, y); confirm "
|
|
111
130
|
"with GetPosTable and a liberal position parser.",
|
|
112
131
|
"tags": ["fusion", "unreliable-return"],
|
|
132
|
+
"submit": "bug",
|
|
113
133
|
},
|
|
114
134
|
{
|
|
115
135
|
"symbol": "Timeline.GetTimelineByName",
|
|
@@ -117,6 +137,7 @@ API_TRUTH: List[Dict[str, Any]] = [
|
|
|
117
137
|
"reality": "Does not exist. Timelines are looked up by index.",
|
|
118
138
|
"recommended": "Iterate GetTimelineByIndex(1..GetTimelineCount()).",
|
|
119
139
|
"tags": ["missing-method", "timeline"],
|
|
140
|
+
"submit": "missing",
|
|
120
141
|
},
|
|
121
142
|
{
|
|
122
143
|
"symbol": "Project render methods (AddRenderJob, SetRenderSettings, ...)",
|
|
@@ -136,6 +157,7 @@ API_TRUTH: List[Dict[str, Any]] = [
|
|
|
136
157
|
"recommended": "Treat a trailing ellipsis as truncation (see "
|
|
137
158
|
"media_pool_item get_transcription's `truncated` flag).",
|
|
138
159
|
"tags": ["transcription", "truncation"],
|
|
160
|
+
"submit": "bug",
|
|
139
161
|
},
|
|
140
162
|
{
|
|
141
163
|
"symbol": "ProjectManager.CreateProject (with a dirty Untitled project)",
|
|
@@ -147,6 +169,7 @@ API_TRUTH: List[Dict[str, Any]] = [
|
|
|
147
169
|
"without a prompt, then CreateProject; restore with "
|
|
148
170
|
"LoadProject afterward.",
|
|
149
171
|
"tags": ["project", "modal", "silent-failure"],
|
|
172
|
+
"submit": "bug",
|
|
150
173
|
},
|
|
151
174
|
{
|
|
152
175
|
"symbol": "Timeline.InsertFusionCompositionIntoTimeline",
|
|
@@ -179,6 +202,163 @@ API_TRUTH: List[Dict[str, Any]] = [
|
|
|
179
202
|
"instead (exposed as media_pool append_to_timeline clip_infos). "
|
|
180
203
|
"See issue #74.",
|
|
181
204
|
"tags": ["missing-method", "timeline", "title", "generator", "track"],
|
|
205
|
+
"submit": "missing",
|
|
206
|
+
"issue": 74,
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
"symbol": "Per-clip audio channel-format conversion (Stereo<->Mono)",
|
|
210
|
+
"object": "MediaPoolItem / TimelineItem",
|
|
211
|
+
"reality": "No scripting method converts an individual clip's audio "
|
|
212
|
+
"channel format. ConvertTimelineToStereo is timeline-wide, and "
|
|
213
|
+
"CreateStereoClip builds a 3D *visual* stereoscopic clip, not an "
|
|
214
|
+
"audio mono->stereo change. The Edit-page 'Clip Attributes > "
|
|
215
|
+
"Audio' channel mapping is UI-only.",
|
|
216
|
+
"recommended": "Use the supported surface: timeline add_track with audioType "
|
|
217
|
+
"(create mono/stereo tracks), get_track_sub_type (query "
|
|
218
|
+
"format), convert_to_stereo (timeline-wide), and "
|
|
219
|
+
"timeline_item get_source_audio_channel_mapping. Per-clip "
|
|
220
|
+
"conversion is not possible. See issue #73.",
|
|
221
|
+
"tags": ["missing-method", "audio", "channel"],
|
|
222
|
+
"submit": "missing",
|
|
223
|
+
"issue": 73,
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"symbol": "Native multicam clip creation",
|
|
227
|
+
"object": "MediaPool",
|
|
228
|
+
"reality": "There is no method to create a native multicam clip from a set "
|
|
229
|
+
"of angles. Angles can be stacked onto tracks programmatically, "
|
|
230
|
+
"but the multicam-clip conversion is a UI-only step.",
|
|
231
|
+
"recommended": "Prepare a stacked timeline (media_pool setup_multicam_timeline) "
|
|
232
|
+
"and finish the multicam-clip conversion in the Resolve UI.",
|
|
233
|
+
"tags": ["missing-method", "media-pool", "multicam"],
|
|
234
|
+
"submit": "missing",
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
"symbol": "Transition create / copy / clone",
|
|
238
|
+
"object": "Timeline / TimelineItem",
|
|
239
|
+
"reality": "The scripting API exposes no method to add, read, copy, or "
|
|
240
|
+
"clone an edit transition (cross-dissolve, etc.). Transitions "
|
|
241
|
+
"applied in the UI are invisible to and unmodifiable by scripts.",
|
|
242
|
+
"recommended": "Apply/duplicate transitions in the Resolve UI; no scripted "
|
|
243
|
+
"equivalent exists.",
|
|
244
|
+
"tags": ["missing-method", "timeline", "transition"],
|
|
245
|
+
"submit": "missing",
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
"symbol": "Cloud project enumeration / export / user management",
|
|
249
|
+
"object": "ProjectManager",
|
|
250
|
+
"reality": "Only CreateCloudProject, LoadCloudProject, ImportCloudProject "
|
|
251
|
+
"and RestoreCloudProject exist. There is no GetCloudProjectList "
|
|
252
|
+
"(list available cloud projects), no ExportToCloud, and no "
|
|
253
|
+
"Add/RemoveUserToCloudProject — so cloud collaboration can't be "
|
|
254
|
+
"fully automated.",
|
|
255
|
+
"recommended": "Drive cloud project listing, export, and collaborator "
|
|
256
|
+
"management from the Resolve UI; only create/load/import/"
|
|
257
|
+
"restore are scriptable.",
|
|
258
|
+
"tags": ["missing-method", "project", "cloud"],
|
|
259
|
+
"submit": "missing",
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
"symbol": "TimelineItem trim / move / re-time (no position setters)",
|
|
263
|
+
"object": "TimelineItem",
|
|
264
|
+
"reality": "TimelineItem exposes GetStart, GetEnd, GetDuration, "
|
|
265
|
+
"GetLeftOffset, GetRightOffset and GetSourceStart/EndFrame, but "
|
|
266
|
+
"NO matching setters. A clip cannot be trimmed, slipped, slid, "
|
|
267
|
+
"rolled, moved to another time/track, or have its duration "
|
|
268
|
+
"changed once it is on the timeline. Verified via dir() on "
|
|
269
|
+
"Resolve 21.0.0 (getters only).",
|
|
270
|
+
"recommended": "Do edit-point adjustments in the Resolve UI, or rebuild the "
|
|
271
|
+
"timeline from MediaPool.AppendToTimeline clipInfos with the "
|
|
272
|
+
"desired startFrame/endFrame/recordFrame.",
|
|
273
|
+
"tags": ["missing-method", "timeline", "edit", "trim"],
|
|
274
|
+
"submit": "missing",
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
"symbol": "Razor / blade / split a timeline item",
|
|
278
|
+
"object": "Timeline / TimelineItem",
|
|
279
|
+
"reality": "There is no method to split/cut/blade a clip at a given frame. "
|
|
280
|
+
"Verified absent on Timeline and TimelineItem (dir(), 21.0.0).",
|
|
281
|
+
"recommended": "Split in the Resolve UI, or construct the cut up-front by "
|
|
282
|
+
"appending two clipInfos with the desired in/out points.",
|
|
283
|
+
"tags": ["missing-method", "timeline", "edit"],
|
|
284
|
+
"submit": "missing",
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
"symbol": "Clip speed / retime ratio and speed ramps",
|
|
288
|
+
"object": "TimelineItem",
|
|
289
|
+
"reality": "SetProperty exposes only retime *quality* (RetimeProcess, "
|
|
290
|
+
"MotionEstimation) and transform/crop/composite/opacity keys — "
|
|
291
|
+
"not the speed value itself. There is no way to set a clip to a "
|
|
292
|
+
"given % speed, reverse it, or author a speed ramp. Verified "
|
|
293
|
+
"against the documented SetProperty key list (21.0.0).",
|
|
294
|
+
"recommended": "Set clip speed/retime in the Resolve UI; no scripted "
|
|
295
|
+
"equivalent exists.",
|
|
296
|
+
"tags": ["missing-method", "timeline", "retime", "speed"],
|
|
297
|
+
"submit": "missing",
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
"symbol": "Color node graph editing and primary grade values",
|
|
301
|
+
"object": "Graph / TimelineItem",
|
|
302
|
+
"reality": "The Graph object exposes node enable/label/count, LUT get/set, "
|
|
303
|
+
"cache mode, ResetAllGrades, ApplyGradeFromDRX and "
|
|
304
|
+
"ApplyArriCdlLut; TimelineItem adds SetCDL, CopyGrades and color "
|
|
305
|
+
"versions. But you cannot add, delete, or connect nodes, and you "
|
|
306
|
+
"cannot read or write primary grade values (lift/gamma/gain/"
|
|
307
|
+
"offset/contrast/curves/qualifiers/power windows). Grading is "
|
|
308
|
+
"limited to CDL, whole-grade DRX/LUT application and copying.",
|
|
309
|
+
"recommended": "Build node trees and dial grades in the Resolve UI or via "
|
|
310
|
+
"DRX/CDL/LUT import; per-parameter grade control is not "
|
|
311
|
+
"scriptable.",
|
|
312
|
+
"tags": ["missing-method", "color", "grade", "node"],
|
|
313
|
+
"submit": "missing",
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
"symbol": "Fairlight audio levels / pan / EQ / automation / FairlightFX",
|
|
317
|
+
"object": "TimelineItem / Timeline",
|
|
318
|
+
"reality": "There is no API to set clip or track volume, pan, EQ, audio "
|
|
319
|
+
"automation, or to add/configure FairlightFX. SetProperty covers "
|
|
320
|
+
"video transform only; the audio surface is read-only "
|
|
321
|
+
"(GetSourceAudioChannelMapping, GetAudioMapping, voice "
|
|
322
|
+
"isolation). Verified via dir() + SetProperty docs (21.0.0).",
|
|
323
|
+
"recommended": "Mix in the Fairlight UI; only voice-isolation state and "
|
|
324
|
+
"channel-mapping reads are scriptable.",
|
|
325
|
+
"tags": ["missing-method", "audio", "fairlight"],
|
|
326
|
+
"submit": "missing",
|
|
327
|
+
},
|
|
328
|
+
{
|
|
329
|
+
"symbol": "Proxy / optimized-media generation",
|
|
330
|
+
"object": "MediaPoolItem",
|
|
331
|
+
"reality": "Only LinkProxyMedia, UnlinkProxyMedia and "
|
|
332
|
+
"LinkFullResolutionMedia exist (attach/detach EXISTING proxies). "
|
|
333
|
+
"There is no method to generate proxies or optimized media. "
|
|
334
|
+
"Verified via MediaPoolItem dir() (21.0.0).",
|
|
335
|
+
"recommended": "Trigger proxy/optimized-media generation from the Resolve "
|
|
336
|
+
"UI; scripting can only link/unlink already-rendered proxies.",
|
|
337
|
+
"tags": ["missing-method", "media-pool", "proxy"],
|
|
338
|
+
"submit": "missing",
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
"symbol": "Insert / Overwrite / Replace / Fit-to-Fill edit modes",
|
|
342
|
+
"object": "MediaPool / Timeline",
|
|
343
|
+
"reality": "MediaPool.AppendToTimeline (with optional recordFrame "
|
|
344
|
+
"positioning) is the only programmatic placement. The standard "
|
|
345
|
+
"edit modes — insert (ripple), overwrite, replace, fit-to-fill, "
|
|
346
|
+
"place-on-top — have no API. Verified via dir() (21.0.0).",
|
|
347
|
+
"recommended": "Position clips with AppendToTimeline clipInfo recordFrame, "
|
|
348
|
+
"or perform insert/overwrite/replace edits in the Resolve UI.",
|
|
349
|
+
"tags": ["missing-method", "timeline", "edit"],
|
|
350
|
+
"submit": "missing",
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
"symbol": "Smart Bins / Power Bins creation",
|
|
354
|
+
"object": "MediaPool",
|
|
355
|
+
"reality": "Only AddSubFolder (a regular bin) exists. Smart Bins (rule-"
|
|
356
|
+
"based) and Power Bins (cross-project) cannot be created or "
|
|
357
|
+
"configured. Verified via MediaPool dir() (21.0.0).",
|
|
358
|
+
"recommended": "Create Smart/Power Bins in the Resolve UI; only regular "
|
|
359
|
+
"bins are scriptable.",
|
|
360
|
+
"tags": ["missing-method", "media-pool", "bins"],
|
|
361
|
+
"submit": "missing",
|
|
182
362
|
},
|
|
183
363
|
{
|
|
184
364
|
"symbol": "subprocess inheriting stdin under the MCP stdio server",
|
|
@@ -212,3 +392,17 @@ def lookup_api_truth(query: Optional[str] = None) -> List[Dict[str, Any]]:
|
|
|
212
392
|
if q in hay:
|
|
213
393
|
out.append(e)
|
|
214
394
|
return out
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
def submittable_limitations() -> Dict[str, List[Dict[str, Any]]]:
|
|
398
|
+
"""Group ``submit``-tagged entries for the Blackmagic-facing report.
|
|
399
|
+
|
|
400
|
+
Returns ``{"missing": [...], "bug": [...]}`` — entries Blackmagic should add
|
|
401
|
+
vs. behaviors they should fix — preserving API_TRUTH order within each group.
|
|
402
|
+
"""
|
|
403
|
+
groups: Dict[str, List[Dict[str, Any]]] = {"missing": [], "bug": []}
|
|
404
|
+
for e in API_TRUTH:
|
|
405
|
+
kind = e.get("submit")
|
|
406
|
+
if kind in groups:
|
|
407
|
+
groups[kind].append(e)
|
|
408
|
+
return groups
|