From 4c813e24cb528eecd494dd3b2a922ba6ea9442e4 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 18 Jul 2024 14:19:28 +0200 Subject: [PATCH 01/16] Refactor data handling and add new method for editorial publish data. - Treat data as container if "load" key exists - Added method to get editorial publish data with optional version - Updated metadata handling in LoadEditorialPackage class --- client/ayon_resolve/api/pipeline.py | 4 + client/ayon_resolve/api/plugin.py | 30 +++++ .../plugins/load/load_editorial_package.py | 121 +++++++++++++++++- 3 files changed, 149 insertions(+), 6 deletions(-) diff --git a/client/ayon_resolve/api/pipeline.py b/client/ayon_resolve/api/pipeline.py index 05d2c9bcd1..58789b2a8c 100644 --- a/client/ayon_resolve/api/pipeline.py +++ b/client/ayon_resolve/api/pipeline.py @@ -156,6 +156,10 @@ def ls(): continue data = json.loads(data) + # treat data as container + if data.get("load"): + data = data["load"] + # If not all required data, skip it required = ['schema', 'id', 'loader', 'representation'] if not all(key in data for key in required): diff --git a/client/ayon_resolve/api/plugin.py b/client/ayon_resolve/api/plugin.py index 0b339cdf7c..c3d6f33c5f 100644 --- a/client/ayon_resolve/api/plugin.py +++ b/client/ayon_resolve/api/plugin.py @@ -5,6 +5,7 @@ import qargparse from qtpy import QtWidgets, QtCore +from ayon_core.pipeline.constants import AVALON_INSTANCE_ID from ayon_core.settings import get_current_project_settings from ayon_core.pipeline import ( LegacyCreator, @@ -901,6 +902,35 @@ def _create_parents(self): self.parents.append(parent) +def get_editorial_publish_data( + folder_path, + product_name, + version=None +) -> dict: + """Get editorial publish data from context. + + Args: + folder_path (str): Folder path where editorial package is located. + product_name (str): Editorial product name. + version (Optional[str]): Editorial product version. Defaults to None. + + Returns: + dict: Editorial publish data. + """ + data = { + "id": AVALON_INSTANCE_ID, + "productType": "editorial_pkg", + "productName": product_name, + "folderPath": folder_path, + "active": True, + } + + if version: + data["version"] = version + + return data + + def get_representation_files(representation): anatomy = Anatomy() files = [] diff --git a/client/ayon_resolve/plugins/load/load_editorial_package.py b/client/ayon_resolve/plugins/load/load_editorial_package.py index 234e7b7f71..000b78d667 100644 --- a/client/ayon_resolve/plugins/load/load_editorial_package.py +++ b/client/ayon_resolve/plugins/load/load_editorial_package.py @@ -1,11 +1,15 @@ +import json from pathlib import Path +import random from ayon_core.pipeline import ( + AVALON_CONTAINER_ID, load, get_representation_path, ) from ayon_resolve.api import lib +from ayon_resolve.api.plugin import get_editorial_publish_data class LoadEditorialPackage(load.LoaderPlugin): @@ -32,21 +36,126 @@ def load(self, context, name, namespace, data): project = lib.get_current_project() media_pool = project.GetMediaPool() + folder_path = context["folder"]["path"] # create versioned bin for editorial package version_name = context["version"]["name"] - bin_name = f"{name}_{version_name}" - lib.create_bin(bin_name) - + loaded_bin = lib.create_bin(f"{folder_path}/{name}/{version_name}") + loaded_timeline_name = f"{name}_{version_name}_timeline" import_options = { - "timelineName": "Editorial Package Timeline", + "timelineName": loaded_timeline_name, "importSourceClips": True, "sourceClipsPath": search_folder_path.as_posix(), } + # import timeline from otio file timeline = media_pool.ImportTimelineFromFile(files, import_options) + + # get timeline media pool item for metadata update + timeline_media_pool_item = None + for item in lib.iter_all_media_pool_clips(root=loaded_bin): + item_name = item.GetName() + if item_name != loaded_timeline_name: + continue + timeline_media_pool_item = item + break + + # Update the metadata + if timeline_media_pool_item: + clip_data = self._get_container_data( + context, data) + + timeline_media_pool_item.SetMetadata( + lib.pype_tag_name, json.dumps(clip_data) + ) + + # set clip color based on random choice + clip_color = self.get_clip_color() + print("Clip color: ", clip_color) + timeline_media_pool_item.SetClipColor(clip_color) + + # TODO: there are two ways to import timeline resources (representation + # and resources folder) but Resolve seems to ignore any of this + # since it is importing sources automatically. But we might need + # to at least set some metadata to those loaded media pool items print("Timeline imported: ", timeline) def update(self, container, context): - # TODO: implement update method in future - pass + self.load( + context, + context["product"]["name"], + container["namespace"], + container + ) + + def _get_container_data( + self, + context: dict, + data: dict + ) -> dict: + """Return metadata related to the representation and version.""" + + # add additional metadata from the version to imprint AYON knob + version_entity = context["version"] + + # remove unnecessary keys from the data + for key in ["_item", "name"]: + if key not in data: + continue + data.pop(key) + + data = { + "load": data, + } + + # add version attributes to the load data + data["load"].update( + version_entity["attrib"] + ) + + # add variables related to version context + data["load"].update( + { + "schema": "ayon:container-3.0", + "id": AVALON_CONTAINER_ID, + "loader": str(self.__class__.__name__), + "author": version_entity["data"]["author"], + "representation": context["representation"]["id"], + "version": version_entity["version"], + } + ) + + # add publish data for streamline publishing + data["publish"] = get_editorial_publish_data( + folder_path=context["folder"]["path"], + product_name=context["product"]["name"], + version=version_entity["version"], + ) + + return data + + def get_clip_color(self): + """Return clip color based on version data.""" + + # list of all available davinci resolve clip colors + colors = [ + "Orange", + "Apricot" + "Yellow", + "Lime", + "Olive", + "Green", + "Teal", + "Navy", + "Blue", + "Purple", + "Violet", + "Pink", + "Tan", + "Beige", + "Brown", + "Chocolate", + ] + + # return one of the colors based on random position + return random.choice(colors) From c2680624f7eecf439e0f15430370c8ccb3f0676e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 18 Jul 2024 15:15:43 +0200 Subject: [PATCH 02/16] Add CreateEditorialPackage class for creating editorial packages. This commit introduces a new class, CreateEditorialPackage, which extends LegacyCreator to handle the creation of editorial packages. It includes methods to convert timelines to editorial package instances and update metadata accordingly. --- .../create/create_editorial_package.py | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 client/ayon_resolve/plugins/create/create_editorial_package.py diff --git a/client/ayon_resolve/plugins/create/create_editorial_package.py b/client/ayon_resolve/plugins/create/create_editorial_package.py new file mode 100644 index 0000000000..34d16ca1b4 --- /dev/null +++ b/client/ayon_resolve/plugins/create/create_editorial_package.py @@ -0,0 +1,46 @@ +from pprint import pformat +import json +from ayon_core.pipeline.create.legacy_create import LegacyCreator + +from ayon_resolve.api import lib + + +class CreateEditorialPackage(LegacyCreator): + """Create Editorial Package.""" + + name = "editorial_pkg" + label = "Editorial Package" + product_type = "editorial_pkg" + icon = "camera" + defaults = ["Main"] + + def process(self): + """Process the creation of the editorial package.""" + if (self.options or {}).get("useSelection"): + # if selected is on then get only timeline from media pool + # selection + self.convert_timeline_to_editorial_package_instance() + else: + # if selected is on then get only active timeline + self.convert_timeline_to_editorial_package_instance() + + def convert_timeline_to_editorial_package_instance(self): + """Convert timeline to editorial package instance.""" + current_timeline = lib.get_current_timeline() + timeline_name = current_timeline.GetName() + + # get timeline media pool item for metadata update + timeline_media_pool_item = None + for item in lib.iter_all_media_pool_clips(): + item_name = item.GetName() + if item_name != timeline_name: + continue + timeline_media_pool_item = item + break + + # Update the metadata + if timeline_media_pool_item: + publish_data = {"publish": self.data} + timeline_media_pool_item.SetMetadata( + lib.pype_tag_name, json.dumps(publish_data) + ) From e62a9c77daeb9636108ee78c5713676b84bd88c6 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 18 Jul 2024 15:17:06 +0200 Subject: [PATCH 03/16] Refactor iter_all_media_pool_clips function for flexibility - Updated iter_all_media_pool_clips to accept a root parameter for custom starting point instead of always using the project's root folder. --- client/ayon_resolve/api/lib.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/client/ayon_resolve/api/lib.py b/client/ayon_resolve/api/lib.py index 829c72b80a..9135d22d97 100644 --- a/client/ayon_resolve/api/lib.py +++ b/client/ayon_resolve/api/lib.py @@ -960,9 +960,13 @@ def get_reformated_path(path, padded=False, first=False): return path -def iter_all_media_pool_clips(): - """Recursively iterate all media pool clips in current project""" - root = get_current_project().GetMediaPool().GetRootFolder() +def iter_all_media_pool_clips(root=None): + """Recursively iterate all media pool clips in current project + + Args: + root (resolve.Folder)[optional]: root folder / bin object + """ + root = root or get_current_project().GetMediaPool().GetRootFolder() queue = [root] for folder in queue: for clip in folder.GetClipList(): From e9b431a1ab484cf1a7aba3f1ddc1111f32cf8716 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 18 Jul 2024 15:31:36 +0200 Subject: [PATCH 04/16] Remove unused import and reformat code for clarity Removed an unused import statement and reformatted the code for better readability. --- client/ayon_resolve/plugins/create/create_editorial_package.py | 1 - 1 file changed, 1 deletion(-) diff --git a/client/ayon_resolve/plugins/create/create_editorial_package.py b/client/ayon_resolve/plugins/create/create_editorial_package.py index 34d16ca1b4..7d4bd6a9a1 100644 --- a/client/ayon_resolve/plugins/create/create_editorial_package.py +++ b/client/ayon_resolve/plugins/create/create_editorial_package.py @@ -1,4 +1,3 @@ -from pprint import pformat import json from ayon_core.pipeline.create.legacy_create import LegacyCreator From 7c896a4f96221369a6c1204adc345ee9502a1200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Thu, 18 Jul 2024 15:37:38 +0200 Subject: [PATCH 05/16] Update client/ayon_resolve/api/lib.py Co-authored-by: Roy Nieterau --- client/ayon_resolve/api/lib.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/ayon_resolve/api/lib.py b/client/ayon_resolve/api/lib.py index 95d8729a92..932bfb2691 100644 --- a/client/ayon_resolve/api/lib.py +++ b/client/ayon_resolve/api/lib.py @@ -961,7 +961,8 @@ def iter_all_media_pool_clips(root=None): """Recursively iterate all media pool clips in current project Args: - root (resolve.Folder)[optional]: root folder / bin object + root (Optional[resolve.Folder]): root folder / bin object. + When None, defaults to media pool root folder. """ root = root or get_current_project().GetMediaPool().GetRootFolder() queue = [root] From 64071b6cafaf7ec724ffea01890937ed6b8fa206 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 18 Jul 2024 15:44:35 +0200 Subject: [PATCH 06/16] Refactor data handling logic in ls function - Refactored ls function to handle 'load' data specifically. --- client/ayon_resolve/api/pipeline.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/ayon_resolve/api/pipeline.py b/client/ayon_resolve/api/pipeline.py index 58789b2a8c..d68ba228ef 100644 --- a/client/ayon_resolve/api/pipeline.py +++ b/client/ayon_resolve/api/pipeline.py @@ -157,6 +157,9 @@ def ls(): data = json.loads(data) # treat data as container + # There might be cases where clip's metadata are having additional + # because it needs to store 'load' and 'publish' data. In that case + # we need to get only 'load' data if data.get("load"): data = data["load"] From 7a8c241e8d451d3e856058deb2c9d409c405a854 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 18 Jul 2024 15:46:32 +0200 Subject: [PATCH 07/16] Remove redundant method and streamline timeline retrieval in CreateEditorialPackage. - Removed duplicate method for converting timeline to editorial package instance. - Updated process method to directly retrieve current timeline for conversion. --- .../plugins/create/create_editorial_package.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/client/ayon_resolve/plugins/create/create_editorial_package.py b/client/ayon_resolve/plugins/create/create_editorial_package.py index 7d4bd6a9a1..407081a2bf 100644 --- a/client/ayon_resolve/plugins/create/create_editorial_package.py +++ b/client/ayon_resolve/plugins/create/create_editorial_package.py @@ -15,16 +15,6 @@ class CreateEditorialPackage(LegacyCreator): def process(self): """Process the creation of the editorial package.""" - if (self.options or {}).get("useSelection"): - # if selected is on then get only timeline from media pool - # selection - self.convert_timeline_to_editorial_package_instance() - else: - # if selected is on then get only active timeline - self.convert_timeline_to_editorial_package_instance() - - def convert_timeline_to_editorial_package_instance(self): - """Convert timeline to editorial package instance.""" current_timeline = lib.get_current_timeline() timeline_name = current_timeline.GetName() From e39f5b57869f0100a36488ec1d362b50dbe8d390 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 18 Jul 2024 15:50:45 +0200 Subject: [PATCH 08/16] Add error handling for missing timeline in media pool - Added a check to handle cases where the timeline is not found in the media pool, raising a NameError. - Refactored code to set clip color based on a random choice. --- .../create/create_editorial_package.py | 2 ++ .../plugins/load/load_editorial_package.py | 21 +++++++++---------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/client/ayon_resolve/plugins/create/create_editorial_package.py b/client/ayon_resolve/plugins/create/create_editorial_package.py index 407081a2bf..19f10fc170 100644 --- a/client/ayon_resolve/plugins/create/create_editorial_package.py +++ b/client/ayon_resolve/plugins/create/create_editorial_package.py @@ -33,3 +33,5 @@ def process(self): timeline_media_pool_item.SetMetadata( lib.pype_tag_name, json.dumps(publish_data) ) + else: + NameError("Timeline not found in media pool.") diff --git a/client/ayon_resolve/plugins/load/load_editorial_package.py b/client/ayon_resolve/plugins/load/load_editorial_package.py index 000b78d667..ed6b7efa4a 100644 --- a/client/ayon_resolve/plugins/load/load_editorial_package.py +++ b/client/ayon_resolve/plugins/load/load_editorial_package.py @@ -61,18 +61,17 @@ def load(self, context, name, namespace, data): break # Update the metadata - if timeline_media_pool_item: - clip_data = self._get_container_data( - context, data) + clip_data = self._get_container_data( + context, data) - timeline_media_pool_item.SetMetadata( - lib.pype_tag_name, json.dumps(clip_data) - ) + timeline_media_pool_item.SetMetadata( + lib.pype_tag_name, json.dumps(clip_data) + ) + + # set clip color based on random choice + clip_color = self.get_clip_color() + timeline_media_pool_item.SetClipColor(clip_color) - # set clip color based on random choice - clip_color = self.get_clip_color() - print("Clip color: ", clip_color) - timeline_media_pool_item.SetClipColor(clip_color) # TODO: there are two ways to import timeline resources (representation # and resources folder) but Resolve seems to ignore any of this @@ -135,7 +134,7 @@ def _get_container_data( return data def get_clip_color(self): - """Return clip color based on version data.""" + """Return clip color.""" # list of all available davinci resolve clip colors colors = [ From 2e7b487e671fbb1e14b7cb8b810fb711c2255168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Mon, 22 Jul 2024 11:17:56 +0200 Subject: [PATCH 09/16] Update client/ayon_resolve/plugins/load/load_editorial_package.py Co-authored-by: Roy Nieterau --- client/ayon_resolve/plugins/load/load_editorial_package.py | 1 - 1 file changed, 1 deletion(-) diff --git a/client/ayon_resolve/plugins/load/load_editorial_package.py b/client/ayon_resolve/plugins/load/load_editorial_package.py index ed6b7efa4a..013db78350 100644 --- a/client/ayon_resolve/plugins/load/load_editorial_package.py +++ b/client/ayon_resolve/plugins/load/load_editorial_package.py @@ -72,7 +72,6 @@ def load(self, context, name, namespace, data): clip_color = self.get_clip_color() timeline_media_pool_item.SetClipColor(clip_color) - # TODO: there are two ways to import timeline resources (representation # and resources folder) but Resolve seems to ignore any of this # since it is importing sources automatically. But we might need From 7fca4242382b7a137dd1d7e9cc8c6179773af153 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 25 Jul 2024 17:30:03 +0200 Subject: [PATCH 10/16] WIP on feature/AY-979_Resolve-update-to-new-publisher --- client/ayon_resolve/api/lib.py | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/client/ayon_resolve/api/lib.py b/client/ayon_resolve/api/lib.py index 932bfb2691..807ee60c07 100644 --- a/client/ayon_resolve/api/lib.py +++ b/client/ayon_resolve/api/lib.py @@ -1,7 +1,8 @@ import sys -import json import re import os +import json +import uuid import contextlib from typing import List, Dict, Any from opentimelineio import opentime @@ -40,6 +41,27 @@ self.pype_timeline_name = "OpenPypeTimeline" +def get_timeline_media_pool_item(timeline, root=None): + """Return MediaPoolItem from Timeline""" + + # Due to limitations in the Resolve API we can't get + # the media pool item directly from the timeline. + # We can find it by name, however names are not + # enforced to be unique across bins. So, we give it + # unique name. + original_name = timeline.GetName() + identifier = str(uuid.uuid4().hex) + try: + timeline.SetName(identifier) + for item in iter_all_media_pool_clips(root=root): + if item.GetName() != identifier: + continue + return item + finally: + # Revert to original name + timeline.SetName(original_name) + + @contextlib.contextmanager def maintain_current_timeline(to_timeline: object, from_timeline: object = None): From 9d3a824c3d551d5222dd64a019c5fe68821f0497 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 25 Jul 2024 17:36:30 +0200 Subject: [PATCH 11/16] Update get_timeline_media_pool_item function signature and add detailed docstring. - Updated get_timeline_media_pool_item function to accept timeline and root arguments. - Added detailed docstring specifying the argument types and return type for better clarity. --- client/ayon_resolve/api/lib.py | 13 +++++++++++-- .../plugins/load/load_editorial_package.py | 10 +++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/client/ayon_resolve/api/lib.py b/client/ayon_resolve/api/lib.py index 807ee60c07..eee403ca1d 100644 --- a/client/ayon_resolve/api/lib.py +++ b/client/ayon_resolve/api/lib.py @@ -41,8 +41,17 @@ self.pype_timeline_name = "OpenPypeTimeline" -def get_timeline_media_pool_item(timeline, root=None): - """Return MediaPoolItem from Timeline""" +def get_timeline_media_pool_item(timeline, root=None) -> object: + """Return MediaPoolItem from Timeline + + + Args: + timeline (resolve.Timeline): timeline object + root (resolve.Folder): root folder / bin object + + Returns: + resolve.MediaPoolItem: media pool item from timeline + """ # Due to limitations in the Resolve API we can't get # the media pool item directly from the timeline. diff --git a/client/ayon_resolve/plugins/load/load_editorial_package.py b/client/ayon_resolve/plugins/load/load_editorial_package.py index 013db78350..38905f6d55 100644 --- a/client/ayon_resolve/plugins/load/load_editorial_package.py +++ b/client/ayon_resolve/plugins/load/load_editorial_package.py @@ -52,13 +52,9 @@ def load(self, context, name, namespace, data): timeline = media_pool.ImportTimelineFromFile(files, import_options) # get timeline media pool item for metadata update - timeline_media_pool_item = None - for item in lib.iter_all_media_pool_clips(root=loaded_bin): - item_name = item.GetName() - if item_name != loaded_timeline_name: - continue - timeline_media_pool_item = item - break + timeline_media_pool_item = lib.get_timeline_media_pool_item( + timeline, loaded_bin + ) # Update the metadata clip_data = self._get_container_data( From 9f0040e73a94a981921d8a28586cb53ebdcf80ff Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 29 Jul 2024 11:31:00 +0200 Subject: [PATCH 12/16] Refactor metadata update process in CreateEditorialPackage Simplify metadata update process by refactoring code for better readability and maintainability. --- .../create/create_editorial_package.py | 29 +++++++------------ 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/client/ayon_resolve/plugins/create/create_editorial_package.py b/client/ayon_resolve/plugins/create/create_editorial_package.py index 19f10fc170..4a00a51e4a 100644 --- a/client/ayon_resolve/plugins/create/create_editorial_package.py +++ b/client/ayon_resolve/plugins/create/create_editorial_package.py @@ -16,22 +16,13 @@ class CreateEditorialPackage(LegacyCreator): def process(self): """Process the creation of the editorial package.""" current_timeline = lib.get_current_timeline() - timeline_name = current_timeline.GetName() - - # get timeline media pool item for metadata update - timeline_media_pool_item = None - for item in lib.iter_all_media_pool_clips(): - item_name = item.GetName() - if item_name != timeline_name: - continue - timeline_media_pool_item = item - break - - # Update the metadata - if timeline_media_pool_item: - publish_data = {"publish": self.data} - timeline_media_pool_item.SetMetadata( - lib.pype_tag_name, json.dumps(publish_data) - ) - else: - NameError("Timeline not found in media pool.") + + timeline_media_pool_item = lib.get_timeline_media_pool_item( + current_timeline + ) + + publish_data = {"publish": self.data} + + timeline_media_pool_item.SetMetadata( + lib.pype_tag_name, json.dumps(publish_data) + ) From 0bd5eb5a8dba7644b7fe7d67dfd0da68873adb16 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 29 Jul 2024 11:32:57 +0200 Subject: [PATCH 13/16] suggestion https://github.com/ynput/ayon-resolve/pull/11#discussion_r1682849058 --- client/ayon_resolve/plugins/create/create_editorial_package.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/ayon_resolve/plugins/create/create_editorial_package.py b/client/ayon_resolve/plugins/create/create_editorial_package.py index 4a00a51e4a..67ae9c3edb 100644 --- a/client/ayon_resolve/plugins/create/create_editorial_package.py +++ b/client/ayon_resolve/plugins/create/create_editorial_package.py @@ -17,6 +17,9 @@ def process(self): """Process the creation of the editorial package.""" current_timeline = lib.get_current_timeline() + if not current_timeline: + raise RuntimeError("Make sure to have an active current timeline.") + timeline_media_pool_item = lib.get_timeline_media_pool_item( current_timeline ) From 8cf50d065164e5b5a580faa59191ed5d80b7e73f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 8 Aug 2024 11:42:32 +0200 Subject: [PATCH 14/16] Refactor timeline naming logic for editorial package - Refactored timeline name creation based on folder path - Added metadata clearing for timeline clips --- .../ayon_resolve/plugins/load/load_editorial_package.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/client/ayon_resolve/plugins/load/load_editorial_package.py b/client/ayon_resolve/plugins/load/load_editorial_package.py index 38905f6d55..1e4d95c6e6 100644 --- a/client/ayon_resolve/plugins/load/load_editorial_package.py +++ b/client/ayon_resolve/plugins/load/load_editorial_package.py @@ -41,7 +41,11 @@ def load(self, context, name, namespace, data): # create versioned bin for editorial package version_name = context["version"]["name"] loaded_bin = lib.create_bin(f"{folder_path}/{name}/{version_name}") - loaded_timeline_name = f"{name}_{version_name}_timeline" + + # make timeline unique name based on folder path + folder_path_name = folder_path.replace("/", "_").lstrip("_") + loaded_timeline_name = ( + f"{folder_path_name}_{name}_{version_name}_timeline") import_options = { "timelineName": loaded_timeline_name, "importSourceClips": True, @@ -75,6 +79,9 @@ def load(self, context, name, namespace, data): print("Timeline imported: ", timeline) def update(self, container, context): + timeline_mp_clip = container["_item"] + timeline_mp_clip.SetMetadata(lib.pype_tag_name, "") + self.load( context, context["product"]["name"], From 4a57cd4e3d0c2a28acb5560997f74934971ac1d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Wed, 18 Sep 2024 17:19:22 +0200 Subject: [PATCH 15/16] Update client/ayon_resolve/plugins/load/load_editorial_package.py Co-authored-by: Robin De Lillo --- client/ayon_resolve/plugins/load/load_editorial_package.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/client/ayon_resolve/plugins/load/load_editorial_package.py b/client/ayon_resolve/plugins/load/load_editorial_package.py index 1e4d95c6e6..c63e79566a 100644 --- a/client/ayon_resolve/plugins/load/load_editorial_package.py +++ b/client/ayon_resolve/plugins/load/load_editorial_package.py @@ -99,11 +99,8 @@ def _get_container_data( # add additional metadata from the version to imprint AYON knob version_entity = context["version"] - # remove unnecessary keys from the data - for key in ["_item", "name"]: - if key not in data: - continue - data.pop(key) + for key in ("_item", "name"): + data.pop(key, None) # remove unnecessary key from the data if it exists data = { "load": data, From c860167891df3e3e9b3f1ff928331ed85fb5884e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 18 Sep 2024 17:31:48 +0200 Subject: [PATCH 16/16] Update method name to get_random_clip_color for clarity. - Renamed method from get_clip_color to get_random_clip_color for better understanding. --- client/ayon_resolve/plugins/load/load_editorial_package.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_resolve/plugins/load/load_editorial_package.py b/client/ayon_resolve/plugins/load/load_editorial_package.py index c63e79566a..4d65365119 100644 --- a/client/ayon_resolve/plugins/load/load_editorial_package.py +++ b/client/ayon_resolve/plugins/load/load_editorial_package.py @@ -69,7 +69,7 @@ def load(self, context, name, namespace, data): ) # set clip color based on random choice - clip_color = self.get_clip_color() + clip_color = self.get_random_clip_color() timeline_media_pool_item.SetClipColor(clip_color) # TODO: there are two ways to import timeline resources (representation @@ -132,7 +132,7 @@ def _get_container_data( return data - def get_clip_color(self): + def get_random_clip_color(self): """Return clip color.""" # list of all available davinci resolve clip colors