DaVinci Resolve MCP

by samuelgursky
Verified
#!/usr/bin/env python3 """ DaVinci Resolve Media Operations """ import logging import os from typing import List, Dict, Any logger = logging.getLogger("davinci-resolve-mcp.media") def list_media_pool_clips(resolve) -> List[Dict[str, Any]]: """List all clips in the media pool of the current project.""" if resolve is None: return [{"error": "Not connected to DaVinci Resolve"}] project_manager = resolve.GetProjectManager() if not project_manager: return [{"error": "Failed to get Project Manager"}] current_project = project_manager.GetCurrentProject() if not current_project: return [{"error": "No project currently open"}] media_pool = current_project.GetMediaPool() if not media_pool: return [{"error": "Failed to get Media Pool"}] # Get the root folder and all its clips root_folder = media_pool.GetRootFolder() if not root_folder: return [{"error": "Failed to get Root Folder"}] clips = root_folder.GetClipList() # Format clip info clip_info = [] for clip in clips: if clip: clip_info.append({ "name": clip.GetName(), "type": clip.GetClipProperty()["Type"], "duration": clip.GetClipProperty()["Duration"], "fps": clip.GetClipProperty().get("FPS", "Unknown") }) return clip_info if clip_info else [{"info": "No clips found in the media pool"}] def import_media(resolve, file_path: str) -> str: """Import a media file into the current project's media pool.""" if resolve is None: return "Error: Not connected to DaVinci Resolve" # Validate file path if not file_path: return "Error: File path cannot be empty" if not os.path.exists(file_path): return f"Error: File '{file_path}' does not exist" project_manager = resolve.GetProjectManager() if not project_manager: return "Error: Failed to get Project Manager" current_project = project_manager.GetCurrentProject() if not current_project: return "Error: No project currently open" media_pool = current_project.GetMediaPool() if not media_pool: return "Error: Failed to get Media Pool" # Import the media file # DaVinci Resolve API expects a list of file paths imported_media = media_pool.ImportMedia([file_path]) if imported_media and len(imported_media) > 0: return f"Successfully imported '{os.path.basename(file_path)}'" else: return f"Failed to import '{file_path}'. The file may be in an unsupported format." def create_bin(resolve, name: str) -> str: """Create a new bin/folder in the media pool.""" if resolve is None: return "Error: Not connected to DaVinci Resolve" if not name: return "Error: Bin name cannot be empty" project_manager = resolve.GetProjectManager() if not project_manager: return "Error: Failed to get Project Manager" current_project = project_manager.GetCurrentProject() if not current_project: return "Error: No project currently open" media_pool = current_project.GetMediaPool() if not media_pool: return "Error: Failed to get Media Pool" # Get the root folder to add the bin to root_folder = media_pool.GetRootFolder() if not root_folder: return "Error: Failed to get Root Folder" # Check if bin already exists (by checking the subfolders) folders = root_folder.GetSubFolderList() for folder in folders: if folder.GetName() == name: return f"Error: Bin '{name}' already exists" # Create the bin new_bin = media_pool.AddSubFolder(root_folder, name) if new_bin: return f"Successfully created bin '{name}'" else: return f"Failed to create bin '{name}'" def list_timeline_clips(resolve) -> List[Dict[str, Any]]: """List all clips in the current timeline.""" if resolve is None: return [{"error": "Not connected to DaVinci Resolve"}] project_manager = resolve.GetProjectManager() if not project_manager: return [{"error": "Failed to get Project Manager"}] current_project = project_manager.GetCurrentProject() if not current_project: return [{"error": "No project currently open"}] current_timeline = current_project.GetCurrentTimeline() if not current_timeline: return [{"error": "No timeline currently active"}] # Get all video tracks video_tracks = current_timeline.GetTrackCount("video") clip_info = [] for track_index in range(1, video_tracks + 1): # Note: Track indices in Resolve API are 1-based clips = current_timeline.GetItemListInTrack("video", track_index) for clip in clips: if clip: clip_info.append({ "name": clip.GetName(), "track": f"V{track_index}", "start_frame": clip.GetStart(), "end_frame": clip.GetEnd(), "duration": clip.GetDuration() }) # Get audio tracks as well audio_tracks = current_timeline.GetTrackCount("audio") for track_index in range(1, audio_tracks + 1): clips = current_timeline.GetItemListInTrack("audio", track_index) for clip in clips: if clip: clip_info.append({ "name": clip.GetName(), "track": f"A{track_index}", "start_frame": clip.GetStart(), "end_frame": clip.GetEnd(), "duration": clip.GetDuration() }) return clip_info if clip_info else [{"info": "No clips found in the current timeline"}] def add_clip_to_timeline(resolve, clip_name: str, timeline_name: str = None) -> str: """Add a media pool clip to the timeline. Args: resolve: The DaVinci Resolve instance clip_name: Name of the clip in the media pool timeline_name: Optional timeline to target (uses current if not specified) """ if not resolve: return "Error: Not connected to DaVinci Resolve" project_manager = resolve.GetProjectManager() if not project_manager: return "Error: Failed to get Project Manager" current_project = project_manager.GetCurrentProject() if not current_project: return "Error: No project currently open" media_pool = current_project.GetMediaPool() if not media_pool: return "Error: Failed to get Media Pool" # Get all clips in root folder root_folder = media_pool.GetRootFolder() clips = root_folder.GetClipList() target_clip = None for clip in clips: if clip.GetName() == clip_name: target_clip = clip break if not target_clip: return f"Error: Clip '{clip_name}' not found in Media Pool" # Get the target timeline timeline = None if timeline_name: # Switch to the specified timeline timeline_count = current_project.GetTimelineCount() for i in range(1, timeline_count + 1): t = current_project.GetTimelineByIndex(i) if t and t.GetName() == timeline_name: timeline = t current_project.SetCurrentTimeline(timeline) break if not timeline: return f"Error: Timeline '{timeline_name}' not found" else: # Use current timeline timeline = current_project.GetCurrentTimeline() if not timeline: return "Error: No timeline currently active" # Add clip to timeline # We need to use media_pool.AppendToTimeline() which expects a list of clips result = media_pool.AppendToTimeline([target_clip]) if result and len(result) > 0: return f"Successfully added clip '{clip_name}' to timeline" else: return f"Failed to add clip '{clip_name}' to timeline"