davinci-resolve-mcp 2.86.3 → 2.87.0
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/CHANGELOG.md +82 -0
- package/README.md +5 -5
- package/README.zh-CN.md +6 -6
- package/docs/SKILL.md +16 -1
- package/docs/reference/api-coverage.md +28 -6
- package/docs/reference/resolve_scripting_api.txt +21 -1
- package/install.py +1 -1
- package/package.json +1 -1
- package/src/granular/common.py +1 -1
- package/src/server.py +118 -6
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,88 @@
|
|
|
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.87.0
|
|
6
|
+
|
|
7
|
+
The ten Resolve 21.0.4 scripting surfaces that the 24 Jul 2026 README refresh
|
|
8
|
+
documented beyond the three wired in v2.86.0. Contributed by @legionsound
|
|
9
|
+
(PR #139), who reported them as issues #135–#138 from Studio 21.0.4.5.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **`layout_presets` gains `list`** (`Resolve.GetLayoutPresetList`). The tool
|
|
14
|
+
had six actions and every one of them took a preset name the caller had no
|
|
15
|
+
way to enumerate.
|
|
16
|
+
- **`render_presets` gains `list_burnin` and `delete_burnin`**
|
|
17
|
+
(`Resolve.GetBurnInPresetList` / `DeleteBurnInPreset`). `list_burnin` is the
|
|
18
|
+
missing half of the burn-in surface: the `DataBurnIn` render setting and both
|
|
19
|
+
`load_burnin_preset` actions take a name nothing could list.
|
|
20
|
+
- **`resolve_control` gains the six `*_user_preferences_preset` actions** —
|
|
21
|
+
`list`, `save`, `load`, `delete`, `import`, `export`. Two caveats are carried
|
|
22
|
+
in the docstrings and answers rather than left to be discovered:
|
|
23
|
+
`load_user_preferences_preset` is **session-wide** (it swaps the user's global
|
|
24
|
+
Resolve preferences, not a project setting), and
|
|
25
|
+
`import_user_preferences_preset` answers with the README's own caveat that the
|
|
26
|
+
imported preset is *not* auto-loaded, so a caller follows with `load` instead
|
|
27
|
+
of stopping early.
|
|
28
|
+
- **`project_manager` gains `list_attributes`**
|
|
29
|
+
(`ProjectManager.GetProjectAttributesInCurrentFolder`) — `lastModifiedDate`,
|
|
30
|
+
`creationDate`, `notes`, and `liveCollaborationMode` per project in the
|
|
31
|
+
current folder, without loading any project.
|
|
32
|
+
|
|
33
|
+
All ten are `_requires_method`-guarded at 21.0.4, advertised in the capability
|
|
34
|
+
and preset-lifecycle probes, and covered by 21 stub contract cases in
|
|
35
|
+
`tests/test_resolve2104_preset_actions.py` (answers, name-required errors,
|
|
36
|
+
pre-21.0.4 guards, `_unknown` listings, capability advertisement on both a
|
|
37
|
+
21.0.4 and a legacy stub).
|
|
38
|
+
|
|
39
|
+
### Documentation
|
|
40
|
+
|
|
41
|
+
- **`docs/reference/resolve_scripting_api.txt` was the 26 May 2026 README** —
|
|
42
|
+
which is exactly why this delta went unnoticed. It is now the 24 Jul 2026
|
|
43
|
+
text these wrappers came from.
|
|
44
|
+
- **`api-coverage.md`: 351 → 361 methods**, with the ten new rows marked 🔬 and
|
|
45
|
+
carrying the contributor's Studio 21.0.4.5 results as a contributor report,
|
|
46
|
+
not as validation of ours — this machine runs Studio 19.1.3 and free 21.0.3,
|
|
47
|
+
neither of which is 21.0.4. `LoadUserPreferencesPreset` is recorded as
|
|
48
|
+
deliberately unexecuted even by the reporter, same class as
|
|
49
|
+
`DisableBackgroundTasksForCurrentResolveSession`.
|
|
50
|
+
- **The README key stats were stale at 349** since the v2.86.0 surfaces landed;
|
|
51
|
+
both READMEs and the live-tested badge now read 361 covered / 338 live-tested
|
|
52
|
+
(93.6%), and the English tested-against row picks up the free 21.0.3 build the
|
|
53
|
+
coverage doc already listed.
|
|
54
|
+
|
|
55
|
+
## What's New in v2.86.4
|
|
56
|
+
|
|
57
|
+
The issue #132 follow-up, which turned out not to be a tool bug at all. No
|
|
58
|
+
behavior changed in any tool.
|
|
59
|
+
|
|
60
|
+
### Fixed
|
|
61
|
+
|
|
62
|
+
- **The skills told an assistant to "route the user to the UI" and stopped
|
|
63
|
+
there, so it invented the directions.** In issue #132 a user was sent hunting
|
|
64
|
+
for a retime dropdown "in the lower left of the clip"; the keyframe tray was
|
|
65
|
+
never mentioned. That direction exists nowhere in this repo — no skill, doc,
|
|
66
|
+
or ledger entry describes where any Resolve control sits. The assistant
|
|
67
|
+
improvised the handoff and delivered it in the same confident register as the
|
|
68
|
+
API facts around it, which had been measured, so the user had no way to tell
|
|
69
|
+
the two apart. `resolve-edit` now carries the rule: **never improvise UI
|
|
70
|
+
geography.** Name the operation, say you cannot see the user's screen, and
|
|
71
|
+
treat a UI pointer already written into a skill (the playback-frame-rate path
|
|
72
|
+
in `resolve-rough-cut`) as the only kind to quote — verbatim, never extended
|
|
73
|
+
from memory. Where no pointer exists, point at Blackmagic's manual for their
|
|
74
|
+
build rather than supplying one. `resolve-rough-cut` picks up the same guard
|
|
75
|
+
at its own UI handoff.
|
|
76
|
+
|
|
77
|
+
Deliberately **not** fixed by adding the correct location. This repo verifies
|
|
78
|
+
API behavior and has no mechanism to version-guard a UI claim — every
|
|
79
|
+
`api_truth` entry is stamped with the build it was measured on because
|
|
80
|
+
unstamped claims rot, and UI geography moves between builds, pages and
|
|
81
|
+
layouts with no drift guard that would catch it going stale. The reporter hit
|
|
82
|
+
this on Resolve 21; the validation machine here is Studio 19.1.3.7, so
|
|
83
|
+
confirming a location here and publishing it for 21 would be the exact move
|
|
84
|
+
v2.82.1 exists to correct. Thanks to @magwa101 for coming back with the
|
|
85
|
+
detail that relocated the bug.
|
|
86
|
+
|
|
5
87
|
## What's New in v2.86.3
|
|
6
88
|
|
|
7
89
|
A Simplified Chinese phrasing fix from the reviewer who asked for it when #122
|
package/README.md
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
English | [简体中文](README.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
[](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
|
|
6
6
|
[](https://www.npmjs.com/package/davinci-resolve-mcp)
|
|
7
7
|
[](docs/reference/api-coverage.md)
|
|
8
8
|
[-blue.svg)](#server-modes)
|
|
9
9
|
[-18%20tools-blueviolet.svg)](#server-modes)
|
|
10
|
-
[](docs/reference/api-coverage.md#test-results)
|
|
11
11
|
[](https://www.blackmagicdesign.com/products/davinciresolve)
|
|
12
12
|
[](https://www.python.org/downloads/)
|
|
13
13
|
[](https://opensource.org/licenses/MIT)
|
|
@@ -265,10 +265,10 @@ The default server is a local stdio process launched by your MCP client; it does
|
|
|
265
265
|
| MCP Tools | **34** compound / **341** granular (live server) |
|
|
266
266
|
| Advanced (offline) tools | **18** — .drp/.drt/.drx + DB authoring, no Resolve running |
|
|
267
267
|
| Kernel Actions | **136** guarded workflow actions across 9 compound tools |
|
|
268
|
-
| API Methods Covered | **
|
|
269
|
-
| Methods Live Tested | **338/
|
|
268
|
+
| API Methods Covered | **361/361** (100%) |
|
|
269
|
+
| Methods Live Tested | **338/361** (93.6%) |
|
|
270
270
|
| Live Test Pass Rate | **338/338** (100%) |
|
|
271
|
-
| Tested Against | DaVinci Resolve 19.1.3 Studio + Resolve 20.3.2 Studio + Resolve 21.0.2 Studio |
|
|
271
|
+
| Tested Against | DaVinci Resolve 19.1.3 Studio + Resolve 20.3.2 Studio + Resolve 21.0.2 Studio + Resolve 21.0.3 **free** (via the in-app bridge) |
|
|
272
272
|
|
|
273
273
|
For method-by-method status, see [API Coverage and Test Results](docs/reference/api-coverage.md). For current workflow support, see [Kernel Action Coverage](docs/kernels/README.md).
|
|
274
274
|
|
package/README.zh-CN.md
CHANGED
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) | 简体中文
|
|
4
4
|
|
|
5
|
-
[](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
|
|
6
6
|
[](https://www.npmjs.com/package/davinci-resolve-mcp)
|
|
7
7
|
[](docs/reference/api-coverage.md)
|
|
8
8
|
[-blue.svg)](#服务器模式)
|
|
9
9
|
[-18%20tools-blueviolet.svg)](#服务器模式)
|
|
10
|
-
[](docs/reference/api-coverage.md#test-results)
|
|
11
11
|
[](https://www.blackmagicdesign.com/products/davinciresolve)
|
|
12
12
|
[](https://www.python.org/downloads/)
|
|
13
13
|
[](https://opensource.org/licenses/MIT)
|
|
14
14
|
|
|
15
|
-
> 本翻译对应 v2.
|
|
15
|
+
> 本翻译对应 v2.87.0 版 README。如与英文原版有出入,以 [英文原版](README.md) 为准。
|
|
16
16
|
|
|
17
17
|
一个 Model Context Protocol (MCP) 服务器,让 AI 助手通过官方脚本 API 控制 DaVinci Resolve Studio(达芬奇)。它提供完整的 API 覆盖,外加带护栏的工作流助手,涵盖剪辑、媒体池整理、渲染设置、审阅标记、调色、Fusion、Fairlight、项目生命周期任务、扩展开发,以及不碰源媒体的媒体分析。
|
|
18
18
|
|
|
@@ -193,10 +193,10 @@ DRX 调色写入**针对 Resolve Studio 做过实机校准**:调色参数默
|
|
|
193
193
|
| MCP 工具 | **34** 复合 / **341** 细粒度(实时服务器) |
|
|
194
194
|
| Advanced(离线)工具 | **18**——.drp/.drt/.drx + 数据库创作,无需 Resolve 运行 |
|
|
195
195
|
| 内核 action | 9 个复合工具下 **136** 个带护栏的工作流 action |
|
|
196
|
-
| API 方法覆盖 | **
|
|
197
|
-
| 实机测试方法数 | **338/
|
|
196
|
+
| API 方法覆盖 | **361/361**(100%) |
|
|
197
|
+
| 实机测试方法数 | **338/361**(93.6%) |
|
|
198
198
|
| 实机测试通过率 | **338/338**(100%) |
|
|
199
|
-
| 测试环境 | DaVinci Resolve 19.1.3 Studio + 20.3.2 Studio + 21.0.2 Studio |
|
|
199
|
+
| 测试环境 | DaVinci Resolve 19.1.3 Studio + 20.3.2 Studio + 21.0.2 Studio + 21.0.3 **免费版**(经内置桥接) |
|
|
200
200
|
|
|
201
201
|
逐方法状态见 [API 覆盖与测试结果](docs/reference/api-coverage.md)。当前工作流支持见 [内核 action 覆盖](docs/kernels/README.md)。
|
|
202
202
|
|
package/docs/SKILL.md
CHANGED
|
@@ -498,11 +498,21 @@ Key actions:
|
|
|
498
498
|
- `get_keyframe_mode` / `set_keyframe_mode(mode)`
|
|
499
499
|
- `get_fairlight_presets` — Resolve 20.2.2+; returns available Fairlight
|
|
500
500
|
preset names
|
|
501
|
+
- `list/save/load/delete/import/export_user_preferences_preset` — Resolve
|
|
502
|
+
21.0.4+; user-preferences presets. `load_...` is SESSION-WIDE: it swaps the
|
|
503
|
+
user's global Resolve preferences, so only call it when the user asked for
|
|
504
|
+
the switch. `import_...` does not activate the imported preset — follow with
|
|
505
|
+
`load_user_preferences_preset`
|
|
501
506
|
- `quit` — terminates Resolve (destructive; confirm with user first)
|
|
502
507
|
|
|
503
508
|
**`layout_presets`** — Save, load, export, import, delete UI layout presets.
|
|
509
|
+
`list` (Resolve 21.0.4+) enumerates the saved preset names the other actions
|
|
510
|
+
take.
|
|
504
511
|
|
|
505
512
|
**`render_presets`** — Import and export render and burn-in presets.
|
|
513
|
+
`list_burnin` / `delete_burnin` (Resolve 21.0.4+) enumerate and remove burn-in
|
|
514
|
+
presets — `list_burnin` is the only way to discover the names the `DataBurnIn`
|
|
515
|
+
render setting and the `load_burnin_preset` actions expect.
|
|
506
516
|
|
|
507
517
|
---
|
|
508
518
|
|
|
@@ -510,11 +520,16 @@ Key actions:
|
|
|
510
520
|
|
|
511
521
|
**`project_manager`** — CRUD on projects.
|
|
512
522
|
|
|
513
|
-
Key actions: `list`, `
|
|
523
|
+
Key actions: `list`, `list_attributes`, `get_current`,
|
|
524
|
+
`create(name, media_location_path?)`,
|
|
514
525
|
`load(name)`, `save`, `close`,
|
|
515
526
|
`delete(name)`, `import_project(path)`, `export_project(name, path)`, `archive`,
|
|
516
527
|
`restore`
|
|
517
528
|
|
|
529
|
+
`list_attributes` (Resolve 21.0.4+) returns `lastModifiedDate`, `creationDate`,
|
|
530
|
+
`notes`, and `liveCollaborationMode` per project in the current folder without
|
|
531
|
+
loading any of them.
|
|
532
|
+
|
|
518
533
|
Project / Database / Archive kernel actions (v2.15.0+) add guarded project
|
|
519
534
|
lifecycle, settings, database, preset, and archive boundary helpers:
|
|
520
535
|
|
|
@@ -8,8 +8,8 @@ Complete Resolve scripting API coverage, live-test status, and method-by-method
|
|
|
8
8
|
|--------|-------|
|
|
9
9
|
| MCP Tools | **34** compound (default) / **341** granular |
|
|
10
10
|
| Kernel Actions | **136** guarded MCP workflow actions across 9 compound tools |
|
|
11
|
-
| API Methods Covered | **
|
|
12
|
-
| Methods Live Tested | **338/
|
|
11
|
+
| API Methods Covered | **361/361** (100%) |
|
|
12
|
+
| Methods Live Tested | **338/361** (93.6%) |
|
|
13
13
|
| Live Test Pass Rate | **338/338** (100%) |
|
|
14
14
|
| API Object Classes | 13 |
|
|
15
15
|
| Tested Against | DaVinci Resolve 19.1.3 Studio + Resolve 20.3.2 Studio + Resolve 21.0.2 Studio + Resolve 21.0.3 **free** (via the in-app bridge) |
|
|
@@ -109,7 +109,7 @@ source, these summaries are downstream of it:
|
|
|
109
109
|
| Phase 5 | 6/6 | 100% | Scene cuts, subtitles from audio, graph node cache/tools/enable |
|
|
110
110
|
| Resolve 20 delta | 12/12 | 100% | Resolve 20.0-20.2.2 scripting additions live-tested on 20.3.2 |
|
|
111
111
|
| Resolve 21 delta | 7/7 | 100% | Resolve 21.0 additions that could be executed, live-tested on Studio 21.0.2.4 (`tests/live_resolve21_validation.py`). The other 6 need an AI Extras pack or are unsafe to run — counted as untested, not as passes |
|
|
112
|
-
| **Total** | **338/338** | **100%** | **
|
|
112
|
+
| **Total** | **338/338** | **100%** | **93.6% of the 361 covered methods tested live** |
|
|
113
113
|
|
|
114
114
|
#### Resolve 21 delta detail
|
|
115
115
|
|
|
@@ -130,7 +130,7 @@ marked 🔬 rather than ⚠️.
|
|
|
130
130
|
| `Project.GenerateSpeech` | 🔬 | Requires AI Speech Generator; returned an error **string**, not a MediaPoolItem |
|
|
131
131
|
| `Resolve.DisableBackgroundTasksForCurrentResolveSession` | 🔬 | Present in `dir()`; **not executed** — session-wide, returns None, and has no `Enable...` counterpart, so there is no undo short of restarting Resolve |
|
|
132
132
|
|
|
133
|
-
### Untested Methods (
|
|
133
|
+
### Untested Methods (23 of 361)
|
|
134
134
|
|
|
135
135
|
Every ☁️ and 🔬 row from the reference tables, listed here so the count is
|
|
136
136
|
checkable rather than asserted.
|
|
@@ -150,12 +150,24 @@ checkable rather than asserted.
|
|
|
150
150
|
| `Resolve.DisableBackgroundTasksForCurrentResolveSession` | Deliberately not executed: session-wide, returns `None`, and has no `Enable...` counterpart, so there is no undo short of restarting Resolve | No |
|
|
151
151
|
| `MPI.GetTimeline` | Requires a Resolve 21.0.4 build; the validation machine runs Studio 19.1.3 and free 21.0.3 | Yes |
|
|
152
152
|
| `TL.GetSelectedClips` | Requires a Resolve 21.0.4 build; the validation machine runs 19.1.3 | Yes |
|
|
153
|
+
| `Resolve.GetLayoutPresetList` | Requires a Resolve 21.0.4 build; the validation machine runs Studio 19.1.3 and free 21.0.3 | Yes |
|
|
154
|
+
| `Resolve.GetBurnInPresetList` | Requires a Resolve 21.0.4 build; the validation machine runs Studio 19.1.3 and free 21.0.3 | Yes |
|
|
155
|
+
| `Resolve.DeleteBurnInPreset` | Requires a Resolve 21.0.4 build; also, no scripting API creates a burn-in preset to round-trip against | Yes |
|
|
156
|
+
| `Resolve.GetUserPreferencesPresetList` | Requires a Resolve 21.0.4 build; the validation machine runs Studio 19.1.3 and free 21.0.3 | Yes |
|
|
157
|
+
| `Resolve.SaveUserPreferencesPreset` | Requires a Resolve 21.0.4 build; the validation machine runs Studio 19.1.3 and free 21.0.3 | Yes |
|
|
158
|
+
| `Resolve.LoadUserPreferencesPreset` | Deliberately not executed even by the reporter: swaps the user's global preferences session-wide | No |
|
|
159
|
+
| `Resolve.DeleteUserPreferencesPreset` | Requires a Resolve 21.0.4 build; the validation machine runs Studio 19.1.3 and free 21.0.3 | Yes |
|
|
160
|
+
| `Resolve.ImportUserPreferencesPreset` | Requires a Resolve 21.0.4 build and a preset file to import | Yes |
|
|
161
|
+
| `Resolve.ExportUserPreferencesPreset` | Requires a Resolve 21.0.4 build; the validation machine runs Studio 19.1.3 and free 21.0.3 | Yes |
|
|
162
|
+
| `PM.GetProjectAttributesInCurrentFolder` | Requires a Resolve 21.0.4 build; the validation machine runs Studio 19.1.3 and free 21.0.3 | Yes |
|
|
153
163
|
|
|
154
164
|
The five AI Extras rows are untested for want of a downloadable pack, not because
|
|
155
165
|
the wrappers are suspect — a report from anyone who has the packs installed would
|
|
156
|
-
close them. The
|
|
166
|
+
close them. The twelve 21.0.4 rows are untested for want of the build: this machine
|
|
157
167
|
runs 19.1.3, so they are guarded and unit-tested against stubs and carry a
|
|
158
|
-
contributor's report rather than a result of ours
|
|
168
|
+
contributor's report rather than a result of ours (issue #131 for the first two;
|
|
169
|
+
issues #135–#138 for the ten from the 24 Jul 2026 README refresh, several with
|
|
170
|
+
save→list→delete round-trips on Studio 21.0.4.5). The remaining one is a
|
|
159
171
|
decision rather than a gap: it is reachable, and
|
|
160
172
|
running it during a validation sweep would disable background tasks for every
|
|
161
173
|
project open in that Resolve instance.
|
|
@@ -199,6 +211,15 @@ Every method in the DaVinci Resolve Scripting API and its test status. Methods a
|
|
|
199
211
|
| 21 | `SetKeyframeMode(keyframeMode)` | ⚠️ | API accepts; mode must match valid enum |
|
|
200
212
|
| 22 | `GetFairlightPresets()` | ✅ | Returns a preset map. Live on 20.3.2 Studio and 21.0.3 free; **absent below 20.2.2** — confirmed missing on 19.1.3, so the version floor is verified from both sides |
|
|
201
213
|
| 23 | `DisableBackgroundTasksForCurrentResolveSession()` | 🔬 | Resolve 21.0. Present in `dir()`; **not executed** — session-wide, returns `None`, no `Enable...` counterpart, so no undo short of restarting Resolve |
|
|
214
|
+
| 24 | `GetLayoutPresetList()` | 🔬 | Resolve 21.0.4 (24 Jul 2026 README). Not executed here — no 21.0.4 build; reporter's save→list→delete round-trip on Studio 21.0.4.5 in issue #137 |
|
|
215
|
+
| 25 | `GetBurnInPresetList()` | 🔬 | Resolve 21.0.4. Not executed here; reported returning a list on Studio 21.0.4.5 in issue #136 |
|
|
216
|
+
| 26 | `DeleteBurnInPreset(presetName)` | 🔬 | Resolve 21.0.4. `dir()`-present on 21.0.4.5 (issue #136); not executed anywhere — no scripting API creates a burn-in preset to round-trip against |
|
|
217
|
+
| 27 | `GetUserPreferencesPresetList()` | 🔬 | Resolve 21.0.4. Not executed here; reporter's save→list→delete round-trip on Studio 21.0.4.5 in issue #138 |
|
|
218
|
+
| 28 | `SaveUserPreferencesPreset(presetName)` | 🔬 | Resolve 21.0.4. Not executed here; part of the issue #138 round-trip on 21.0.4.5 |
|
|
219
|
+
| 29 | `LoadUserPreferencesPreset(presetName)` | 🔬 | Resolve 21.0.4. `dir()`-present on 21.0.4.5; **not executed** even by the reporter — swaps the user's global preferences session-wide (issue #138) |
|
|
220
|
+
| 30 | `DeleteUserPreferencesPreset(presetName)` | 🔬 | Resolve 21.0.4. Not executed here; part of the issue #138 round-trip on 21.0.4.5 |
|
|
221
|
+
| 31 | `ImportUserPreferencesPreset(presetFilePath, presetName)` | 🔬 | Resolve 21.0.4. `dir()`-present on 21.0.4.5 only (issue #138) — no preset file was on hand. Per the README the imported preset is **not** auto-loaded |
|
|
222
|
+
| 32 | `ExportUserPreferencesPreset(presetName, exportPath)` | 🔬 | Resolve 21.0.4. `dir()`-present on 21.0.4.5 only (issue #138) |
|
|
202
223
|
|
|
203
224
|
### ProjectManager
|
|
204
225
|
|
|
@@ -229,6 +250,7 @@ Every method in the DaVinci Resolve Scripting API and its test status. Methods a
|
|
|
229
250
|
| 23 | `LoadCloudProject({cloudSettings})` | ☁️ | Requires cloud infrastructure |
|
|
230
251
|
| 24 | `ImportCloudProject(filePath, {cloudSettings})` | ☁️ | Requires cloud infrastructure |
|
|
231
252
|
| 25 | `RestoreCloudProject(folderPath, {cloudSettings})` | ☁️ | Requires cloud infrastructure |
|
|
253
|
+
| 26 | `GetProjectAttributesInCurrentFolder()` | 🔬 | Resolve 21.0.4 (24 Jul 2026 README). Not executed here — no 21.0.4 build; reported live on Studio 21.0.4.5 in issue #135, returning `lastModifiedDate` / `creationDate` / `notes` / `liveCollaborationMode` for all 8 projects in the current folder |
|
|
232
254
|
|
|
233
255
|
### Project
|
|
234
256
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Last Updated:
|
|
1
|
+
Last Updated: 24 Jul 2026
|
|
2
2
|
-------------------------
|
|
3
3
|
In this package, you will find a brief introduction to the Scripting API for DaVinci Resolve Studio. Apart from this README.txt file, this package contains folders containing the basic import
|
|
4
4
|
modules for scripting access (DaVinciResolve.py) and some representative examples.
|
|
@@ -91,6 +91,7 @@ Resolve
|
|
|
91
91
|
GetProductName() --> string # Returns product name.
|
|
92
92
|
GetVersion() --> [version fields] # Returns list of product version fields in [major, minor, patch, build, suffix] format.
|
|
93
93
|
GetVersionString() --> string # Returns product version in "major.minor.patch[suffix].build" format.
|
|
94
|
+
GetLayoutPresetList() --> [presetNames...] # Returns list of layout preset names.
|
|
94
95
|
LoadLayoutPreset(presetName) --> Bool # Loads UI layout from saved preset named 'presetName'.
|
|
95
96
|
UpdateLayoutPreset(presetName) --> Bool # Overwrites preset named 'presetName' with current UI layout.
|
|
96
97
|
ExportLayoutPreset(presetName, presetFilePath) --> Bool # Exports preset named 'presetName' to path 'presetFilePath'.
|
|
@@ -100,8 +101,16 @@ Resolve
|
|
|
100
101
|
Quit() --> None # Quits the Resolve App.
|
|
101
102
|
ImportRenderPreset(presetPath) --> Bool # Import a preset from presetPath (string) and set it as current preset for rendering.
|
|
102
103
|
ExportRenderPreset(presetName, exportPath) --> Bool # Export a preset to a given path (string) if presetName(string) exists.
|
|
104
|
+
GetBurnInPresetList() --> [presetName...] # Returns a list of data burn in preset names.
|
|
105
|
+
DeleteBurnInPreset(presetName) --> Bool # Deletes the data burn in preset.
|
|
103
106
|
ImportBurnInPreset(presetPath) --> Bool # Import a data burn in preset from a given presetPath (string)
|
|
104
107
|
ExportBurnInPreset(presetName, exportPath) --> Bool # Export a data burn in preset to a given path (string) if presetName (string) exists.
|
|
108
|
+
GetUserPreferencesPresetList() --> [presetNames...] # Returns a list of user preferences preset names.
|
|
109
|
+
LoadUserPreferencesPreset(presetName) --> Bool # Loads the user preferences preset named 'presetName'.
|
|
110
|
+
SaveUserPreferencesPreset(presetName) --> Bool # Saves the current user preferences as a new preset named 'presetName'.
|
|
111
|
+
DeleteUserPreferencesPreset(presetName) --> Bool # Deletes the user preferences preset named 'presetName'.
|
|
112
|
+
ImportUserPreferencesPreset(presetFilePath, presetName) --> Bool # Imports user preferences preset from presetFilePath. Optional presetName argument to name the imported preset. The imported preset is not automatically loaded, use LoadUserPreferencesPreset(..) to load it.
|
|
113
|
+
ExportUserPreferencesPreset(presetName, exportPath) --> Bool # Exports the user preferences preset to exportPath.
|
|
105
114
|
GetKeyframeMode() --> keyframeMode # Returns the currently set keyframe mode (int). Refer to section 'Keyframe Mode information' below for details.
|
|
106
115
|
SetKeyframeMode(keyframeMode) --> Bool # Returns True when 'keyframeMode'(enum) is successfully set. Refer to section 'Keyframe Mode information' below for details.
|
|
107
116
|
GetFairlightPresets() --> [presetNames...]. # Returns a list of Fairlight presets by name
|
|
@@ -122,6 +131,8 @@ ProjectManager
|
|
|
122
131
|
CreateFolder(folderName) --> Bool # Creates a folder if folderName (string) is unique.
|
|
123
132
|
DeleteFolder(folderName) --> Bool # Deletes the specified folder if it exists. Returns True in case of success.
|
|
124
133
|
GetProjectListInCurrentFolder() --> [project names...] # Returns a list of project names in current folder.
|
|
134
|
+
GetProjectAttributesInCurrentFolder() --> {project name: {attributes}, ...} # Returns a dictionary of project names in the current folder to project attributes.
|
|
135
|
+
# Attributes include "lastModifiedDate", "creationDate", "notes", and "liveCollaborationMode".
|
|
125
136
|
GetFolderListInCurrentFolder() --> [folder names...] # Returns a list of folder names in current folder.
|
|
126
137
|
GotoRootFolder() --> Bool # Opens root folder in database.
|
|
127
138
|
GotoParentFolder() --> Bool # Opens parent folder of current folder in database if current folder has parent.
|
|
@@ -295,6 +306,7 @@ MediaPoolItem
|
|
|
295
306
|
# If no argument is specified, a dict of all set metadata properties is returned.
|
|
296
307
|
SetMetadata(metadataType, metadataValue) --> Bool # Sets the given metadata to metadataValue (string). Returns True if successful.
|
|
297
308
|
SetMetadata({metadata}) --> Bool # Sets the item metadata with specified 'metadata' dict. Returns True if successful.
|
|
309
|
+
GetTimeline() --> TimelineItem # Returns the timeline object if the mpItem is a timeline clip, or None if not.
|
|
298
310
|
GetThirdPartyMetadata(metadataType=None) --> string|dict # Returns the third party metadata value for the key 'metadataType'.
|
|
299
311
|
# If no argument is specified, a dict of all set third party metadata properties is returned.
|
|
300
312
|
SetThirdPartyMetadata(metadataType, metadataValue) --> Bool # Sets/Add the given third party metadata to metadataValue (string). Returns True if successful.
|
|
@@ -385,6 +397,7 @@ Timeline
|
|
|
385
397
|
DeleteClips([timelineItems], Bool) --> Bool # Deletes specified TimelineItems from the timeline, performing ripple delete if the second argument is True. Second argument is optional (The default for this is False)
|
|
386
398
|
SetClipsLinked([timelineItems], Bool) --> Bool # Links or unlinks the specified TimelineItems depending on second argument.
|
|
387
399
|
GetItemListInTrack(trackType, index) --> [items...] # Returns a list of timeline items on that track (based on trackType and index). 1 <= index <= GetTrackCount(trackType).
|
|
400
|
+
GetSelectedClips() --> [items...] # Returns the currently selected timeline items.
|
|
388
401
|
AddMarker(frameId, color, name, note, duration, --> Bool # Creates a new marker at given frameId position and with given marker information. 'customData' is optional and helps to attach user specific data to the marker.
|
|
389
402
|
customData)
|
|
390
403
|
GetMarkers() --> {markers...} # Returns a dict (frameId -> {information}) of all markers and dicts with their information.
|
|
@@ -693,6 +706,10 @@ Affects:
|
|
|
693
706
|
Affects:
|
|
694
707
|
• x = Project:GetSetting('timelineFrameRate') and Project:SetSetting('timelineFrameRate', x)
|
|
695
708
|
|
|
709
|
+
"timelineSampleRate" - the property value is one of the sample rates available to the user in project settings under "Audio sample rate" option in the Fairlight tab.
|
|
710
|
+
Affects:
|
|
711
|
+
• x = Project:GetSetting('timelineSampleRate') and Project:SetSetting('timelineSampleRate', x)
|
|
712
|
+
|
|
696
713
|
The following Clip properties have specifically enumerated values:
|
|
697
714
|
"Super Scale" - the property value is an enumerated integer between 1 and 4 with these meanings: 1=no scaling, and 2, 3 and 4 represent the Super Scale multipliers 2x, 3x and 4x.
|
|
698
715
|
for super scale multiplier '2x Enhanced', exactly 4 arguments must be passed as outlined below. If less than 4 arguments are passed, it will default to 2x.
|
|
@@ -844,6 +861,9 @@ The parameter setting is a dictionary containing the following keys:
|
|
|
844
861
|
- "ReplaceExistingFilesInPlace": Bool
|
|
845
862
|
- "ExportSubtitle": Bool
|
|
846
863
|
- "SubtitleFormat": string (options: "BurnIn", "EmbeddedCaptions", "SeparateFile")
|
|
864
|
+
- "UseFullExtents": Bool
|
|
865
|
+
- "AddFrameHandles": int (>= 0). Ignored if use full extents is enabled.
|
|
866
|
+
- "DataBurnIn": string. (example: "Same as project", "None")
|
|
847
867
|
|
|
848
868
|
Looking up timeline export properties
|
|
849
869
|
-------------------------------------
|
package/install.py
CHANGED
|
@@ -36,7 +36,7 @@ from src.utils.update_check import (
|
|
|
36
36
|
|
|
37
37
|
# ─── Version ──────────────────────────────────────────────────────────────────
|
|
38
38
|
|
|
39
|
-
VERSION = "2.
|
|
39
|
+
VERSION = "2.87.0"
|
|
40
40
|
# Only hard floor: mcp[cli] requires Python 3.10+. There is no upper bound —
|
|
41
41
|
# Resolve's scripting bridge loads into newer interpreters on recent builds
|
|
42
42
|
# (Python 3.14 verified against Resolve Studio 20.3.2). Older Resolve builds
|
package/package.json
CHANGED
package/src/granular/common.py
CHANGED
|
@@ -85,7 +85,7 @@ if not logging.getLogger().handlers:
|
|
|
85
85
|
handlers=[logging.StreamHandler()],
|
|
86
86
|
)
|
|
87
87
|
|
|
88
|
-
VERSION = "2.
|
|
88
|
+
VERSION = "2.87.0"
|
|
89
89
|
logger = logging.getLogger("davinci-resolve-mcp")
|
|
90
90
|
logger.info(f"Starting DaVinci Resolve MCP Server v{VERSION}")
|
|
91
91
|
logger.info(f"Detected platform: {get_platform()}")
|
package/src/server.py
CHANGED
|
@@ -11,7 +11,7 @@ Usage:
|
|
|
11
11
|
python src/server.py --full # Start the 341-tool granular server instead
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
|
-
VERSION = "2.
|
|
14
|
+
VERSION = "2.87.0"
|
|
15
15
|
|
|
16
16
|
import base64
|
|
17
17
|
import os
|
|
@@ -13581,6 +13581,16 @@ def resolve_control(action: str, params: Optional[Dict[str, Any]] = None) -> Dic
|
|
|
13581
13581
|
get_fairlight_presets() -> {presets}
|
|
13582
13582
|
set_high_priority() -> {success}
|
|
13583
13583
|
disable_background_tasks_for_current_session() -> {success} — Resolve 21+
|
|
13584
|
+
list_user_preferences_presets() -> {presets} — Resolve 21.0.4+
|
|
13585
|
+
save_user_preferences_preset(name) -> {success} — Resolve 21.0.4+
|
|
13586
|
+
load_user_preferences_preset(name) -> {success} — Resolve 21.0.4+.
|
|
13587
|
+
SESSION-WIDE: swaps the user's global Resolve preferences, not a
|
|
13588
|
+
project setting. Only call when the user asked for the switch.
|
|
13589
|
+
delete_user_preferences_preset(name) -> {success} — Resolve 21.0.4+
|
|
13590
|
+
import_user_preferences_preset(path, name?) -> {success} — Resolve 21.0.4+.
|
|
13591
|
+
The imported preset is NOT auto-loaded; follow with
|
|
13592
|
+
load_user_preferences_preset to activate it.
|
|
13593
|
+
export_user_preferences_preset(name, path) -> {success} — Resolve 21.0.4+
|
|
13584
13594
|
open_control_panel(port?, host?, open_browser?) -> {success, url, pid, port, status}
|
|
13585
13595
|
— Launches the analysis control panel (src/analysis_dashboard.py) as a background process.
|
|
13586
13596
|
Idempotent: returns the existing URL if already running.
|
|
@@ -13816,7 +13826,56 @@ def resolve_control(action: str, params: Optional[Dict[str, Any]] = None) -> Dic
|
|
|
13816
13826
|
return missing
|
|
13817
13827
|
r.DisableBackgroundTasksForCurrentResolveSession()
|
|
13818
13828
|
return _ok()
|
|
13819
|
-
|
|
13829
|
+
elif action == "list_user_preferences_presets":
|
|
13830
|
+
missing = _requires_method(r, "GetUserPreferencesPresetList", "21.0.4")
|
|
13831
|
+
if missing:
|
|
13832
|
+
return missing
|
|
13833
|
+
return {"presets": _ser(r.GetUserPreferencesPresetList() or [])}
|
|
13834
|
+
elif action == "save_user_preferences_preset":
|
|
13835
|
+
missing = _requires_method(r, "SaveUserPreferencesPreset", "21.0.4")
|
|
13836
|
+
if missing:
|
|
13837
|
+
return missing
|
|
13838
|
+
if not p.get("name"):
|
|
13839
|
+
return _err("save_user_preferences_preset requires name")
|
|
13840
|
+
return {"success": bool(r.SaveUserPreferencesPreset(p["name"]))}
|
|
13841
|
+
elif action == "load_user_preferences_preset":
|
|
13842
|
+
missing = _requires_method(r, "LoadUserPreferencesPreset", "21.0.4")
|
|
13843
|
+
if missing:
|
|
13844
|
+
return missing
|
|
13845
|
+
if not p.get("name"):
|
|
13846
|
+
return _err("load_user_preferences_preset requires name")
|
|
13847
|
+
return {"success": bool(r.LoadUserPreferencesPreset(p["name"]))}
|
|
13848
|
+
elif action == "delete_user_preferences_preset":
|
|
13849
|
+
missing = _requires_method(r, "DeleteUserPreferencesPreset", "21.0.4")
|
|
13850
|
+
if missing:
|
|
13851
|
+
return missing
|
|
13852
|
+
if not p.get("name"):
|
|
13853
|
+
return _err("delete_user_preferences_preset requires name")
|
|
13854
|
+
return {"success": bool(r.DeleteUserPreferencesPreset(p["name"]))}
|
|
13855
|
+
elif action == "import_user_preferences_preset":
|
|
13856
|
+
missing = _requires_method(r, "ImportUserPreferencesPreset", "21.0.4")
|
|
13857
|
+
if missing:
|
|
13858
|
+
return missing
|
|
13859
|
+
if not p.get("path"):
|
|
13860
|
+
return _err("import_user_preferences_preset requires path")
|
|
13861
|
+
if p.get("name"):
|
|
13862
|
+
ok = bool(r.ImportUserPreferencesPreset(p["path"], p["name"]))
|
|
13863
|
+
else:
|
|
13864
|
+
ok = bool(r.ImportUserPreferencesPreset(p["path"]))
|
|
13865
|
+
return {"success": ok,
|
|
13866
|
+
"note": "The imported preset is not auto-loaded; use load_user_preferences_preset to activate it."}
|
|
13867
|
+
elif action == "export_user_preferences_preset":
|
|
13868
|
+
missing = _requires_method(r, "ExportUserPreferencesPreset", "21.0.4")
|
|
13869
|
+
if missing:
|
|
13870
|
+
return missing
|
|
13871
|
+
err, clean = _validate_params(p, {
|
|
13872
|
+
"name": {"type": str, "required": True, "non_empty": True},
|
|
13873
|
+
"path": {"type": str, "required": True, "non_empty": True},
|
|
13874
|
+
})
|
|
13875
|
+
if err:
|
|
13876
|
+
return _err(err)
|
|
13877
|
+
return {"success": bool(r.ExportUserPreferencesPreset(clean["name"], clean["path"]))}
|
|
13878
|
+
return _unknown(action, ["launch","runtime_mode","get_version","api_truth","check_version_support","verification_stats","job_status","list_jobs","mcp_update_status","set_mcp_update_policy","ignore_mcp_update","snooze_mcp_update","clear_mcp_update_preferences","get_page","open_page","get_keyframe_mode","set_keyframe_mode","quit","get_fairlight_presets","set_high_priority","disable_background_tasks_for_current_session","list_user_preferences_presets","save_user_preferences_preset","load_user_preferences_preset","delete_user_preferences_preset","import_user_preferences_preset","export_user_preferences_preset","open_control_panel","control_panel_status","close_control_panel","save_state","restore_state"])
|
|
13820
13879
|
|
|
13821
13880
|
|
|
13822
13881
|
# ─── V2 C4: Per-field corrections with provenance + changelog ────────────────
|
|
@@ -14682,6 +14741,7 @@ def layout_presets(action: str, params: Optional[Dict[str, Any]] = None) -> Dict
|
|
|
14682
14741
|
"""Manage DaVinci Resolve UI layout presets.
|
|
14683
14742
|
|
|
14684
14743
|
Actions:
|
|
14744
|
+
list() -> {presets} — Resolve 21.0.4+; saved layout preset names
|
|
14685
14745
|
save(name) -> {success}
|
|
14686
14746
|
load(name) -> {success}
|
|
14687
14747
|
update(name) -> {success}
|
|
@@ -14694,7 +14754,12 @@ def layout_presets(action: str, params: Optional[Dict[str, Any]] = None) -> Dict
|
|
|
14694
14754
|
if r is None:
|
|
14695
14755
|
return _not_connected_error()
|
|
14696
14756
|
|
|
14697
|
-
if action == "
|
|
14757
|
+
if action == "list":
|
|
14758
|
+
missing = _requires_method(r, "GetLayoutPresetList", "21.0.4")
|
|
14759
|
+
if missing:
|
|
14760
|
+
return missing
|
|
14761
|
+
return {"presets": _ser(r.GetLayoutPresetList() or [])}
|
|
14762
|
+
elif action == "save":
|
|
14698
14763
|
if not p.get("name"):
|
|
14699
14764
|
return _err("save requires name")
|
|
14700
14765
|
return {"success": bool(r.SaveLayoutPreset(p["name"]))}
|
|
@@ -14716,7 +14781,7 @@ def layout_presets(action: str, params: Optional[Dict[str, Any]] = None) -> Dict
|
|
|
14716
14781
|
return {"success": bool(r.ImportLayoutPreset(p["path"]))}
|
|
14717
14782
|
elif action == "delete":
|
|
14718
14783
|
return {"success": bool(r.DeleteLayoutPreset(p["name"]))}
|
|
14719
|
-
return _unknown(action, ["save","load","update","export","import_preset","delete"])
|
|
14784
|
+
return _unknown(action, ["list","save","load","update","export","import_preset","delete"])
|
|
14720
14785
|
|
|
14721
14786
|
|
|
14722
14787
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -14733,6 +14798,10 @@ def render_presets(action: str, params: Optional[Dict[str, Any]] = None) -> Dict
|
|
|
14733
14798
|
export_render(name, path) -> {success}
|
|
14734
14799
|
import_burnin(path) -> {success}
|
|
14735
14800
|
export_burnin(name, path) -> {success}
|
|
14801
|
+
list_burnin() -> {presets} — Resolve 21.0.4+; burn-in preset names usable
|
|
14802
|
+
with the render tool's DataBurnIn setting and load_burnin_preset on
|
|
14803
|
+
project_settings / timeline_item
|
|
14804
|
+
delete_burnin(name) -> {success} — Resolve 21.0.4+
|
|
14736
14805
|
"""
|
|
14737
14806
|
p = _params(params)
|
|
14738
14807
|
r = get_resolve()
|
|
@@ -14747,7 +14816,19 @@ def render_presets(action: str, params: Optional[Dict[str, Any]] = None) -> Dict
|
|
|
14747
14816
|
return {"success": bool(r.ImportBurnInPreset(p["path"]))}
|
|
14748
14817
|
elif action == "export_burnin":
|
|
14749
14818
|
return {"success": bool(r.ExportBurnInPreset(p["name"], p["path"]))}
|
|
14750
|
-
|
|
14819
|
+
elif action == "list_burnin":
|
|
14820
|
+
missing = _requires_method(r, "GetBurnInPresetList", "21.0.4")
|
|
14821
|
+
if missing:
|
|
14822
|
+
return missing
|
|
14823
|
+
return {"presets": _ser(r.GetBurnInPresetList() or [])}
|
|
14824
|
+
elif action == "delete_burnin":
|
|
14825
|
+
missing = _requires_method(r, "DeleteBurnInPreset", "21.0.4")
|
|
14826
|
+
if missing:
|
|
14827
|
+
return missing
|
|
14828
|
+
if not p.get("name"):
|
|
14829
|
+
return _err("delete_burnin requires name")
|
|
14830
|
+
return {"success": bool(r.DeleteBurnInPreset(p["name"]))}
|
|
14831
|
+
return _unknown(action, ["import_render","export_render","import_burnin","export_burnin","list_burnin","delete_burnin"])
|
|
14751
14832
|
|
|
14752
14833
|
|
|
14753
14834
|
# ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -14783,6 +14864,7 @@ _PROJECT_MANAGER_METHODS = [
|
|
|
14783
14864
|
"CreateFolder",
|
|
14784
14865
|
"DeleteFolder",
|
|
14785
14866
|
"GetProjectListInCurrentFolder",
|
|
14867
|
+
"GetProjectAttributesInCurrentFolder",
|
|
14786
14868
|
"GetFolderListInCurrentFolder",
|
|
14787
14869
|
"GotoRootFolder",
|
|
14788
14870
|
"GotoParentFolder",
|
|
@@ -14938,6 +15020,7 @@ def _project_capabilities(pm=None, project=None, resolve_obj=None) -> Dict[str,
|
|
|
14938
15020
|
"kernel_actions": list(_PROJECT_KERNEL_ACTIONS),
|
|
14939
15021
|
"resolve": {
|
|
14940
15022
|
"layout_presets": {
|
|
15023
|
+
"list": _has_method(resolve_obj, "GetLayoutPresetList") if resolve_obj else True,
|
|
14941
15024
|
"save": _has_method(resolve_obj, "SaveLayoutPreset") if resolve_obj else True,
|
|
14942
15025
|
"load": _has_method(resolve_obj, "LoadLayoutPreset") if resolve_obj else True,
|
|
14943
15026
|
"update": _has_method(resolve_obj, "UpdateLayoutPreset") if resolve_obj else True,
|
|
@@ -14950,6 +15033,16 @@ def _project_capabilities(pm=None, project=None, resolve_obj=None) -> Dict[str,
|
|
|
14950
15033
|
"export_render": _has_method(resolve_obj, "ExportRenderPreset") if resolve_obj else True,
|
|
14951
15034
|
"import_burnin": _has_method(resolve_obj, "ImportBurnInPreset") if resolve_obj else True,
|
|
14952
15035
|
"export_burnin": _has_method(resolve_obj, "ExportBurnInPreset") if resolve_obj else True,
|
|
15036
|
+
"list_burnin": _has_method(resolve_obj, "GetBurnInPresetList") if resolve_obj else True,
|
|
15037
|
+
"delete_burnin": _has_method(resolve_obj, "DeleteBurnInPreset") if resolve_obj else True,
|
|
15038
|
+
},
|
|
15039
|
+
"user_preferences_presets": {
|
|
15040
|
+
"list": _has_method(resolve_obj, "GetUserPreferencesPresetList") if resolve_obj else True,
|
|
15041
|
+
"save": _has_method(resolve_obj, "SaveUserPreferencesPreset") if resolve_obj else True,
|
|
15042
|
+
"load": _has_method(resolve_obj, "LoadUserPreferencesPreset") if resolve_obj else True,
|
|
15043
|
+
"delete": _has_method(resolve_obj, "DeleteUserPreferencesPreset") if resolve_obj else True,
|
|
15044
|
+
"import": _has_method(resolve_obj, "ImportUserPreferencesPreset") if resolve_obj else True,
|
|
15045
|
+
"export": _has_method(resolve_obj, "ExportUserPreferencesPreset") if resolve_obj else True,
|
|
14953
15046
|
},
|
|
14954
15047
|
},
|
|
14955
15048
|
}
|
|
@@ -15248,6 +15341,7 @@ def _preset_lifecycle_probe(resolve_obj, project, p: Dict[str, Any]) -> Dict[str
|
|
|
15248
15341
|
"quick_export_presets": {"available": _has_method(project, "GetQuickExportRenderPresets")},
|
|
15249
15342
|
"fairlight_presets": {"available": _has_method(resolve_obj, "GetFairlightPresets")},
|
|
15250
15343
|
"layout_presets": {
|
|
15344
|
+
"list": _has_method(resolve_obj, "GetLayoutPresetList"),
|
|
15251
15345
|
"save": _has_method(resolve_obj, "SaveLayoutPreset"),
|
|
15252
15346
|
"load": _has_method(resolve_obj, "LoadLayoutPreset"),
|
|
15253
15347
|
"update": _has_method(resolve_obj, "UpdateLayoutPreset"),
|
|
@@ -15260,6 +15354,16 @@ def _preset_lifecycle_probe(resolve_obj, project, p: Dict[str, Any]) -> Dict[str
|
|
|
15260
15354
|
"export_render": _has_method(resolve_obj, "ExportRenderPreset"),
|
|
15261
15355
|
"import_burnin": _has_method(resolve_obj, "ImportBurnInPreset"),
|
|
15262
15356
|
"export_burnin": _has_method(resolve_obj, "ExportBurnInPreset"),
|
|
15357
|
+
"list_burnin": _has_method(resolve_obj, "GetBurnInPresetList"),
|
|
15358
|
+
"delete_burnin": _has_method(resolve_obj, "DeleteBurnInPreset"),
|
|
15359
|
+
},
|
|
15360
|
+
"user_preferences_presets": {
|
|
15361
|
+
"list": _has_method(resolve_obj, "GetUserPreferencesPresetList"),
|
|
15362
|
+
"save": _has_method(resolve_obj, "SaveUserPreferencesPreset"),
|
|
15363
|
+
"load": _has_method(resolve_obj, "LoadUserPreferencesPreset"),
|
|
15364
|
+
"delete": _has_method(resolve_obj, "DeleteUserPreferencesPreset"),
|
|
15365
|
+
"import": _has_method(resolve_obj, "ImportUserPreferencesPreset"),
|
|
15366
|
+
"export": _has_method(resolve_obj, "ExportUserPreferencesPreset"),
|
|
15263
15367
|
},
|
|
15264
15368
|
}
|
|
15265
15369
|
try:
|
|
@@ -15641,6 +15745,9 @@ def project_manager(action: str, params: Optional[Dict[str, Any]] = None) -> Dic
|
|
|
15641
15745
|
|
|
15642
15746
|
Actions:
|
|
15643
15747
|
list() -> {projects}
|
|
15748
|
+
list_attributes() -> {projects: {name: {lastModifiedDate, creationDate, notes, liveCollaborationMode}}}
|
|
15749
|
+
— Resolve 21.0.4+. Per-project attributes for the current folder without
|
|
15750
|
+
loading any project.
|
|
15644
15751
|
get_current() -> {name, id}
|
|
15645
15752
|
create(name, media_location_path?) -> {success, name}
|
|
15646
15753
|
load(name) -> {success}
|
|
@@ -15722,6 +15829,11 @@ def project_manager(action: str, params: Optional[Dict[str, Any]] = None) -> Dic
|
|
|
15722
15829
|
return _project_boundary_report(r, pm, proj, p)
|
|
15723
15830
|
elif action == "list":
|
|
15724
15831
|
return {"projects": pm.GetProjectListInCurrentFolder()}
|
|
15832
|
+
elif action == "list_attributes":
|
|
15833
|
+
missing = _requires_method(pm, "GetProjectAttributesInCurrentFolder", "21.0.4")
|
|
15834
|
+
if missing:
|
|
15835
|
+
return missing
|
|
15836
|
+
return {"projects": _ser(pm.GetProjectAttributesInCurrentFolder() or {})}
|
|
15725
15837
|
elif action == "get_current":
|
|
15726
15838
|
proj = pm.GetCurrentProject()
|
|
15727
15839
|
return {"name": proj.GetName(), "id": proj.GetUniqueId()} if proj else _err("No project open")
|
|
@@ -15776,7 +15888,7 @@ def project_manager(action: str, params: Optional[Dict[str, Any]] = None) -> Dic
|
|
|
15776
15888
|
if not p.get("path"):
|
|
15777
15889
|
return _err("restore requires path")
|
|
15778
15890
|
return {"success": bool(pm.RestoreProject(p["path"], p.get("name")))}
|
|
15779
|
-
return _unknown(action, ["list","get_current","create","load","save","close","delete","import_project","export_project","archive","restore","lint","diff_to_spec","plan_spec","apply_spec", *_PROJECT_KERNEL_ACTIONS])
|
|
15891
|
+
return _unknown(action, ["list","list_attributes","get_current","create","load","save","close","delete","import_project","export_project","archive","restore","lint","diff_to_spec","plan_spec","apply_spec", *_PROJECT_KERNEL_ACTIONS])
|
|
15780
15892
|
|
|
15781
15893
|
|
|
15782
15894
|
# ═══════════════════════════════════════════════════════════════════════════════
|