davinci-resolve-mcp 2.63.2 → 2.65.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 +81 -0
- package/README.md +1 -1
- package/docs/SKILL.md +8 -2
- package/docs/guides/media-analysis-guide.md +17 -0
- package/docs/install.md +23 -1
- package/install.py +30 -3
- package/package.json +1 -1
- package/scripts/doctor.py +73 -15
- package/src/analysis_dashboard.py +156 -18
- package/src/control_panel_i18n.py +780 -0
- package/src/granular/common.py +4 -3
- package/src/server.py +3 -2
- package/src/utils/media_analysis.py +146 -3
- package/src/utils/resolve_connection.py +46 -13
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,87 @@
|
|
|
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.65.0
|
|
6
|
+
|
|
7
|
+
Bundles two community contributions from @double2tea: an optional HTTP
|
|
8
|
+
transcription backend and a localized, build-aware control panel. Both are
|
|
9
|
+
opt-in and change no default behavior — with neither configured, existing
|
|
10
|
+
transcription backends and the English panel work exactly as before.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **MLX Audio Router transcription backend** (PR #95, @double2tea) — an optional
|
|
15
|
+
HTTP transcription backend that runs outside the Resolve MCP Python
|
|
16
|
+
environment. Enabled only when `DAVINCI_RESOLVE_MCP_MLX_AUDIO_URL` is set and a
|
|
17
|
+
bounded `GET /health` probe succeeds; an optional
|
|
18
|
+
`DAVINCI_RESOLVE_MCP_MLX_AUDIO_MODEL` overrides the router's default model.
|
|
19
|
+
When configured and healthy it is preferred in transcription capability
|
|
20
|
+
ordering, and its response is normalized into the existing JSON/SRT/VTT
|
|
21
|
+
transcript artifacts. Standard-library only (`urllib`); the MCP server never
|
|
22
|
+
installs, starts, or downloads anything on the router's behalf, and existing
|
|
23
|
+
Whisper backends are untouched when no URL is set.
|
|
24
|
+
- **Control panel localization (English / Simplified Chinese)** (PR #96,
|
|
25
|
+
@double2tea) — a persistent language switch on the local control panel.
|
|
26
|
+
English remains the authored, canonical UI; the browser stores only the
|
|
27
|
+
selected locale in `localStorage` and the initial locale follows browser
|
|
28
|
+
preferences. Translation runs client-side over the DOM (text nodes plus
|
|
29
|
+
`aria-label`/`title`/`placeholder`) and is fully reversible; no server API or
|
|
30
|
+
persisted project data changes.
|
|
31
|
+
- **Build-aware AI console** (PR #96, @double2tea) — the Resolve AI console now
|
|
32
|
+
uses the runtime capability payload to disable actions the connected Resolve
|
|
33
|
+
build cannot execute, distinguishing "Requires Resolve 21+" from "Unavailable
|
|
34
|
+
on this build" and surfacing the Resolve 20 transcription methods
|
|
35
|
+
(`TranscribeAudio` / `ClearTranscription`). Narrow-screen navigation and the
|
|
36
|
+
mobile footer were also improved.
|
|
37
|
+
|
|
38
|
+
### Validation
|
|
39
|
+
|
|
40
|
+
- Static checks and drift guards pass; `tests/test_media_analysis.py` (110),
|
|
41
|
+
`tests/test_control_panel_i18n.py` + `tests/test_control_panel_ai_capabilities.py`
|
|
42
|
+
+ `tests/test_open_control_panel.py` (14) pass on the merged tree.
|
|
43
|
+
- No DaVinci Resolve scripting behavior changed: PR #95 is a self-contained
|
|
44
|
+
HTTP/stdlib backend gated behind an env var, and PR #96 changes only the
|
|
45
|
+
control panel's client-side HTML/JS. Live Resolve validation not required.
|
|
46
|
+
|
|
47
|
+
## What's New in v2.64.0
|
|
48
|
+
|
|
49
|
+
Adds opt-in support for DaVinci Resolve's **Network** external-scripting mode
|
|
50
|
+
(PR #91… correction: PR #94, by @double2tea), so the MCP can drive a Resolve
|
|
51
|
+
instance addressed by IP — including a Resolve running on the same machine with
|
|
52
|
+
`External scripting using = Network`. Contributed in PR #94 by @double2tea,
|
|
53
|
+
with two additional connection sites hardened during adoption. Local mode is
|
|
54
|
+
unchanged and remains the default.
|
|
55
|
+
|
|
56
|
+
### Added
|
|
57
|
+
|
|
58
|
+
- **Resolve Network scripting mode** — set `RESOLVE_SCRIPT_HOST` to the Resolve
|
|
59
|
+
host IP (`127.0.0.1` on the same machine) to route connections through
|
|
60
|
+
Resolve's explicit IP-targeted `scriptapp("Resolve", host, timeout)` overload.
|
|
61
|
+
`RESOLVE_SCRIPT_TIMEOUT` (positive finite seconds, default 5) bounds the
|
|
62
|
+
connection wait. When `RESOLVE_SCRIPT_HOST` is absent, the server uses the
|
|
63
|
+
one-argument Local discovery exactly as before. A shared `connect_resolve`
|
|
64
|
+
helper centralizes this behavior; the compound server, granular server,
|
|
65
|
+
analysis dashboard, `scripts/doctor.py`, and the installer's post-install
|
|
66
|
+
connection probe all route through it. The installer copies
|
|
67
|
+
`RESOLVE_SCRIPT_HOST`/`RESOLVE_SCRIPT_TIMEOUT` into generated client configs
|
|
68
|
+
when present in its environment.
|
|
69
|
+
- **`doctor.py` Network flags** — `python3 scripts/doctor.py --resolve-host
|
|
70
|
+
<ip> [--resolve-timeout <seconds>]` runs the read-only connection check
|
|
71
|
+
against a Network-mode host.
|
|
72
|
+
|
|
73
|
+
### Security
|
|
74
|
+
|
|
75
|
+
- Network scripting permits remote control of Resolve. Documentation (SKILL.md,
|
|
76
|
+
install.md) advises using Local mode when remote access is unnecessary, and
|
|
77
|
+
otherwise restricting access with host firewall and network controls.
|
|
78
|
+
|
|
79
|
+
### Validation
|
|
80
|
+
|
|
81
|
+
- Live-validated on DaVinci Resolve Studio 19.1.3.7: Local mode (one-argument
|
|
82
|
+
discovery) and Network mode (`--resolve-host 127.0.0.1 --resolve-timeout 8`)
|
|
83
|
+
both connect through the shared `connect_resolve` helper. PR author validated
|
|
84
|
+
against Studio 20.3.2.9 in Network mode. Full offline suite: 1514 tests.
|
|
85
|
+
|
|
5
86
|
## What's New in v2.63.2
|
|
6
87
|
|
|
7
88
|
Installer fix for Windows MSIX builds of Claude Desktop (issue #93, reported by
|
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)
|
package/docs/SKILL.md
CHANGED
|
@@ -14,8 +14,14 @@ session — projects, timelines, clips, color grading, Fusion compositions, audi
|
|
|
14
14
|
render queues, and more — through natural language.
|
|
15
15
|
|
|
16
16
|
DaVinci Resolve must be running with **Preferences > General > "External scripting
|
|
17
|
-
using"** set to **Local
|
|
18
|
-
|
|
17
|
+
using"** set to **Local**, or set to **Network** with `RESOLVE_SCRIPT_HOST`
|
|
18
|
+
configured to the Resolve host IP (use `127.0.0.1` on the same machine). The
|
|
19
|
+
server auto-launches Resolve if it is not running, but that first connection can
|
|
20
|
+
take up to 60 seconds.
|
|
21
|
+
|
|
22
|
+
Network scripting permits remote control of Resolve. Use Local mode when remote
|
|
23
|
+
access is unnecessary; otherwise restrict access with host firewall and network
|
|
24
|
+
controls.
|
|
19
25
|
|
|
20
26
|
**Session-start update note.** The first `resolve_control(action="get_version")`
|
|
21
27
|
of a session returns an `mcp` block with the cached update check
|
|
@@ -79,6 +79,23 @@ which ffmpeg && ffmpeg -version 2>&1 | head -1
|
|
|
79
79
|
which whisper 2>/dev/null || which whisper-cpp 2>/dev/null || python3 -c "import whisper" 2>/dev/null
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
+
An HTTP MLX Audio Router can be used without installing a transcription module
|
|
83
|
+
into the Resolve MCP Python environment:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
export DAVINCI_RESOLVE_MCP_MLX_AUDIO_URL=http://127.0.0.1:8000
|
|
87
|
+
# Optional: omit this to use the router's own default model.
|
|
88
|
+
export DAVINCI_RESOLVE_MCP_MLX_AUDIO_MODEL=mlx-community/Qwen3-ASR-1.7B-8bit
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The configured service must expose `GET /health`, returning JSON with
|
|
92
|
+
`{"status":"ok"}`, and `POST /stt`. The transcription request uses the local
|
|
93
|
+
source path and requests JSON output; the response must contain a `transcript`
|
|
94
|
+
string whose value is a JSON object with `text` and `segments`. The
|
|
95
|
+
[Audiobox MLX Audio Router](https://github.com/double2tea/Audiobox) implements
|
|
96
|
+
this contract. Model download behavior follows the existing
|
|
97
|
+
`allow_model_download` transcription option.
|
|
98
|
+
|
|
82
99
|
FFprobe is required. If missing:
|
|
83
100
|
- macOS: `brew install ffmpeg`
|
|
84
101
|
- Linux: `sudo apt install ffmpeg` or `sudo dnf install ffmpeg`
|
package/docs/install.md
CHANGED
|
@@ -7,7 +7,9 @@ This guide covers Resolve requirements, the universal installer, supported MCP c
|
|
|
7
7
|
- **DaVinci Resolve Studio** 18.5+ (macOS, Windows, or Linux) — the free edition does not support external scripting
|
|
8
8
|
- **Python 3.10+** (the MCP SDK requires 3.10). **3.10–3.12 is the lowest-risk
|
|
9
9
|
choice**; 3.13/3.14 also work on recent Resolve builds — see below
|
|
10
|
-
- DaVinci Resolve running with **Preferences > General > "External scripting using"**
|
|
10
|
+
- DaVinci Resolve running with **Preferences > General > "External scripting using"**
|
|
11
|
+
set to **Local**, or **Network** with `RESOLVE_SCRIPT_HOST` set to the Resolve
|
|
12
|
+
host IP (`127.0.0.1` when Resolve and the MCP run on the same machine)
|
|
11
13
|
|
|
12
14
|
> **Python 3.13 / 3.14:** these are **allowed** — setup will use them and warn.
|
|
13
15
|
> Python 3.14 is verified working against DaVinci Resolve Studio 20.3.2. On
|
|
@@ -170,6 +172,26 @@ If you prefer to set things up yourself, add to your MCP client config:
|
|
|
170
172
|
|
|
171
173
|
On Windows, installer-generated configs also include `PYTHONHOME`. That scopes Resolve's Python binding to the selected interpreter and avoids the Resolve 20.3 multi-Python crash reported in [Issue #26](https://github.com/samuelgursky/davinci-resolve-mcp/issues/26).
|
|
172
174
|
|
|
175
|
+
For Resolve's **Network** scripting mode, add
|
|
176
|
+
`"RESOLVE_SCRIPT_HOST": "127.0.0.1"` to the `env` object above, replacing the
|
|
177
|
+
address when Resolve runs on another host. When this variable is present, the
|
|
178
|
+
server uses Resolve's explicit IP-targeted `scriptapp` call with a bounded
|
|
179
|
+
connection timeout. Set `RESOLVE_SCRIPT_TIMEOUT` to override the default
|
|
180
|
+
five-second timeout with a positive finite number of seconds. The installer
|
|
181
|
+
includes both values in generated client configs when they are present in its
|
|
182
|
+
environment.
|
|
183
|
+
|
|
184
|
+
Network scripting permits remote control of Resolve. Prefer Local mode when
|
|
185
|
+
remote access is unnecessary; otherwise restrict access with host firewall and
|
|
186
|
+
network controls.
|
|
187
|
+
|
|
188
|
+
Run the read-only doctor against Network mode explicitly:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
python3 scripts/doctor.py --resolve-host 127.0.0.1
|
|
192
|
+
python3 scripts/doctor.py --resolve-host resolve.example.test --resolve-timeout 12.5
|
|
193
|
+
```
|
|
194
|
+
|
|
173
195
|
When the compound server is running, `resolve_control(action="get_version")`
|
|
174
196
|
includes the local MCP version, the last update-check status, and the current
|
|
175
197
|
update decision under the `mcp` key. `resolve_control(action="mcp_update_status",
|
package/install.py
CHANGED
|
@@ -15,6 +15,7 @@ Usage:
|
|
|
15
15
|
|
|
16
16
|
import argparse
|
|
17
17
|
import json
|
|
18
|
+
import math
|
|
18
19
|
import os
|
|
19
20
|
import platform
|
|
20
21
|
import shutil
|
|
@@ -35,7 +36,7 @@ from src.utils.update_check import (
|
|
|
35
36
|
|
|
36
37
|
# ─── Version ──────────────────────────────────────────────────────────────────
|
|
37
38
|
|
|
38
|
-
VERSION = "2.
|
|
39
|
+
VERSION = "2.65.0"
|
|
39
40
|
# Only hard floor: mcp[cli] requires Python 3.10+. There is no upper bound —
|
|
40
41
|
# Resolve's scripting bridge loads into newer interpreters on recent builds
|
|
41
42
|
# (Python 3.14 verified against Resolve Studio 20.3.2). Older Resolve builds
|
|
@@ -474,6 +475,13 @@ def build_server_env(python_path, api_path, lib_path, system=SYSTEM, python_home
|
|
|
474
475
|
if system == "Windows":
|
|
475
476
|
env["PYTHONHOME"] = str(python_home or get_python_base_install(python_path))
|
|
476
477
|
|
|
478
|
+
host = os.environ.get("RESOLVE_SCRIPT_HOST")
|
|
479
|
+
if host:
|
|
480
|
+
env["RESOLVE_SCRIPT_HOST"] = host
|
|
481
|
+
timeout = os.environ.get("RESOLVE_SCRIPT_TIMEOUT")
|
|
482
|
+
if timeout:
|
|
483
|
+
env["RESOLVE_SCRIPT_TIMEOUT"] = timeout
|
|
484
|
+
|
|
477
485
|
return env
|
|
478
486
|
|
|
479
487
|
|
|
@@ -810,12 +818,21 @@ def verify_resolve_connection(python_path, api_path, lib_path):
|
|
|
810
818
|
|
|
811
819
|
env = {**os.environ, **build_server_env(python_path, api_path, lib_path)}
|
|
812
820
|
modules_path = env["PYTHONPATH"]
|
|
821
|
+
repo_root = str(Path(__file__).resolve().parent)
|
|
822
|
+
# Route through connect_resolve so Network mode (RESOLVE_SCRIPT_HOST, propagated
|
|
823
|
+
# into env by build_server_env) uses the explicit IP-targeted overload. Fall
|
|
824
|
+
# back to Local-mode discovery if the helper cannot be imported.
|
|
813
825
|
test_script = textwrap.dedent(f"""\
|
|
814
826
|
import sys
|
|
815
827
|
sys.path.insert(0, {modules_path!r})
|
|
828
|
+
sys.path.insert(0, {repo_root!r})
|
|
816
829
|
try:
|
|
817
830
|
import DaVinciResolveScript as dvr
|
|
818
|
-
|
|
831
|
+
try:
|
|
832
|
+
from src.utils.resolve_connection import connect_resolve
|
|
833
|
+
except Exception:
|
|
834
|
+
connect_resolve = lambda mod: mod.scriptapp('Resolve')
|
|
835
|
+
resolve = connect_resolve(dvr)
|
|
819
836
|
if resolve:
|
|
820
837
|
name = resolve.GetProductName()
|
|
821
838
|
ver = resolve.GetVersionString()
|
|
@@ -828,12 +845,22 @@ def verify_resolve_connection(python_path, api_path, lib_path):
|
|
|
828
845
|
print(f"ERROR: {{e}}")
|
|
829
846
|
""")
|
|
830
847
|
|
|
848
|
+
process_timeout = 10.0
|
|
849
|
+
configured_timeout = env.get("RESOLVE_SCRIPT_TIMEOUT")
|
|
850
|
+
if configured_timeout:
|
|
851
|
+
try:
|
|
852
|
+
network_timeout = float(configured_timeout)
|
|
853
|
+
if math.isfinite(network_timeout) and network_timeout > 0:
|
|
854
|
+
process_timeout = max(process_timeout, network_timeout + 2)
|
|
855
|
+
except ValueError:
|
|
856
|
+
pass
|
|
857
|
+
|
|
831
858
|
try:
|
|
832
859
|
result = subprocess.run(
|
|
833
860
|
[str(python_path), "-c", test_script],
|
|
834
861
|
capture_output=True,
|
|
835
862
|
text=True,
|
|
836
|
-
timeout=
|
|
863
|
+
timeout=process_timeout,
|
|
837
864
|
env=env,
|
|
838
865
|
)
|
|
839
866
|
output = result.stdout.strip() or result.stderr.strip()
|
package/package.json
CHANGED
package/scripts/doctor.py
CHANGED
|
@@ -7,16 +7,19 @@ mutating anything. Prints OK/WARN/FAIL lines (or JSON with --json) and exits
|
|
|
7
7
|
nonzero only when a FAIL is present.
|
|
8
8
|
|
|
9
9
|
Run: `python3 scripts/doctor.py`
|
|
10
|
+
Network mode: `python3 scripts/doctor.py --resolve-host 127.0.0.1`
|
|
10
11
|
|
|
11
12
|
Overridable via environment: DAVINCI_MCP_REPO, DAVINCI_MCP_PYTHON,
|
|
12
13
|
CODEX_HOME, CLAUDE_DESKTOP_CONFIG, RESOLVE_APP, RESOLVE_SCRIPT_API,
|
|
13
|
-
RESOLVE_SCRIPT_MODULES, RESOLVE_SCRIPT_LIB
|
|
14
|
+
RESOLVE_SCRIPT_MODULES, RESOLVE_SCRIPT_LIB, RESOLVE_SCRIPT_HOST,
|
|
15
|
+
RESOLVE_SCRIPT_TIMEOUT.
|
|
14
16
|
"""
|
|
15
17
|
|
|
16
18
|
from __future__ import annotations
|
|
17
19
|
|
|
18
20
|
import argparse
|
|
19
21
|
import json
|
|
22
|
+
import math
|
|
20
23
|
import os
|
|
21
24
|
import re
|
|
22
25
|
import subprocess
|
|
@@ -128,26 +131,41 @@ def git_head() -> str:
|
|
|
128
131
|
return head["stdout"] or head["stderr"] or "git describe produced no output"
|
|
129
132
|
|
|
130
133
|
|
|
131
|
-
def resolve_probe(
|
|
134
|
+
def resolve_probe(
|
|
135
|
+
resolve_host: str | None = None,
|
|
136
|
+
resolve_timeout: float | None = None,
|
|
137
|
+
) -> dict[str, Any]:
|
|
132
138
|
if not PYTHON.exists():
|
|
133
139
|
return {"import_ok": False, "error": f"{PYTHON} is missing"}
|
|
134
140
|
|
|
135
141
|
code = f"""
|
|
136
142
|
import json
|
|
137
143
|
import sys
|
|
144
|
+
sys.path.insert(0, {str(REPO)!r})
|
|
138
145
|
sys.path.insert(0, {str(RESOLVE_MODULES)!r})
|
|
139
146
|
try:
|
|
140
147
|
import DaVinciResolveScript as dvr
|
|
141
|
-
|
|
142
|
-
payload = {{
|
|
143
|
-
"import_ok": True,
|
|
144
|
-
"module": getattr(dvr, "__file__", None),
|
|
145
|
-
"resolve_connected": bool(resolve),
|
|
146
|
-
"product": resolve.GetProductName() if resolve else None,
|
|
147
|
-
"version": resolve.GetVersionString() if resolve else None,
|
|
148
|
-
}}
|
|
148
|
+
from src.utils.resolve_connection import connect_resolve
|
|
149
149
|
except Exception as exc:
|
|
150
150
|
payload = {{"import_ok": False, "error": repr(exc)}}
|
|
151
|
+
else:
|
|
152
|
+
try:
|
|
153
|
+
resolve = connect_resolve(dvr)
|
|
154
|
+
except Exception as exc:
|
|
155
|
+
payload = {{
|
|
156
|
+
"import_ok": True,
|
|
157
|
+
"module": getattr(dvr, "__file__", None),
|
|
158
|
+
"resolve_connected": False,
|
|
159
|
+
"connection_error": repr(exc),
|
|
160
|
+
}}
|
|
161
|
+
else:
|
|
162
|
+
payload = {{
|
|
163
|
+
"import_ok": True,
|
|
164
|
+
"module": getattr(dvr, "__file__", None),
|
|
165
|
+
"resolve_connected": bool(resolve),
|
|
166
|
+
"product": resolve.GetProductName() if resolve else None,
|
|
167
|
+
"version": resolve.GetVersionString() if resolve else None,
|
|
168
|
+
}}
|
|
151
169
|
print(json.dumps(payload))
|
|
152
170
|
"""
|
|
153
171
|
env = {
|
|
@@ -156,7 +174,26 @@ print(json.dumps(payload))
|
|
|
156
174
|
"RESOLVE_SCRIPT_LIB": str(RESOLVE_LIB),
|
|
157
175
|
"PYTHONPATH": str(RESOLVE_MODULES),
|
|
158
176
|
}
|
|
159
|
-
|
|
177
|
+
if resolve_host is not None:
|
|
178
|
+
env["RESOLVE_SCRIPT_HOST"] = resolve_host
|
|
179
|
+
if resolve_timeout is not None:
|
|
180
|
+
env["RESOLVE_SCRIPT_TIMEOUT"] = str(resolve_timeout)
|
|
181
|
+
process_timeout = 12.0
|
|
182
|
+
configured_timeout = env.get("RESOLVE_SCRIPT_TIMEOUT")
|
|
183
|
+
if configured_timeout:
|
|
184
|
+
try:
|
|
185
|
+
network_timeout = float(configured_timeout)
|
|
186
|
+
if math.isfinite(network_timeout) and network_timeout > 0:
|
|
187
|
+
process_timeout = max(process_timeout, network_timeout + 2)
|
|
188
|
+
except ValueError:
|
|
189
|
+
pass
|
|
190
|
+
proc = subprocess.run(
|
|
191
|
+
[str(PYTHON), "-c", code],
|
|
192
|
+
capture_output=True,
|
|
193
|
+
text=True,
|
|
194
|
+
timeout=process_timeout,
|
|
195
|
+
env=env,
|
|
196
|
+
)
|
|
160
197
|
output = (proc.stdout or proc.stderr).strip()
|
|
161
198
|
try:
|
|
162
199
|
payload = json.loads(output)
|
|
@@ -166,7 +203,10 @@ print(json.dumps(payload))
|
|
|
166
203
|
return payload
|
|
167
204
|
|
|
168
205
|
|
|
169
|
-
def collect(
|
|
206
|
+
def collect(
|
|
207
|
+
resolve_host: str | None = None,
|
|
208
|
+
resolve_timeout: float | None = None,
|
|
209
|
+
) -> list[dict[str, str]]:
|
|
170
210
|
results: list[dict[str, str]] = []
|
|
171
211
|
|
|
172
212
|
check(results, "OK" if REPO.exists() else "FAIL", "MCP checkout", str(REPO))
|
|
@@ -186,18 +226,27 @@ def collect() -> list[dict[str, str]]:
|
|
|
186
226
|
pyver = run([str(PYTHON), "--version"]) if PYTHON.exists() else {"ok": False, "stdout": "", "stderr": "missing"}
|
|
187
227
|
check(results, "OK" if pyver["ok"] else "FAIL", "Python version", pyver["stdout"] or pyver["stderr"])
|
|
188
228
|
|
|
189
|
-
probe = resolve_probe()
|
|
229
|
+
probe = resolve_probe(resolve_host, resolve_timeout)
|
|
190
230
|
if probe.get("import_ok"):
|
|
191
231
|
check(results, "OK", "DaVinciResolveScript import", str(probe.get("module")))
|
|
192
232
|
if probe.get("resolve_connected"):
|
|
193
233
|
detail = f"{probe.get('product')} {probe.get('version')}"
|
|
194
234
|
check(results, "OK", "Resolve scripting connection", detail)
|
|
235
|
+
elif probe.get("connection_error"):
|
|
236
|
+
check(
|
|
237
|
+
results,
|
|
238
|
+
"FAIL",
|
|
239
|
+
"Resolve scripting connection",
|
|
240
|
+
str(probe["connection_error"]),
|
|
241
|
+
)
|
|
195
242
|
else:
|
|
196
243
|
check(
|
|
197
244
|
results,
|
|
198
245
|
"WARN",
|
|
199
246
|
"Resolve scripting connection",
|
|
200
|
-
|
|
247
|
+
"Module import worked, but scriptapp returned no object. Use "
|
|
248
|
+
"External scripting = Local, or Network with --resolve-host "
|
|
249
|
+
"set to the Resolve host IP, then restart Resolve.",
|
|
201
250
|
)
|
|
202
251
|
else:
|
|
203
252
|
check(results, "FAIL", "DaVinciResolveScript import", str(probe.get("error")))
|
|
@@ -211,9 +260,18 @@ def collect() -> list[dict[str, str]]:
|
|
|
211
260
|
def main() -> int:
|
|
212
261
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
213
262
|
parser.add_argument("--json", action="store_true", help="Print machine-readable JSON")
|
|
263
|
+
parser.add_argument(
|
|
264
|
+
"--resolve-host",
|
|
265
|
+
help="Resolve host IP for Network scripting mode",
|
|
266
|
+
)
|
|
267
|
+
parser.add_argument(
|
|
268
|
+
"--resolve-timeout",
|
|
269
|
+
type=float,
|
|
270
|
+
help="Network connection timeout in seconds (default: 5)",
|
|
271
|
+
)
|
|
214
272
|
args = parser.parse_args()
|
|
215
273
|
|
|
216
|
-
results = collect()
|
|
274
|
+
results = collect(args.resolve_host, args.resolve_timeout)
|
|
217
275
|
if args.json:
|
|
218
276
|
print(json.dumps({"checks": results}, indent=2))
|
|
219
277
|
else:
|