2DaVinci Resolve client wrapper.
4Provides a clean interface to the DaVinci Resolve API with proper error handling
9from typing
import Any, Dict, List, Optional, TYPE_CHECKING
13 from .types
import DaVinciResolveApp, DaVinciProjectManager, DaVinciProject
15from .utils.platform
import setup_resolve_environment, check_resolve_running
18logger = logging.getLogger(__name__)
22 """Base exception for DaVinci Resolve related errors."""
28 """Raised when DaVinci Resolve is not running."""
34 """Raised when connection to DaVinci Resolve fails."""
41 A clean interface to the DaVinci Resolve API.
43 This class handles the connection to DaVinci Resolve and provides
44 organized methods for interacting with projects, timelines, media, etc.
48 self.
_resolve: Optional[
"DaVinciResolveApp"] =
None
54 """Connect to DaVinci Resolve."""
56 if not check_resolve_running():
58 "DaVinci Resolve is not running. Please start DaVinci Resolve first."
62 if not setup_resolve_environment():
64 "Failed to set up DaVinci Resolve environment variables."
69 import DaVinciResolveScript
as dvr_script
71 self.
_resolve = dvr_script.scriptapp(
"Resolve")
75 "Failed to get Resolve object. Check that DaVinci Resolve is running."
87 logger.info(f
"Connected to {self.get_version()}")
89 except ImportError
as e:
91 f
"Failed to import DaVinciResolveScript: {e}. "
92 "Check environment variables and DaVinci Resolve installation."
94 except Exception
as e:
98 """Disconnect from DaVinci Resolve."""
103 logger.info(
"Disconnected from DaVinci Resolve")
106 """Check if connected to DaVinci Resolve."""
110 """Ensure we're connected to Resolve."""
115 """Ensure we have a current project."""
129 """Get DaVinci Resolve version."""
133 f
"{self._resolve.GetProductName()} {self._resolve.GetVersionString()}"
138 """Get the current page (Edit, Color, Fusion, etc.)."""
141 return self.
_resolve.GetCurrentPage()
145 """Switch to a specific page."""
157 if page.lower()
not in valid_pages:
158 raise ValueError(f
"Invalid page. Must be one of: {', '.join(valid_pages)}")
161 return bool(self.
_resolve.OpenPage(page.lower()))
166 """List all projects in the current database."""
171 return [p
for p
in projects
if p]
175 """Get the name of the currently open project."""
178 return project.GetName()
179 except DaVinciResolveError:
183 """Open a project by name."""
191 if name
not in projects:
193 f
"Project '{name}' not found. Available: {', '.join(projects)}"
199 logger.info(f
"Opened project: {name}")
204 """Create a new project."""
213 raise ValueError(f
"Project '{name}' already exists")
218 logger.info(f
"Created project: {name}")
224 """List all timelines in the current project."""
227 timeline_count = project.GetTimelineCount()
228 timelines: List[str] = []
230 for i
in range(1, timeline_count + 1):
231 timeline = project.GetTimelineByIndex(i)
233 name = timeline.GetName()
234 if isinstance(name, str):
235 timelines.append(name)
240 """Get the name of the current timeline."""
243 current_timeline = project.GetCurrentTimeline()
244 return current_timeline.GetName()
if current_timeline
else None
245 except DaVinciResolveError:
249 """Create a new timeline."""
252 media_pool = project.GetMediaPool()
256 timeline = media_pool.CreateEmptyTimeline(name)
258 logger.info(f
"Created timeline: {name}")
264 """Switch to a timeline by name."""
268 timeline_count = project.GetTimelineCount()
269 for i
in range(1, timeline_count + 1):
270 timeline = project.GetTimelineByIndex(i)
271 if timeline
and timeline.GetName() == name:
272 result = project.SetCurrentTimeline(timeline)
274 logger.info(f
"Switched to timeline: {name}")
277 raise ValueError(f
"Timeline '{name}' not found")
281 """List all clips in the media pool root folder."""
284 media_pool = project.GetMediaPool()
288 root_folder = media_pool.GetRootFolder()
292 clips = root_folder.GetClipList()
296 result: List[Dict[str, Any]] = []
299 "name": clip.GetName(),
300 "duration": clip.GetDuration(),
301 "fps": clip.GetClipProperty(
"FPS")
or "Unknown",
303 result.append(clip_info)
308 """Import a media file into the media pool."""
311 media_pool = project.GetMediaPool()
316 imported_clips = media_pool.ImportMedia([file_path])
319 logger.info(f
"Imported media: {file_path}")
Optional[str] get_current_timeline_name(self)
None _ensure_connected(self)
bool open_project(self, str name)
List[Dict[str, Any]] list_media_clips(self)
Optional[str] get_current_project_name(self)
Optional[] _current_project
str get_current_page(self)
bool create_timeline(self, str name)
bool import_media(self, str file_path)
List[str] list_projects(self)
bool create_project(self, str name)
Optional[] _project_manager
Any _ensure_project(self)
bool switch_timeline(self, str name)
bool switch_page(self, str page)
List[str] list_timelines(self)