davinci-resolve-mcp 2.66.0 → 2.67.1
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 +101 -0
- package/README.md +1 -1
- package/docs/SKILL.md +10 -0
- package/docs/kernels/render-deliver-kernel.md +46 -2
- package/docs/process/release-process.md +8 -1
- package/docs/reference/api-limitations.md +18 -1
- package/install.py +1 -1
- package/package.json +1 -1
- package/resolve-advanced/README.md +4 -1
- package/resolve-advanced/server/deliverable-spec-bridge.mjs +310 -0
- package/resolve-advanced/server/runner-apply-contract.mjs +16 -1
- package/resolve-advanced/server/tools/deliverable.mjs +20 -1
- package/src/granular/common.py +5 -1
- package/src/granular/project.py +22 -7
- package/src/server.py +271 -22
- package/src/utils/api_truth.py +43 -0
- package/src/utils/delivery_targets.py +846 -0
- package/src/utils/render_ids.py +68 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""Render format/codec id normalization — display names to the ids Resolve wants.
|
|
2
|
+
|
|
3
|
+
`Project.GetRenderFormats()` returns ``{display_name: format_id}`` (e.g.
|
|
4
|
+
``{"QuickTime": "mov"}``) and `Project.GetRenderCodecs(format_id)` returns
|
|
5
|
+
``{display_name: codec_id}`` (e.g. ``{"Apple ProRes 422 HQ": "ProRes422HQ"}``).
|
|
6
|
+
But `GetRenderCodecs`, `GetRenderResolutions` and `SetCurrentRenderFormatAndCodec`
|
|
7
|
+
all expect the **id**, so passing the label the user actually sees in the UI is
|
|
8
|
+
silently rejected.
|
|
9
|
+
|
|
10
|
+
The format half of this was issue #59. The codec half hid longer because for
|
|
11
|
+
``mp4`` the label and id are identical (``{"H.264": "H.264"}``), so the common web
|
|
12
|
+
case works by coincidence; only formats where they diverge — QuickTime/ProRes,
|
|
13
|
+
i.e. every professional master — actually break.
|
|
14
|
+
|
|
15
|
+
These live here rather than in `server.py` so the compound and granular servers
|
|
16
|
+
share one implementation. The format fix originally landed only in `server.py`
|
|
17
|
+
and never reached `src/granular/project.py`; a shared module is what stops that
|
|
18
|
+
recurring.
|
|
19
|
+
|
|
20
|
+
Both resolvers **normalize, they do not validate**: an unrecognized value passes
|
|
21
|
+
through unchanged for Resolve to reject. Callers that need a hard failure must
|
|
22
|
+
check the Resolve return value (see `_prepare_render_job`, which refuses to queue
|
|
23
|
+
a job when `SetCurrentRenderFormatAndCodec` returns False).
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
from typing import Any, Dict, Optional
|
|
29
|
+
|
|
30
|
+
__all__ = [
|
|
31
|
+
"render_format_id_from_formats",
|
|
32
|
+
"render_codec_id_from_codecs",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _match_by_label_or_id(mapping: Dict[Any, Any], value: str) -> Optional[str]:
|
|
37
|
+
"""Case-insensitive match of `value` against either side of a {label: id} map."""
|
|
38
|
+
needle = value.lower()
|
|
39
|
+
for label, identifier in mapping.items():
|
|
40
|
+
label_text = str(label)
|
|
41
|
+
id_text = str(identifier)
|
|
42
|
+
if label_text.lower() == needle:
|
|
43
|
+
return id_text or value
|
|
44
|
+
if id_text.lower() == needle:
|
|
45
|
+
return id_text
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def render_format_id_from_formats(formats: Any, fmt: str) -> str:
|
|
50
|
+
"""Normalize a render format display name/extension to its format id."""
|
|
51
|
+
if not isinstance(fmt, str) or not fmt or not isinstance(formats, dict):
|
|
52
|
+
return fmt
|
|
53
|
+
if fmt in formats:
|
|
54
|
+
return formats.get(fmt) or fmt
|
|
55
|
+
if fmt in formats.values():
|
|
56
|
+
return fmt
|
|
57
|
+
return _match_by_label_or_id(formats, fmt) or fmt
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def render_codec_id_from_codecs(codecs: Any, codec: str) -> str:
|
|
61
|
+
"""Normalize a render codec display name to its codec id."""
|
|
62
|
+
if not isinstance(codec, str) or not codec or not isinstance(codecs, dict):
|
|
63
|
+
return codec
|
|
64
|
+
if codec in codecs:
|
|
65
|
+
return codecs.get(codec) or codec
|
|
66
|
+
if codec in codecs.values():
|
|
67
|
+
return codec
|
|
68
|
+
return _match_by_label_or_id(codecs, codec) or codec
|