davinci-resolve-mcp 2.23.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/AGENTS.md +85 -0
- package/CHANGELOG.md +802 -0
- package/CLAUDE.md +15 -0
- package/LICENSE +21 -0
- package/README.md +159 -0
- package/SECURITY.md +53 -0
- package/bin/davinci-resolve-mcp.mjs +376 -0
- package/docs/README.md +56 -0
- package/docs/SKILL.md +1145 -0
- package/docs/authoring/fuse-dctl-authoring.md +242 -0
- package/docs/authoring/script-plugin-authoring.md +195 -0
- package/docs/contributing.md +82 -0
- package/docs/guides/color-decision-guide.md +387 -0
- package/docs/guides/editorial-decision-guide.md +136 -0
- package/docs/guides/media-analysis-guide.md +615 -0
- package/docs/guides/multicam-setup-guide.md +138 -0
- package/docs/install.md +198 -0
- package/docs/integrations/workflow-integrations.md +120 -0
- package/docs/kernels/README.md +28 -0
- package/docs/kernels/audio-fairlight-kernel.md +86 -0
- package/docs/kernels/color-grade-kernel.md +103 -0
- package/docs/kernels/extension-authoring-kernel.md +101 -0
- package/docs/kernels/fusion-composition-kernel.md +91 -0
- package/docs/kernels/media-pool-ingest-kernel.md +147 -0
- package/docs/kernels/project-lifecycle-kernel.md +120 -0
- package/docs/kernels/render-deliver-kernel.md +92 -0
- package/docs/kernels/review-annotation-kernel.md +110 -0
- package/docs/kernels/timeline-conform-interchange-kernel.md +99 -0
- package/docs/kernels/timeline-edit-kernel.md +189 -0
- package/docs/notes/codec-plugin-notes.md +136 -0
- package/docs/notes/dctl-notes.md +234 -0
- package/docs/notes/fusion-template-notes.md +136 -0
- package/docs/notes/lut-notes.md +136 -0
- package/docs/notes/openfx-notes.md +120 -0
- package/docs/process/release-process.md +152 -0
- package/docs/reference/api-coverage.md +488 -0
- package/docs/reference/resolve_scripting_api.txt +1012 -0
- package/examples/README.md +53 -0
- package/examples/markers/README.md +81 -0
- package/examples/media/README.md +94 -0
- package/examples/timeline/README.md +98 -0
- package/install.py +1196 -0
- package/package.json +52 -0
- package/scripts/audit_api_parity.py +275 -0
- package/scripts/live_media_analysis_polish_probe.py +65 -0
- package/src/__init__.py +3 -0
- package/src/analysis_dashboard.py +4936 -0
- package/src/control_panel.py +13 -0
- package/src/granular/__init__.py +17 -0
- package/src/granular/common.py +727 -0
- package/src/granular/folder.py +287 -0
- package/src/granular/gallery.py +306 -0
- package/src/granular/graph.py +309 -0
- package/src/granular/media_pool.py +679 -0
- package/src/granular/media_pool_item.py +852 -0
- package/src/granular/media_storage.py +179 -0
- package/src/granular/project.py +1594 -0
- package/src/granular/resolve_control.py +521 -0
- package/src/granular/timeline.py +1074 -0
- package/src/granular/timeline_item.py +2251 -0
- package/src/resolve_mcp_server.py +43 -0
- package/src/server.py +15691 -0
- package/src/utils/__init__.py +3 -0
- package/src/utils/app_control.py +319 -0
- package/src/utils/audio_fairlight_live_probe.py +263 -0
- package/src/utils/cdl.py +20 -0
- package/src/utils/cloud_operations.py +192 -0
- package/src/utils/color_grade_live_probe.py +444 -0
- package/src/utils/dctl_templates.py +368 -0
- package/src/utils/extension_authoring_live_probe.py +292 -0
- package/src/utils/fuse_templates.py +1968 -0
- package/src/utils/fusion_composition_live_probe.py +284 -0
- package/src/utils/layout_presets.py +333 -0
- package/src/utils/mcp_stdio.py +32 -0
- package/src/utils/media_analysis.py +3618 -0
- package/src/utils/media_analysis_jobs.py +796 -0
- package/src/utils/media_pool_ingest_live_probe.py +592 -0
- package/src/utils/multicam.py +393 -0
- package/src/utils/object_inspection.py +287 -0
- package/src/utils/platform.py +157 -0
- package/src/utils/project_lifecycle_live_probe.py +376 -0
- package/src/utils/project_properties.py +601 -0
- package/src/utils/render_deliver_live_probe.py +384 -0
- package/src/utils/resolve_connection.py +77 -0
- package/src/utils/review_annotation_live_probe.py +352 -0
- package/src/utils/script_templates.py +1193 -0
- package/src/utils/sync_detection.py +887 -0
- package/src/utils/timeline_conform_live_probe.py +280 -0
- package/src/utils/timeline_kernel_live_probe.py +1091 -0
- package/src/utils/timeline_kernel_probe.py +185 -0
- package/src/utils/timeline_title_text.py +87 -0
- package/src/utils/update_check.py +610 -0
|
@@ -0,0 +1,601 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
DaVinci Resolve MCP Server - Project Properties Utilities
|
|
4
|
+
|
|
5
|
+
This module provides functions for working with DaVinci Resolve project properties:
|
|
6
|
+
- Getting and setting project settings
|
|
7
|
+
- Managing project metadata
|
|
8
|
+
- Handling project-specific configurations
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import logging
|
|
13
|
+
import json
|
|
14
|
+
from typing import Dict, List, Any, Optional, Union
|
|
15
|
+
|
|
16
|
+
# Configure logging
|
|
17
|
+
logger = logging.getLogger("davinci-resolve-mcp.project_properties")
|
|
18
|
+
|
|
19
|
+
# Common project properties with their types
|
|
20
|
+
PROJECT_PROPERTY_TYPES = {
|
|
21
|
+
# Timeline settings
|
|
22
|
+
"timelineFrameRate": "float",
|
|
23
|
+
"timelineResolutionWidth": "int",
|
|
24
|
+
"timelineResolutionHeight": "int",
|
|
25
|
+
"timelineOutputResolutionWidth": "int",
|
|
26
|
+
"timelineOutputResolutionHeight": "int",
|
|
27
|
+
"timelineInterlaceProcessing": "int",
|
|
28
|
+
|
|
29
|
+
# Color settings
|
|
30
|
+
"colorScienceMode": "int",
|
|
31
|
+
"timelineColorSpace": "string",
|
|
32
|
+
"timelineGamma": "string",
|
|
33
|
+
"inputDRT": "string",
|
|
34
|
+
"outputDRT": "string",
|
|
35
|
+
|
|
36
|
+
# Image processing
|
|
37
|
+
"superScaleEnabled": "bool",
|
|
38
|
+
"superScaleQuality": "int",
|
|
39
|
+
"noiseReductionEnabled": "bool",
|
|
40
|
+
"noiseReductionMode": "int",
|
|
41
|
+
"noiseReductionValue": "float",
|
|
42
|
+
|
|
43
|
+
# Format settings
|
|
44
|
+
"timelineAudioSampleRate": "int",
|
|
45
|
+
"timelineAudioBitDepth": "int",
|
|
46
|
+
"mediaPoolRelativePath": "bool",
|
|
47
|
+
|
|
48
|
+
# Cache settings
|
|
49
|
+
"CacheMode": "int",
|
|
50
|
+
"CacheClipMode": "int",
|
|
51
|
+
"OptimizedMediaMode": "int",
|
|
52
|
+
"ProxyMode": "int",
|
|
53
|
+
"ProxyQuality": "int",
|
|
54
|
+
"TimelineCacheMode": "int",
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
def get_all_project_properties(project_obj) -> Dict[str, Any]:
|
|
58
|
+
"""
|
|
59
|
+
Get all project properties and their values.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
project_obj: Project object from DaVinci Resolve API
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Dictionary of all available project properties and their values
|
|
66
|
+
"""
|
|
67
|
+
if project_obj is None:
|
|
68
|
+
return {"error": "Invalid project object"}
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
# Get all settings using empty string as key
|
|
72
|
+
all_settings = project_obj.GetSetting('')
|
|
73
|
+
|
|
74
|
+
# Check if we got a valid response
|
|
75
|
+
if all_settings is None or not isinstance(all_settings, dict):
|
|
76
|
+
logger.warning("GetSetting('') did not return expected dictionary")
|
|
77
|
+
|
|
78
|
+
# Fall back to getting known properties individually
|
|
79
|
+
properties = {}
|
|
80
|
+
for prop_name in PROJECT_PROPERTY_TYPES.keys():
|
|
81
|
+
try:
|
|
82
|
+
value = project_obj.GetSetting(prop_name)
|
|
83
|
+
properties[prop_name] = value
|
|
84
|
+
except Exception as e:
|
|
85
|
+
logger.debug(f"Error getting property {prop_name}: {str(e)}")
|
|
86
|
+
|
|
87
|
+
return properties
|
|
88
|
+
else:
|
|
89
|
+
# Return all settings
|
|
90
|
+
return all_settings
|
|
91
|
+
|
|
92
|
+
except Exception as e:
|
|
93
|
+
logger.error(f"Error getting project properties: {str(e)}")
|
|
94
|
+
return {"error": f"Error getting project properties: {str(e)}"}
|
|
95
|
+
|
|
96
|
+
def get_project_property(project_obj, property_name: str) -> Any:
|
|
97
|
+
"""
|
|
98
|
+
Get a specific project property value.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
project_obj: Project object from DaVinci Resolve API
|
|
102
|
+
property_name: Name of the property to get
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
Value of the specified property or error information
|
|
106
|
+
"""
|
|
107
|
+
if project_obj is None:
|
|
108
|
+
return {"error": "Invalid project object"}
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
# Get the specified property
|
|
112
|
+
value = project_obj.GetSetting(property_name)
|
|
113
|
+
|
|
114
|
+
# Properly convert the value based on expected type
|
|
115
|
+
if property_name in PROJECT_PROPERTY_TYPES:
|
|
116
|
+
property_type = PROJECT_PROPERTY_TYPES[property_name]
|
|
117
|
+
|
|
118
|
+
if property_type == "int" and not isinstance(value, int):
|
|
119
|
+
try:
|
|
120
|
+
value = int(value)
|
|
121
|
+
except (ValueError, TypeError):
|
|
122
|
+
# Keep Resolve's raw value when it cannot be safely coerced.
|
|
123
|
+
pass
|
|
124
|
+
elif property_type == "float" and not isinstance(value, float):
|
|
125
|
+
try:
|
|
126
|
+
value = float(value)
|
|
127
|
+
except (ValueError, TypeError):
|
|
128
|
+
# Keep Resolve's raw value when it cannot be safely coerced.
|
|
129
|
+
pass
|
|
130
|
+
elif property_type == "bool" and not isinstance(value, bool):
|
|
131
|
+
# Convert string representations of boolean
|
|
132
|
+
if isinstance(value, str):
|
|
133
|
+
value = value.lower() in ("true", "yes", "1", "on")
|
|
134
|
+
|
|
135
|
+
return value
|
|
136
|
+
except Exception as e:
|
|
137
|
+
logger.error(f"Error getting project property {property_name}: {str(e)}")
|
|
138
|
+
return {"error": f"Error getting project property: {str(e)}"}
|
|
139
|
+
|
|
140
|
+
def set_project_property(project_obj, property_name: str, property_value: Any) -> bool:
|
|
141
|
+
"""
|
|
142
|
+
Set a project property value.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
project_obj: Project object from DaVinci Resolve API
|
|
146
|
+
property_name: Name of the property to set
|
|
147
|
+
property_value: Value to set for the property
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
True if successful, False otherwise
|
|
151
|
+
"""
|
|
152
|
+
if project_obj is None:
|
|
153
|
+
return False
|
|
154
|
+
|
|
155
|
+
try:
|
|
156
|
+
# Handle type conversion based on expected property type
|
|
157
|
+
if property_name in PROJECT_PROPERTY_TYPES:
|
|
158
|
+
property_type = PROJECT_PROPERTY_TYPES[property_name]
|
|
159
|
+
|
|
160
|
+
if property_type == "int":
|
|
161
|
+
try:
|
|
162
|
+
property_value = int(property_value)
|
|
163
|
+
except (ValueError, TypeError):
|
|
164
|
+
logger.warning(f"Invalid integer value for property {property_name}: {property_value}")
|
|
165
|
+
|
|
166
|
+
elif property_type == "float":
|
|
167
|
+
try:
|
|
168
|
+
property_value = float(property_value)
|
|
169
|
+
except (ValueError, TypeError):
|
|
170
|
+
logger.warning(f"Invalid float value for property {property_name}: {property_value}")
|
|
171
|
+
|
|
172
|
+
elif property_type == "bool":
|
|
173
|
+
if isinstance(property_value, str):
|
|
174
|
+
property_value = property_value.lower() in ("true", "yes", "1", "on")
|
|
175
|
+
property_value = bool(property_value)
|
|
176
|
+
|
|
177
|
+
# Set the property
|
|
178
|
+
return project_obj.SetSetting(property_name, property_value)
|
|
179
|
+
|
|
180
|
+
except Exception as e:
|
|
181
|
+
logger.error(f"Error setting project property {property_name}: {str(e)}")
|
|
182
|
+
return False
|
|
183
|
+
|
|
184
|
+
def get_timeline_format_settings(project_obj) -> Dict[str, Any]:
|
|
185
|
+
"""
|
|
186
|
+
Get timeline format settings for the project.
|
|
187
|
+
|
|
188
|
+
Args:
|
|
189
|
+
project_obj: Project object from DaVinci Resolve API
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
Dictionary of timeline format settings
|
|
193
|
+
"""
|
|
194
|
+
if project_obj is None:
|
|
195
|
+
return {"error": "Invalid project object"}
|
|
196
|
+
|
|
197
|
+
try:
|
|
198
|
+
# Get relevant timeline format settings
|
|
199
|
+
settings = {}
|
|
200
|
+
format_properties = [
|
|
201
|
+
"timelineFrameRate",
|
|
202
|
+
"timelineResolutionWidth",
|
|
203
|
+
"timelineResolutionHeight",
|
|
204
|
+
"timelineOutputResolutionWidth",
|
|
205
|
+
"timelineOutputResolutionHeight",
|
|
206
|
+
"timelineInterlaceProcessing"
|
|
207
|
+
]
|
|
208
|
+
|
|
209
|
+
for prop in format_properties:
|
|
210
|
+
settings[prop] = get_project_property(project_obj, prop)
|
|
211
|
+
|
|
212
|
+
# Add frame rate details
|
|
213
|
+
if "timelineFrameRate" in settings:
|
|
214
|
+
fps = settings["timelineFrameRate"]
|
|
215
|
+
|
|
216
|
+
# Check if it's a drop frame rate
|
|
217
|
+
is_drop_frame = False
|
|
218
|
+
if isinstance(fps, (int, float)):
|
|
219
|
+
# Common drop frame rates: 29.97, 59.94
|
|
220
|
+
is_drop_frame = abs(fps - 29.97) < 0.01 or abs(fps - 59.94) < 0.01
|
|
221
|
+
|
|
222
|
+
settings["isDropFrame"] = is_drop_frame
|
|
223
|
+
|
|
224
|
+
# Add resolution name if standard
|
|
225
|
+
if "timelineResolutionWidth" in settings and "timelineResolutionHeight" in settings:
|
|
226
|
+
width = settings["timelineResolutionWidth"]
|
|
227
|
+
height = settings["timelineResolutionHeight"]
|
|
228
|
+
|
|
229
|
+
# Determine common resolution names
|
|
230
|
+
resolution_name = None
|
|
231
|
+
if width == 3840 and height == 2160:
|
|
232
|
+
resolution_name = "UHD 4K"
|
|
233
|
+
elif width == 1920 and height == 1080:
|
|
234
|
+
resolution_name = "FHD 1080p"
|
|
235
|
+
elif width == 1280 and height == 720:
|
|
236
|
+
resolution_name = "HD 720p"
|
|
237
|
+
elif width == 4096 and height in [2160, 2304]:
|
|
238
|
+
resolution_name = "DCI 4K"
|
|
239
|
+
elif width == 2048 and height in [1080, 1152]:
|
|
240
|
+
resolution_name = "DCI 2K"
|
|
241
|
+
|
|
242
|
+
if resolution_name:
|
|
243
|
+
settings["resolutionName"] = resolution_name
|
|
244
|
+
|
|
245
|
+
return settings
|
|
246
|
+
|
|
247
|
+
except Exception as e:
|
|
248
|
+
logger.error(f"Error getting timeline format settings: {str(e)}")
|
|
249
|
+
return {"error": f"Error getting timeline format settings: {str(e)}"}
|
|
250
|
+
|
|
251
|
+
def set_timeline_format(project_obj, width: int, height: int, frame_rate: float,
|
|
252
|
+
interlaced: bool = False) -> bool:
|
|
253
|
+
"""
|
|
254
|
+
Set timeline format (resolution and frame rate).
|
|
255
|
+
|
|
256
|
+
Args:
|
|
257
|
+
project_obj: Project object from DaVinci Resolve API
|
|
258
|
+
width: Timeline width in pixels
|
|
259
|
+
height: Timeline height in pixels
|
|
260
|
+
frame_rate: Timeline frame rate
|
|
261
|
+
interlaced: Whether the timeline should use interlaced processing
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
True if successful, False otherwise
|
|
265
|
+
"""
|
|
266
|
+
if project_obj is None:
|
|
267
|
+
return False
|
|
268
|
+
|
|
269
|
+
try:
|
|
270
|
+
# Set timeline format properties
|
|
271
|
+
success = True
|
|
272
|
+
|
|
273
|
+
# Set resolution
|
|
274
|
+
if not set_project_property(project_obj, "timelineResolutionWidth", width):
|
|
275
|
+
success = False
|
|
276
|
+
|
|
277
|
+
if not set_project_property(project_obj, "timelineResolutionHeight", height):
|
|
278
|
+
success = False
|
|
279
|
+
|
|
280
|
+
# Set frame rate
|
|
281
|
+
if not set_project_property(project_obj, "timelineFrameRate", frame_rate):
|
|
282
|
+
success = False
|
|
283
|
+
|
|
284
|
+
# Set interlaced processing
|
|
285
|
+
interlace_value = 1 if interlaced else 0
|
|
286
|
+
if not set_project_property(project_obj, "timelineInterlaceProcessing", interlace_value):
|
|
287
|
+
success = False
|
|
288
|
+
|
|
289
|
+
return success
|
|
290
|
+
|
|
291
|
+
except Exception as e:
|
|
292
|
+
logger.error(f"Error setting timeline format: {str(e)}")
|
|
293
|
+
return False
|
|
294
|
+
|
|
295
|
+
def get_superscale_settings(project_obj) -> Dict[str, Any]:
|
|
296
|
+
"""
|
|
297
|
+
Get SuperScale settings for the project.
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
project_obj: Project object from DaVinci Resolve API
|
|
301
|
+
|
|
302
|
+
Returns:
|
|
303
|
+
Dictionary of SuperScale settings
|
|
304
|
+
"""
|
|
305
|
+
if project_obj is None:
|
|
306
|
+
return {"error": "Invalid project object"}
|
|
307
|
+
|
|
308
|
+
try:
|
|
309
|
+
# Get SuperScale settings
|
|
310
|
+
settings = {}
|
|
311
|
+
|
|
312
|
+
# Check if SuperScale is enabled
|
|
313
|
+
superscale_enabled = get_project_property(project_obj, "superScaleEnabled")
|
|
314
|
+
settings["enabled"] = bool(superscale_enabled)
|
|
315
|
+
|
|
316
|
+
# Get quality setting
|
|
317
|
+
quality = get_project_property(project_obj, "superScaleQuality")
|
|
318
|
+
settings["quality"] = quality
|
|
319
|
+
|
|
320
|
+
# Translate quality number to descriptive name
|
|
321
|
+
quality_names = {
|
|
322
|
+
0: "Auto",
|
|
323
|
+
1: "Better Quality", # Sharper but might have artifacts
|
|
324
|
+
2: "Smoother", # Less sharp but fewer artifacts
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if quality in quality_names:
|
|
328
|
+
settings["qualityName"] = quality_names[quality]
|
|
329
|
+
|
|
330
|
+
# Add additional SuperScale properties if available
|
|
331
|
+
for prop in ["superScaleOverrideWidth", "superScaleOverrideHeight"]:
|
|
332
|
+
value = get_project_property(project_obj, prop)
|
|
333
|
+
if value is not None:
|
|
334
|
+
settings[prop] = value
|
|
335
|
+
|
|
336
|
+
return settings
|
|
337
|
+
|
|
338
|
+
except Exception as e:
|
|
339
|
+
logger.error(f"Error getting SuperScale settings: {str(e)}")
|
|
340
|
+
return {"error": f"Error getting SuperScale settings: {str(e)}"}
|
|
341
|
+
|
|
342
|
+
def set_superscale_settings(project_obj, enabled: bool, quality: int = 0) -> bool:
|
|
343
|
+
"""
|
|
344
|
+
Set SuperScale settings for the project.
|
|
345
|
+
|
|
346
|
+
Args:
|
|
347
|
+
project_obj: Project object from DaVinci Resolve API
|
|
348
|
+
enabled: Whether SuperScale is enabled
|
|
349
|
+
quality: SuperScale quality (0=Auto, 1=Better Quality, 2=Smoother)
|
|
350
|
+
|
|
351
|
+
Returns:
|
|
352
|
+
True if successful, False otherwise
|
|
353
|
+
"""
|
|
354
|
+
if project_obj is None:
|
|
355
|
+
return False
|
|
356
|
+
|
|
357
|
+
try:
|
|
358
|
+
# Validate quality value
|
|
359
|
+
if quality not in [0, 1, 2]:
|
|
360
|
+
logger.warning(f"Invalid SuperScale quality value: {quality}. Using 0 (Auto)")
|
|
361
|
+
quality = 0
|
|
362
|
+
|
|
363
|
+
# Set SuperScale properties
|
|
364
|
+
success = True
|
|
365
|
+
|
|
366
|
+
# Set enabled state
|
|
367
|
+
if not set_project_property(project_obj, "superScaleEnabled", enabled):
|
|
368
|
+
success = False
|
|
369
|
+
|
|
370
|
+
# Set quality
|
|
371
|
+
if not set_project_property(project_obj, "superScaleQuality", quality):
|
|
372
|
+
success = False
|
|
373
|
+
|
|
374
|
+
return success
|
|
375
|
+
|
|
376
|
+
except Exception as e:
|
|
377
|
+
logger.error(f"Error setting SuperScale settings: {str(e)}")
|
|
378
|
+
return False
|
|
379
|
+
|
|
380
|
+
def get_color_settings(project_obj) -> Dict[str, Any]:
|
|
381
|
+
"""
|
|
382
|
+
Get color science and color space settings for the project.
|
|
383
|
+
|
|
384
|
+
Args:
|
|
385
|
+
project_obj: Project object from DaVinci Resolve API
|
|
386
|
+
|
|
387
|
+
Returns:
|
|
388
|
+
Dictionary of color settings
|
|
389
|
+
"""
|
|
390
|
+
if project_obj is None:
|
|
391
|
+
return {"error": "Invalid project object"}
|
|
392
|
+
|
|
393
|
+
try:
|
|
394
|
+
# Get color-related settings
|
|
395
|
+
settings = {}
|
|
396
|
+
color_properties = [
|
|
397
|
+
"colorScienceMode",
|
|
398
|
+
"timelineColorSpace",
|
|
399
|
+
"timelineGamma",
|
|
400
|
+
"inputDRT",
|
|
401
|
+
"outputDRT"
|
|
402
|
+
]
|
|
403
|
+
|
|
404
|
+
for prop in color_properties:
|
|
405
|
+
value = get_project_property(project_obj, prop)
|
|
406
|
+
if value is not None:
|
|
407
|
+
settings[prop] = value
|
|
408
|
+
|
|
409
|
+
# Translate colorScienceMode to descriptive name
|
|
410
|
+
if "colorScienceMode" in settings:
|
|
411
|
+
mode = settings["colorScienceMode"]
|
|
412
|
+
mode_names = {
|
|
413
|
+
0: "DaVinci YRGB",
|
|
414
|
+
1: "DaVinci YRGB Color Managed",
|
|
415
|
+
2: "ACEScct"
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if mode in mode_names:
|
|
419
|
+
settings["colorScienceName"] = mode_names[mode]
|
|
420
|
+
|
|
421
|
+
return settings
|
|
422
|
+
|
|
423
|
+
except Exception as e:
|
|
424
|
+
logger.error(f"Error getting color settings: {str(e)}")
|
|
425
|
+
return {"error": f"Error getting color settings: {str(e)}"}
|
|
426
|
+
|
|
427
|
+
def set_color_science_mode(project_obj, mode: str) -> bool:
|
|
428
|
+
"""
|
|
429
|
+
Set color science mode for the project.
|
|
430
|
+
|
|
431
|
+
Args:
|
|
432
|
+
project_obj: Project object from DaVinci Resolve API
|
|
433
|
+
mode: Color science mode ('YRGB', 'YRGB Color Managed', 'ACEScct', or numeric value)
|
|
434
|
+
|
|
435
|
+
Returns:
|
|
436
|
+
True if successful, False otherwise
|
|
437
|
+
"""
|
|
438
|
+
if project_obj is None:
|
|
439
|
+
return False
|
|
440
|
+
|
|
441
|
+
try:
|
|
442
|
+
# Map string modes to numeric values
|
|
443
|
+
mode_values = {
|
|
444
|
+
"YRGB": 0,
|
|
445
|
+
"DaVinci YRGB": 0,
|
|
446
|
+
"YRGB Color Managed": 1,
|
|
447
|
+
"DaVinci YRGB Color Managed": 1,
|
|
448
|
+
"ACEScct": 2,
|
|
449
|
+
"ACES": 2
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
# Get numeric value
|
|
453
|
+
mode_value = None
|
|
454
|
+
|
|
455
|
+
if isinstance(mode, int) and 0 <= mode <= 2:
|
|
456
|
+
mode_value = mode
|
|
457
|
+
elif isinstance(mode, str):
|
|
458
|
+
mode_value = mode_values.get(mode)
|
|
459
|
+
|
|
460
|
+
if mode_value is None:
|
|
461
|
+
logger.error(f"Invalid color science mode: {mode}")
|
|
462
|
+
return False
|
|
463
|
+
|
|
464
|
+
# Set the color science mode
|
|
465
|
+
return set_project_property(project_obj, "colorScienceMode", mode_value)
|
|
466
|
+
|
|
467
|
+
except Exception as e:
|
|
468
|
+
logger.error(f"Error setting color science mode: {str(e)}")
|
|
469
|
+
return False
|
|
470
|
+
|
|
471
|
+
def set_color_space(project_obj, color_space: str, gamma: str = None) -> bool:
|
|
472
|
+
"""
|
|
473
|
+
Set timeline color space and gamma.
|
|
474
|
+
|
|
475
|
+
Args:
|
|
476
|
+
project_obj: Project object from DaVinci Resolve API
|
|
477
|
+
color_space: Timeline color space (e.g., 'Rec.709', 'DCI-P3 D65', 'Rec.2020')
|
|
478
|
+
gamma: Timeline gamma (e.g., 'Rec.709 Gamma', 'Gamma 2.4')
|
|
479
|
+
|
|
480
|
+
Returns:
|
|
481
|
+
True if successful, False otherwise
|
|
482
|
+
"""
|
|
483
|
+
if project_obj is None:
|
|
484
|
+
return False
|
|
485
|
+
|
|
486
|
+
try:
|
|
487
|
+
success = True
|
|
488
|
+
|
|
489
|
+
# Set timeline color space
|
|
490
|
+
if not set_project_property(project_obj, "timelineColorSpace", color_space):
|
|
491
|
+
success = False
|
|
492
|
+
|
|
493
|
+
# Set gamma if provided
|
|
494
|
+
if gamma is not None:
|
|
495
|
+
if not set_project_property(project_obj, "timelineGamma", gamma):
|
|
496
|
+
success = False
|
|
497
|
+
|
|
498
|
+
return success
|
|
499
|
+
|
|
500
|
+
except Exception as e:
|
|
501
|
+
logger.error(f"Error setting color space: {str(e)}")
|
|
502
|
+
return False
|
|
503
|
+
|
|
504
|
+
def get_project_metadata(project_obj) -> Dict[str, Any]:
|
|
505
|
+
"""
|
|
506
|
+
Get project metadata.
|
|
507
|
+
|
|
508
|
+
Args:
|
|
509
|
+
project_obj: Project object from DaVinci Resolve API
|
|
510
|
+
|
|
511
|
+
Returns:
|
|
512
|
+
Dictionary of project metadata
|
|
513
|
+
"""
|
|
514
|
+
if project_obj is None:
|
|
515
|
+
return {"error": "Invalid project object"}
|
|
516
|
+
|
|
517
|
+
try:
|
|
518
|
+
metadata = {}
|
|
519
|
+
|
|
520
|
+
# Add basic project info
|
|
521
|
+
metadata["name"] = project_obj.GetName()
|
|
522
|
+
|
|
523
|
+
# Add project path if available
|
|
524
|
+
if hasattr(project_obj, "GetPath"):
|
|
525
|
+
metadata["path"] = project_obj.GetPath()
|
|
526
|
+
|
|
527
|
+
# Get current timeline
|
|
528
|
+
current_timeline = project_obj.GetCurrentTimeline()
|
|
529
|
+
if current_timeline:
|
|
530
|
+
metadata["currentTimeline"] = current_timeline.GetName()
|
|
531
|
+
|
|
532
|
+
# Add timeline count
|
|
533
|
+
timeline_count = project_obj.GetTimelineCount()
|
|
534
|
+
metadata["timelineCount"] = timeline_count
|
|
535
|
+
|
|
536
|
+
# Add frame rate and resolution
|
|
537
|
+
format_settings = get_timeline_format_settings(project_obj)
|
|
538
|
+
if "error" not in format_settings:
|
|
539
|
+
metadata.update(format_settings)
|
|
540
|
+
|
|
541
|
+
# Add color settings
|
|
542
|
+
color_settings = get_color_settings(project_obj)
|
|
543
|
+
if "error" not in color_settings:
|
|
544
|
+
metadata["colorSettings"] = color_settings
|
|
545
|
+
|
|
546
|
+
# Add SuperScale settings
|
|
547
|
+
superscale_settings = get_superscale_settings(project_obj)
|
|
548
|
+
if "error" not in superscale_settings:
|
|
549
|
+
metadata["superScale"] = superscale_settings
|
|
550
|
+
|
|
551
|
+
return metadata
|
|
552
|
+
|
|
553
|
+
except Exception as e:
|
|
554
|
+
logger.error(f"Error getting project metadata: {str(e)}")
|
|
555
|
+
return {"error": f"Error getting project metadata: {str(e)}"}
|
|
556
|
+
|
|
557
|
+
def get_project_info(project_obj) -> Dict[str, Any]:
|
|
558
|
+
"""
|
|
559
|
+
Get comprehensive project information including settings and metadata.
|
|
560
|
+
|
|
561
|
+
Args:
|
|
562
|
+
project_obj: Project object from DaVinci Resolve API
|
|
563
|
+
|
|
564
|
+
Returns:
|
|
565
|
+
Dictionary with project information
|
|
566
|
+
"""
|
|
567
|
+
if project_obj is None:
|
|
568
|
+
return {"error": "Invalid project object"}
|
|
569
|
+
|
|
570
|
+
try:
|
|
571
|
+
# Get project name
|
|
572
|
+
project_name = project_obj.GetName()
|
|
573
|
+
|
|
574
|
+
# Combine all project information
|
|
575
|
+
project_info = {
|
|
576
|
+
"name": project_name,
|
|
577
|
+
"metadata": get_project_metadata(project_obj),
|
|
578
|
+
"settings": get_all_project_properties(project_obj),
|
|
579
|
+
"timelines": []
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
# Add timeline information
|
|
583
|
+
timeline_count = project_obj.GetTimelineCount()
|
|
584
|
+
current_timeline = project_obj.GetCurrentTimeline()
|
|
585
|
+
current_timeline_name = current_timeline.GetName() if current_timeline else None
|
|
586
|
+
|
|
587
|
+
for i in range(1, timeline_count + 1):
|
|
588
|
+
timeline = project_obj.GetTimelineByIndex(i)
|
|
589
|
+
if timeline:
|
|
590
|
+
timeline_info = {
|
|
591
|
+
"name": timeline.GetName(),
|
|
592
|
+
"isCurrent": timeline.GetName() == current_timeline_name,
|
|
593
|
+
"duration": timeline.GetEndFrame() - timeline.GetStartFrame() + 1
|
|
594
|
+
}
|
|
595
|
+
project_info["timelines"].append(timeline_info)
|
|
596
|
+
|
|
597
|
+
return project_info
|
|
598
|
+
|
|
599
|
+
except Exception as e:
|
|
600
|
+
logger.error(f"Error getting project info: {str(e)}")
|
|
601
|
+
return {"error": f"Error getting project info: {str(e)}"}
|