#!/usr/bin/env python3 import sys import os import re # --- ARCH LINUX PATH FIX --- module_path = "/opt/resolve/Developer/Scripting/Modules/" if module_path not in sys.path: sys.path.append(module_path) try: import DaVinciResolveScript as dvr_script except ImportError: print(f"❌ Critical Error: Could not find 'DaVinciResolveScript.py'.") sys.exit(1) # --------------------------- def export_clip_markers_final(): try: resolve = dvr_script.scriptapp("Resolve") project = resolve.GetProjectManager().GetCurrentProject() timeline = project.GetCurrentTimeline() except: return if not timeline: print("❌ Error: No active timeline found.") return # Base Path base_output_path = os.path.expanduser("~/Videos/Resolve_Exports") timeline_name = timeline.GetName() safe_timeline_name = re.sub(r'[\\/*?:"<>|]', "", timeline_name).replace(" ", "_") timeline_dir = os.path.join(base_output_path, safe_timeline_name) # Get Clips from Video Track 1 clips = timeline.GetItemListInTrack("video", 1) if not clips: print("No clips found.") return job_count = 0 print(f"Scanning {len(clips)} clips...") for clip in clips: markers = clip.GetMarkers() if not markers: continue # 1. Prepare Folder Name (Clip Name) clip_name_raw = clip.GetName() safe_clip_folder = re.sub(r'[\\/*?:"<>|]', "", clip_name_raw) safe_clip_folder = safe_clip_folder.replace(".mov", "").replace(".mp4", "").replace(".mxf", "").strip() clip_target_dir = os.path.join(timeline_dir, safe_clip_folder) # Create folder if missing if not os.path.exists(clip_target_dir): try: os.makedirs(clip_target_dir) except OSError: continue # 2. Timing Calculations clip_start_timeline = clip.GetStart() clip_left_offset = clip.GetLeftOffset() for marker_frame, marker_data in markers.items(): timeline_frame_pos = (marker_frame - clip_left_offset) + clip_start_timeline # 3. Prepare File Name (Marker Name) raw_name = marker_data['name'] if marker_data['name'] else marker_data['note'] if not raw_name: base_name = f"Frame_{marker_frame}" else: base_name = re.sub(r'[\\/*?:"<>|]', "", raw_name).strip() # --- THE FIX: Force correct naming --- # We set UniqueFilenameStyle to 1 (Suffix) but we manually control the name. # Unfortunately, API limitation: Resolve ALWAYS appends frame number on image sequences. # The cleanest "trick" is to use the name as is, and accept that Resolve # adds the frame digits. The previous "underscore" trick is the safest bet. final_filename = base_name + "_" # 4. Add to Render Queue project.SetRenderSettings({ "SelectAllFrames": False, "MarkIn": timeline_frame_pos, "MarkOut": timeline_frame_pos, "TargetDir": clip_target_dir, "CustomName": final_filename, "UniqueFilenameStyle": 0 }) project.AddRenderJob() job_count += 1 print(f"✅ Queued: {safe_clip_folder}/{final_filename}[####].ext") print("-" * 30) print(f"🎉 Queued {job_count} stills.") if __name__ == "__main__": export_clip_markers_final()