diff --git a/pype/hosts/resolve/__init__.py b/pype/hosts/resolve/__init__.py index b7e6c7dee3..5f651f4b29 100644 --- a/pype/hosts/resolve/__init__.py +++ b/pype/hosts/resolve/__init__.py @@ -17,6 +17,9 @@ from .lib import ( get_project_manager, get_current_project, get_current_sequence, + get_current_track_items, + create_current_sequence_media_bin, + create_compound_clip, set_project_manager_to_folder_name ) @@ -33,7 +36,8 @@ from .workio import ( work_root ) -bmd = None +bmdvr = None +bmdvf = None __all__ = [ # pipeline @@ -54,6 +58,9 @@ __all__ = [ "get_project_manager", "get_current_project", "get_current_sequence", + "get_current_track_items", + "create_current_sequence_media_bin", + "create_compound_clip", "set_project_manager_to_folder_name", # menu @@ -71,5 +78,6 @@ __all__ = [ "work_root", # singleton with black magic resolve module - "bmd" + "bmdvr", + "bmdvf" ] diff --git a/pype/hosts/resolve/lib.py b/pype/hosts/resolve/lib.py index 25e177eb1c..9232f8ec68 100644 --- a/pype/hosts/resolve/lib.py +++ b/pype/hosts/resolve/lib.py @@ -8,9 +8,9 @@ self.pm = None def get_project_manager(): - from . import bmd + from . import bmdvr if not self.pm: - self.pm = bmd.GetProjectManager() + self.pm = bmdvr.GetProjectManager() return self.pm @@ -28,6 +28,207 @@ def get_current_sequence(): return project.GetCurrentTimeline() +def get_current_track_items( + filter=False, + track_type=None, + selecting_color=None): + """ Gets all available current timeline track items + """ + from pprint import pformat + track_type = track_type or "video" + selecting_color = selecting_color or "Chocolate" + project = get_current_project() + sequence = get_current_sequence() + selected_clips = list() + + # get all tracks count filtered by track type + sequence_video_count = sequence.GetTrackCount(track_type) + + # loop all tracks and get items + _clips = dict() + for track_index in range(1, (int(sequence_video_count) + 1)): + track_name = sequence.GetTrackName(track_type, track_index) + track_track_items = sequence.GetItemListInTrack( + track_type, track_index) + _clips[track_index] = track_track_items + + _data = { + "project": project, + "sequence": sequence, + "track": { + "name": track_name, + "index": track_index, + "type": track_type} + } + # get track item object and its color + for clip_index, ti in enumerate(_clips[track_index]): + data = _data.copy() + data["clip"] = { + "item": ti, + "index": clip_index + } + ti_color = ti.GetClipColor() + if filter is True: + if selecting_color in ti_color: + selected_clips.append(data) + ti.ClearClipColor() + else: + selected_clips.append(data) + + return selected_clips + + +def create_current_sequence_media_bin(sequence): + seq_name = sequence.GetName() + media_pool = get_current_project().GetMediaPool() + root_folder = media_pool.GetRootFolder() + sub_folders = root_folder.GetSubFolderList() + testing_names = list() + + print(f"_ sub_folders: {sub_folders}") + for subfolder in sub_folders: + subf_name = subfolder.GetName() + if seq_name in subf_name: + testing_names.append(subfolder) + else: + testing_names.append(False) + + matching = next((f for f in testing_names if f is not False), None) + + if not matching: + new_folder = media_pool.AddSubFolder(root_folder, seq_name) + media_pool.SetCurrentFolder(new_folder) + else: + media_pool.SetCurrentFolder(matching) + + return media_pool.GetCurrentFolder() + + +def create_compound_clip(clip_data, folder, presets): + """ + Convert timeline object into nested timeline object + + Args: + clip_data (dict): timeline item object packed into dict + with project, timeline (sequence) + folder (resolve.MediaPool.Folder): media pool folder object, + presets (dict): pype config plugin presets + + Returns: + resolve.MediaPoolItem: media pool item with compound clip timeline(cct) + """ + from pprint import pformat + + # get basic objects form data + project = clip_data["project"] + sequence = clip_data["sequence"] + clip = clip_data["clip"] + + # get details of objects + clip_item = clip["item"] + track = clip_data["track"] + + # build name + clip_name_split = clip_item.GetName().split(".") + name = "_".join([ + track["name"], + str(track["index"]), + clip_name_split[0], + str(clip["index"])] + ) + + # get metadata + mp_item = clip_item.GetMediaPoolItem() + mp_props = mp_item.GetClipProperty() + metadata = get_metadata_from_clip(clip_item) + mp = project.GetMediaPool() + + # keep original sequence + sq_origin = sequence + + # print(f"_ sequence: {sequence}") + # print(f"_ metadata: {pformat(metadata)}") + + # Set current folder to input media_pool_folder: + mp.SetCurrentFolder(folder) + + # check if clip doesnt exist already: + clips = folder.GetClipList() + cct = next((c for c in clips + if c.GetName() in name), None) + + if cct: + print(f"_ cct exists: {cct}") + return cct + + # Create empty timeline in current folder and give name: + cct = mp.CreateEmptyTimeline(name) + print(f"_ cct: {cct}") + + # Set current timeline to created timeline: + project.SetCurrentTimeline(cct) + + # Add input clip to the current timeline: + # TODO: set offsets if handles + done = mp.AppendToTimeline([{ + "mediaPoolItem": mp_item, + "startFrame": int(mp_props["Start"]), + "endFrame": int(mp_props["End"]) + }]) + print(f"_ done1: {done}") + + # Set current timeline to the working timeline: + project.SetCurrentTimeline(sq_origin) + + # Add collected metadata to the comound clip: + done = mp_item.SetClipProperty("pypeMetadata", metadata) + print(f"_ done2: {done}") + + return cct + + +def validate_tc(x): + # Validate and reformat timecode string + + if len(x) != 11: + print('Invalid timecode. Try again.') + + c = ':' + colonized = x[:2] + c + x[3:5] + c + x[6:8] + c + x[9:] + + if colonized.replace(':', '').isdigit(): + print(f"_ colonized: {colonized}") + return colonized + else: + print('Invalid timecode. Try again.') + + +def get_metadata_from_clip(clip): + """ + Collect all metadata from resolve timeline item + + Args: + clip (resolve.TimelineItem): timeline item object + + Returns: + dict: all collected metadata as key: values + """ + mp_item = clip.GetMediaPoolItem() + + data = { + "clipIn": clip.GetStart(), + "clipOut": clip.GetEnd(), + "clipLeftOffset": clip.GetLeftOffset(), + "clipRightOffset": clip.GetRightOffset(), + "clipMarkers": clip.GetMarkers(), + "clipFlags": clip.GetFlagList(), + "sourceMetadata": mp_item.GetMetadata(), + "sourceId": mp_item.GetMediaId(), + "sourceProperties": mp_item.GetClipProperty() + } + return data + + def set_project_manager_to_folder_name(folder_name): """ Sets context of Project manager to given folder by name. diff --git a/pype/hosts/resolve/pipeline.py b/pype/hosts/resolve/pipeline.py index 91d06da274..92bef2e13b 100644 --- a/pype/hosts/resolve/pipeline.py +++ b/pype/hosts/resolve/pipeline.py @@ -152,29 +152,11 @@ def maintained_selection(): >>> print(node['selected'].value()) False """ - from . import get_current_project - project = get_current_project() - nodes = [] - previous_selection = None - - # deselect all nodes - reset_selection() - try: # do the operation yield finally: - # unselect all selection in case there is some - reset_selection() - # and select all previously selected nodes - if previous_selection: - try: - for n in nodes: - if n not in previous_selection: - continue - n['selected'].setValue(True) - except ValueError as e: - log.warning(e) + pass def reset_selection(): diff --git a/pype/hosts/resolve/plugin.py b/pype/hosts/resolve/plugin.py index 513b9984f4..002d12106d 100644 --- a/pype/hosts/resolve/plugin.py +++ b/pype/hosts/resolve/plugin.py @@ -89,6 +89,10 @@ class Creator(api.Creator): # adding basic current context resolve objects self.project = resolve.get_current_project() self.sequence = resolve.get_current_sequence() - - # TODO: make sure no duplicity of subsets are in workfile + + if (self.options or {}).get("useSelection"): + self.selected = resolve.get_current_track_items(filter=True) + else: + self.selected = resolve.get_current_track_items(filter=False) + return diff --git a/pype/hosts/resolve/utility_scripts/test.py b/pype/hosts/resolve/utility_scripts/test.py index 4c43507e62..cf7db3b7e5 100644 --- a/pype/hosts/resolve/utility_scripts/test.py +++ b/pype/hosts/resolve/utility_scripts/test.py @@ -10,8 +10,8 @@ def main(): bm = bmdvr.utils.get_resolve_module() log.info(f"blackmagicmodule: {bm}") -import DaVinciResolveScript as bmd -print(f"_>> bmd.scriptapp(Resolve): {bmd.scriptapp('Resolve')}") +import DaVinciResolveScript as bmdvr +print(f"_>> bmdvr.scriptapp(Resolve): {bmdvr.scriptapp('Resolve')}") if __name__ == "__main__": diff --git a/pype/hosts/resolve/utils.py b/pype/hosts/resolve/utils.py index 74ce2dc98f..dcc92c5b8d 100644 --- a/pype/hosts/resolve/utils.py +++ b/pype/hosts/resolve/utils.py @@ -15,10 +15,10 @@ log = Logger().get_logger(__name__, "resolve") def get_resolve_module(): from pype.hosts import resolve # dont run if already loaded - if resolve.bmd: + if resolve.bmdvr: log.info(("resolve module is assigned to " - f"`pype.hosts.resolve.bmd`: {resolve.bmd}")) - return resolve.bmd + f"`pype.hosts.resolve.bmdvr`: {resolve.bmdvr}")) + return resolve.bmdvr try: """ The PYTHONPATH needs to be set correctly for this import @@ -69,10 +69,14 @@ def get_resolve_module(): ) sys.exit() # assign global var and return - bmd = bmd.scriptapp("Resolve") - resolve.bmd = bmd + bmdvr = bmd.scriptapp("Resolve") + bmdvf = bmd.scriptapp("Fusion") + resolve.bmdvr = bmdvr + resolve.bmdvf = bmdvf log.info(("Assigning resolve module to " - f"`pype.hosts.resolve.bmd`: {resolve.bmd}")) + f"`pype.hosts.resolve.bmdvr`: {resolve.bmdvr}")) + log.info(("Assigning resolve module to " + f"`pype.hosts.resolve.bmdvf`: {resolve.bmdvf}")) def _sync_utility_scripts(env=None): diff --git a/pype/plugins/resolve/create/create_shot_clip.py b/pype/plugins/resolve/create/create_shot_clip.py index 43a8ab0cbd..c48ca3a5a6 100644 --- a/pype/plugins/resolve/create/create_shot_clip.py +++ b/pype/plugins/resolve/create/create_shot_clip.py @@ -1,6 +1,6 @@ +from pprint import pformat from pype.hosts import resolve - class CreateShotClip(resolve.Creator): """Publishable clip""" @@ -12,6 +12,25 @@ class CreateShotClip(resolve.Creator): presets = None def process(self): - print(f"Project name: {self.project.GetName()}") - print(f"Sequence name: {self.sequence.GetName()}") - print(self.presets) + project = self.project + sequence = self.sequence + presets = self.presets + print(f"__ selected_clips: {self.selected}") + + # sequence attrs + sq_frame_start = self.sequence.GetStartFrame() + sq_markers = self.sequence.GetMarkers() + print(f"__ sq_frame_start: {pformat(sq_frame_start)}") + print(f"__ seq_markers: {pformat(sq_markers)}") + + # create media bin for compound clips (trackItems) + mp_folder = resolve.create_current_sequence_media_bin(self.sequence) + print(f"_ mp_folder: {mp_folder.GetName()}") + + for t_data in self.selected: + print(t_data) + # convert track item to timeline media pool item + c_clip = resolve.create_compound_clip( + t_data, mp_folder, presets) + + # replace orig clip with compound_clip