#!/usr/bin/env python3
"""
Extract every clip in the current DaVinci Resolve Studio bin to the drive folder.

Each clip in the currently-selected Media Pool folder is rendered to its own
.mp4 (video only, no audio), named after its clip name in Resolve.

Usage:
  1. Open your project in DaVinci Resolve Studio and select the bin holding the clips.
  2. Run:  python3 extract_clips.py
"""

import os
import re
import sys
import time

DRIVE = "/Users/ariel32lubin/github/ariels-org/protocol/content/protocol/drive"
TMP_PREFIX = "_extract_"  # temp timelines named with this are auto-deleted

# --- Locate the Resolve scripting API (macOS defaults) ---
os.environ.setdefault(
    "RESOLVE_SCRIPT_API",
    "/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting",
)
os.environ.setdefault(
    "RESOLVE_SCRIPT_LIB",
    "/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so",
)
sys.path.append(os.path.join(os.environ["RESOLVE_SCRIPT_API"], "Modules"))

import DaVinciResolveScript as dvr  # noqa: E402


def clean_name(name):
    """Clip name -> safe filename (drop extension, swap path-unfriendly chars)."""
    name = os.path.splitext(name)[0]
    return re.sub(r"[^\w.-]+", "_", name).strip("_") or "clip"


def main():
    resolve = dvr.scriptapp("Resolve")
    if resolve is None:
        sys.exit("Could not connect to DaVinci Resolve. Is it running?")

    project = resolve.GetProjectManager().GetCurrentProject()
    media_pool = project.GetMediaPool()
    folder = media_pool.GetCurrentFolder()

    # Real media clips have a File Path; timelines/compound clips don't.
    clips = [c for c in folder.GetClipList() if c.GetClipProperty("File Path")]
    if not clips:
        sys.exit("No source clips found in the selected bin.")

    # Clean up any leftover temp timelines from a previous run.
    stale = [c for c in folder.GetClipList()
             if c.GetName().startswith(TMP_PREFIX) and not c.GetClipProperty("File Path")]
    if stale:
        media_pool.DeleteTimelines(stale)

    resolve.OpenPage("deliver")
    project.SetCurrentRenderFormatAndCodec("mp4", "H264")
    project.SetCurrentRenderMode(1)  # 1 = single clip (one file per timeline)

    used = {}
    for i, clip in enumerate(clips):
        name = clean_name(clip.GetName())
        used[name] = used.get(name, 0) + 1
        if used[name] > 1:  # avoid overwriting clips that share a name
            name = f"{name}_{used[name]}"

        # Render one clip at a time so each job binds to its own timeline.
        # Unique name (pid + index) so it never collides with a leftover timeline.
        timeline = media_pool.CreateTimelineFromClips(f"{TMP_PREFIX}{os.getpid()}_{i}", [clip])
        project.SetCurrentTimeline(timeline)
        project.DeleteAllRenderJobs()
        project.SetRenderSettings({
            "TargetDir": DRIVE,
            "CustomName": name,
            "SelectAllFrames": True,
            "ExportVideo": True,
            "ExportAudio": False,  # video only, no audio
        })
        project.AddRenderJob()

        print(f"Rendering {name}.mp4  <-  {clip.GetName()}")
        project.StartRendering()
        while project.IsRenderingInProgress():
            time.sleep(1)

        # Remove the temp timeline so the bin stays clean.
        media_pool.DeleteTimelines([timeline])

    project.DeleteAllRenderJobs()
    print("Done.")


if __name__ == "__main__":
    main()
