DaVinci Resolve MCP Server

""" DaVinci Resolve API connector module. This module provides functions to connect to DaVinci Resolve's Python API and interact with its various components. """ import sys import os import platform from typing import Optional, Dict, List, Any, Union, Tuple class ResolveAPI: """Class to handle connection and interaction with DaVinci Resolve API.""" def __init__(self): """Initialize the ResolveAPI class and connect to DaVinci Resolve.""" self.resolve = None self.fusion = None self.project_manager = None self.current_project = None self.media_storage = None self.media_pool = None self._connect_to_resolve() def _connect_to_resolve(self) -> None: """ Connect to DaVinci Resolve based on the current operating system. This function adds the appropriate paths to sys.path and imports the DaVinciResolveScript module to establish a connection to Resolve. """ # Determine the appropriate path based on the operating system if platform.system() == "Windows": resolve_script_dir = os.path.join( os.environ.get("PROGRAMDATA", "C:\\ProgramData"), "Blackmagic Design", "DaVinci Resolve", "Support", "Developer", "Scripting" ) script_api_path = os.path.join(resolve_script_dir, "Modules") # Add the API directory to the system path if script_api_path not in sys.path: sys.path.append(script_api_path) # Import the DaVinciResolveScript module try: import DaVinciResolveScript as dvr_script self.resolve = dvr_script.scriptapp("Resolve") except ImportError: print("Error: Could not find DaVinciResolveScript module on Windows.") self.resolve = None elif platform.system() == "Darwin": # macOS path resolve_script_dir = "/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting" script_api_path = os.path.join(resolve_script_dir, "Modules") # Add the API directory to the system path if script_api_path not in sys.path: sys.path.append(script_api_path) # Import the DaVinciResolveScript module try: import DaVinciResolveScript as dvr_script self.resolve = dvr_script.scriptapp("Resolve") except ImportError: # Try the user-specific path if the system-wide path fails user_script_api_path = os.path.join( os.path.expanduser("~"), "Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting/Modules" ) if user_script_api_path not in sys.path: sys.path.append(user_script_api_path) try: import DaVinciResolveScript as dvr_script self.resolve = dvr_script.scriptapp("Resolve") except ImportError: print("Error: Could not find DaVinciResolveScript module on macOS.") self.resolve = None elif platform.system() == "Linux": # Linux path resolve_script_dir = "/opt/resolve/Developer/Scripting" script_api_path = os.path.join(resolve_script_dir, "Modules") # Add the API directory to the system path if script_api_path not in sys.path: sys.path.append(script_api_path) # Import the DaVinciResolveScript module try: import DaVinciResolveScript as dvr_script self.resolve = dvr_script.scriptapp("Resolve") except ImportError: print("Error: Could not find DaVinciResolveScript module on Linux.") self.resolve = None # Initialize other components if Resolve is connected if self.resolve: self.project_manager = self.resolve.GetProjectManager() self.current_project = self.project_manager.GetCurrentProject() self.media_storage = self.resolve.GetMediaStorage() self.fusion = self.resolve.Fusion() # Initialize media pool if a project is open if self.current_project: self.media_pool = self.current_project.GetMediaPool() def is_connected(self) -> bool: """Check if connected to DaVinci Resolve.""" return self.resolve is not None def get_project_manager(self): """Get the project manager object.""" return self.project_manager def get_current_project(self): """Get the current project object.""" if self.project_manager: self.current_project = self.project_manager.GetCurrentProject() return self.current_project def get_media_storage(self): """Get the media storage object.""" return self.media_storage def get_media_pool(self): """Get the media pool object for the current project.""" if self.current_project: self.media_pool = self.current_project.GetMediaPool() return self.media_pool def get_fusion(self): """Get the Fusion object.""" return self.fusion def open_page(self, page_name: str) -> bool: """ Open a specific page in DaVinci Resolve. Args: page_name (str): The name of the page to open. Valid values: "media", "edit", "fusion", "color", "fairlight", "deliver" Returns: bool: True if successful, False otherwise. """ if not self.resolve: return False valid_pages = ["media", "edit", "fusion", "color", "fairlight", "deliver"] if page_name.lower() not in valid_pages: return False self.resolve.OpenPage(page_name.lower()) return True def create_project(self, project_name: str) -> bool: """ Create a new project with the given name. Args: project_name (str): The name of the project to create. Returns: bool: True if successful, False otherwise. """ if not self.project_manager: return False new_project = self.project_manager.CreateProject(project_name) if new_project: self.current_project = new_project self.media_pool = self.current_project.GetMediaPool() return True return False def load_project(self, project_name: str) -> bool: """ Load an existing project with the given name. Args: project_name (str): The name of the project to load. Returns: bool: True if successful, False otherwise. """ if not self.project_manager: return False loaded_project = self.project_manager.LoadProject(project_name) if loaded_project: self.current_project = loaded_project self.media_pool = self.current_project.GetMediaPool() return True return False def save_project(self) -> bool: """ Save the current project. Returns: bool: True if successful, False otherwise. """ if not self.current_project: return False return self.current_project.SaveProject() def get_project_name(self) -> Optional[str]: """ Get the name of the current project. Returns: Optional[str]: The project name, or None if no project is open. """ if not self.current_project: return None return self.current_project.GetName() def create_timeline(self, timeline_name: str) -> bool: """ Create a new timeline with the given name. Args: timeline_name (str): The name of the timeline to create. Returns: bool: True if successful, False otherwise. """ if not self.media_pool: return False new_timeline = self.media_pool.CreateEmptyTimeline(timeline_name) return new_timeline is not None def get_current_timeline(self): """ Get the current timeline. Returns: The current timeline object, or None if no timeline is open. """ if not self.current_project: return None return self.current_project.GetCurrentTimeline() def get_timeline_count(self) -> int: """ Get the number of timelines in the current project. Returns: int: The number of timelines, or 0 if no project is open. """ if not self.current_project: return 0 return self.current_project.GetTimelineCount() def get_timeline_by_index(self, index: int): """ Get a timeline by its index. Args: index (int): The index of the timeline (1-based). Returns: The timeline object, or None if the index is invalid. """ if not self.current_project: return None return self.current_project.GetTimelineByIndex(index) def set_current_timeline(self, timeline) -> bool: """ Set the current timeline. Args: timeline: The timeline object to set as current. Returns: bool: True if successful, False otherwise. """ if not self.current_project: return False return self.current_project.SetCurrentTimeline(timeline) def get_mounted_volumes(self) -> List[str]: """ Get a list of mounted volumes. Returns: List[str]: A list of mounted volume paths. """ if not self.media_storage: return [] return self.media_storage.GetMountedVolumes() def get_sub_folders(self, folder_path: str) -> List[str]: """ Get a list of subfolders in the given folder path. Args: folder_path (str): The path of the folder to get subfolders from. Returns: List[str]: A list of subfolder paths. """ if not self.media_storage: return [] return self.media_storage.GetSubFolders(folder_path) def get_files(self, folder_path: str) -> List[str]: """ Get a list of files in the given folder path. Args: folder_path (str): The path of the folder to get files from. Returns: List[str]: A list of file paths. """ if not self.media_storage: return [] return self.media_storage.GetFiles(folder_path) def add_items_to_media_pool(self, file_paths: List[str]) -> List[Any]: """ Add items from the media storage to the media pool. Args: file_paths (List[str]): A list of file paths to add. Returns: List[Any]: A list of added media pool items. """ if not self.media_storage or not self.media_pool: return [] return self.media_storage.AddItemsToMediaPool(file_paths) def get_root_folder(self): """ Get the root folder of the media pool. Returns: The root folder object, or None if no media pool is available. """ if not self.media_pool: return None return self.media_pool.GetRootFolder() def get_current_folder(self): """ Get the current folder of the media pool. Returns: The current folder object, or None if no media pool is available. """ if not self.media_pool: return None return self.media_pool.GetCurrentFolder() def add_sub_folder(self, parent_folder, folder_name: str): """ Add a subfolder to the given parent folder. Args: parent_folder: The parent folder object. folder_name (str): The name of the subfolder to create. Returns: The created subfolder object, or None if unsuccessful. """ if not self.media_pool: return None return self.media_pool.AddSubFolder(parent_folder, folder_name) def get_folder_clips(self, folder) -> List[Any]: """ Get a list of clips in the given folder. Args: folder: The folder object. Returns: List[Any]: A list of media pool items in the folder. """ if not folder: return [] return folder.GetClips() def get_folder_name(self, folder) -> Optional[str]: """ Get the name of the given folder. Args: folder: The folder object. Returns: Optional[str]: The folder name, or None if the folder is invalid. """ if not folder: return None return folder.GetName() def get_folder_sub_folders(self, folder) -> List[Any]: """ Get a list of subfolders in the given folder. Args: folder: The folder object. Returns: List[Any]: A list of subfolder objects. """ if not folder: return [] return folder.GetSubFolders() def append_to_timeline(self, clips: List[Any]) -> bool: """ Append the given clips to the current timeline. Args: clips (List[Any]): A list of media pool items to append. Returns: bool: True if successful, False otherwise. """ if not self.media_pool: return False return self.media_pool.AppendToTimeline(clips) def create_timeline_from_clips(self, timeline_name: str, clips: List[Any]): """ Create a new timeline with the given name and append the given clips. Args: timeline_name (str): The name of the timeline to create. clips (List[Any]): A list of media pool items to append. Returns: The created timeline object, or None if unsuccessful. """ if not self.media_pool: return None return self.media_pool.CreateTimelineFromClips(timeline_name, clips) def import_timeline_from_file(self, file_path: str): """ Import a timeline from a file. Args: file_path (str): The path of the file to import. Returns: The imported timeline object, or None if unsuccessful. """ if not self.media_pool: return None return self.media_pool.ImportTimelineFromFile(file_path) def execute_lua(self, script: str) -> Any: """ Execute a Lua script in DaVinci Resolve. Args: script (str): The Lua script to execute. Returns: Any: The result of the script execution. """ if not self.fusion: return None return self.fusion.Execute(script) def create_fusion_node(self, comp, node_type: str, inputs: Dict[str, Any] = None) -> Any: """ Create a Fusion node in the given composition. Args: comp: The Fusion composition to add the node to. node_type (str): The type of node to create (e.g., 'Blur', 'ColorCorrector'). inputs (Dict[str, Any], optional): Dictionary of input parameters for the node. Returns: Any: The created node, or None if unsuccessful. """ if not self.fusion or not comp: return None try: # Create the node in the composition node = comp.AddTool(node_type) # Set input parameters if provided if inputs and node: for key, value in inputs.items(): node[key] = value return node except Exception as e: print(f"Error creating Fusion node: {e}") return None def get_current_comp(self) -> Any: """ Get the current Fusion composition. Returns: Any: The current Fusion composition, or None if not available. """ if not self.fusion: return None try: return self.fusion.CurrentComp except Exception as e: print(f"Error getting current composition: {e}") return None
ID: spnoxodh9v