From 558b934c687c2976fb1afc220a7d37dd3eb71737 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 20 Jan 2022 22:03:09 +0100 Subject: [PATCH 01/27] flame: fix collecting files to representation in case of custom flame export preset with multiple nested structures --- .../publish/extract_subset_resources.py | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index 291e440cbe..8cc27aff06 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -129,16 +129,23 @@ class ExtractSubsetResources(openpype.api.Extractor): opfapi.export_clip( export_dir_path, duplclip, preset_path, **kwargs) + extension = preset_config["ext"] # create representation data representation_data = { "name": unique_name, "outputName": unique_name, - "ext": preset_config["ext"], + "ext": extension, "stagingDir": export_dir_path, "tags": repre_tags } files = os.listdir(export_dir_path) + n_stage_dir, n_files = self.check_if_dirs_in_paths( + export_dir_path, files, extension) + + if n_stage_dir: + representation_data["stagingDir"] = n_stage_dir + files = n_files # add files to represetation but add # imagesequence as list @@ -170,3 +177,35 @@ class ExtractSubsetResources(openpype.api.Extractor): self.log.debug("All representations: {}".format( pformat(instance.data["representations"]))) + + def check_if_dirs_in_paths(self, stage_dir, files_list, ext): + + if ( + len(files_list) == 1 + and ext in os.path.splitext(files_list[0])[-1] + ): + + return None, None + + new_stage_dir = None + new_files_list = [] + for file in files_list: + search_path = os.path.join(stage_dir, file) + if not os.path.isdir(search_path): + continue + for root, _dirs, files in os.walk(search_path): + for _file in files: + _fn, _ext = os.path.splitext(_file) + if ext.lower() != _ext[1:].lower(): + continue + new_files_list.append(_file) + if not new_stage_dir: + new_stage_dir = root + + if new_stage_dir: + return new_stage_dir, new_files_list + else: + raise IOError( + "Files in `{}` are not correct! Check `{}`".format( + files_list, stage_dir) + ) From 4f7bcceaddeef602a959dea32ed1ace2e14fdeab Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 21 Jan 2022 10:38:47 +0100 Subject: [PATCH 02/27] Flame: nested folder renamed and doc-string added --- .../publish/extract_subset_resources.py | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index 8cc27aff06..8d244b312b 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -139,10 +139,14 @@ class ExtractSubsetResources(openpype.api.Extractor): "tags": repre_tags } + # collect all available content of export dir files = os.listdir(export_dir_path) - n_stage_dir, n_files = self.check_if_dirs_in_paths( + + # make sure no nested folders inside + n_stage_dir, n_files = self._unfolds_nested_folders( export_dir_path, files, extension) + # fix representation in case of nested folders if n_stage_dir: representation_data["stagingDir"] = n_stage_dir files = n_files @@ -178,13 +182,28 @@ class ExtractSubsetResources(openpype.api.Extractor): self.log.debug("All representations: {}".format( pformat(instance.data["representations"]))) - def check_if_dirs_in_paths(self, stage_dir, files_list, ext): + def _unfolds_nested_folders(self, stage_dir, files_list, ext): + """Unfolds nested folders + Args: + stage_dir (str): path string with directory + files_list (list): list of file names + ext (str): extension (jpg)[without dot] + + Raises: + IOError: in case no files were collected form any directory + + Returns: + str, list: new staging dir path, new list of file names + or + None, None: In case single file in `files_list` + """ + # exclude single files which are having extension + # the same as input ext attr if ( len(files_list) == 1 and ext in os.path.splitext(files_list[0])[-1] ): - return None, None new_stage_dir = None From 279e7d863145ad3641c0afd43bc539480ddcfe6a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 21 Jan 2022 12:06:05 +0100 Subject: [PATCH 03/27] Flame: distribute colorspace to representations --- .../hosts/flame/plugins/publish/extract_subset_resources.py | 6 +++++- openpype/settings/defaults/project_settings/flame.json | 3 ++- .../schemas/projects_schema/schema_project_flame.json | 5 +++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index 8d244b312b..a0345d5175 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -22,6 +22,7 @@ class ExtractSubsetResources(openpype.api.Extractor): "ext": "jpg", "xml_preset_file": "Jpeg (8-bit).xml", "xml_preset_dir": "", + "colorspace_out": "Output - sRGB", "representation_add_range": False, "representation_tags": ["thumbnail"] }, @@ -29,6 +30,7 @@ class ExtractSubsetResources(openpype.api.Extractor): "ext": "mov", "xml_preset_file": "Apple iPad (1920x1080).xml", "xml_preset_dir": "", + "colorspace_out": "Output - Rec.709", "representation_add_range": True, "representation_tags": [ "review", @@ -84,6 +86,7 @@ class ExtractSubsetResources(openpype.api.Extractor): preset_file = preset_config["xml_preset_file"] preset_dir = preset_config["xml_preset_dir"] repre_tags = preset_config["representation_tags"] + color_out = preset_config["colorspace_out"] # validate xml preset file is filled if preset_file == "": @@ -136,7 +139,8 @@ class ExtractSubsetResources(openpype.api.Extractor): "outputName": unique_name, "ext": extension, "stagingDir": export_dir_path, - "tags": repre_tags + "tags": repre_tags, + "colorspace": color_out } # collect all available content of export dir diff --git a/openpype/settings/defaults/project_settings/flame.json b/openpype/settings/defaults/project_settings/flame.json index c81069ef5c..3caf190e37 100644 --- a/openpype/settings/defaults/project_settings/flame.json +++ b/openpype/settings/defaults/project_settings/flame.json @@ -24,8 +24,9 @@ "export_presets_mapping": { "exr16fpdwaa": { "ext": "exr", - "xml_preset_dir": "", "xml_preset_file": "OpenEXR (16-bit fp DWAA).xml", + "xml_preset_dir": "", + "colorspace_out": "ACES - ACEScg", "representation_add_range": true, "representation_tags": [] } diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_flame.json b/openpype/settings/entities/schemas/projects_schema/schema_project_flame.json index 76576ebf73..4cb1a0bb2b 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_flame.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_flame.json @@ -166,6 +166,11 @@ "label": "XML preset folder (optional)", "type": "text" }, + { + "key": "colorspace_out", + "label": "Output color (imageio)", + "type": "text" + }, { "type": "separator" }, From dc419ceaed338fe8c45f5e32d21386a4eabaa9c8 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 21 Jan 2022 12:46:35 +0100 Subject: [PATCH 04/27] flame: add colorspace to representation["data"] --- .../publish/extract_subset_resources.py | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index a0345d5175..a80366b9e4 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -47,6 +47,16 @@ class ExtractSubsetResources(openpype.api.Extractor): export_presets_mapping = {} def process(self, instance): + try: + self._process(instance) + # bring ui back + self.hide_ui_on_process = False + except Exception as msg: + self.log.error(msg) + # bring ui back + self.hide_ui_on_process = False + + def _process(self, instance): if ( self.keep_original_representation @@ -140,7 +150,9 @@ class ExtractSubsetResources(openpype.api.Extractor): "ext": extension, "stagingDir": export_dir_path, "tags": repre_tags, - "colorspace": color_out + "data": { + "colorspace": color_out + } } # collect all available content of export dir @@ -205,10 +217,23 @@ class ExtractSubsetResources(openpype.api.Extractor): # exclude single files which are having extension # the same as input ext attr if ( + # only one file in list len(files_list) == 1 + # file is having extension as input and ext in os.path.splitext(files_list[0])[-1] ): return None, None + elif ( + # more then one file in list + len(files_list) >= 1 + # extension is correct + and ext in os.path.splitext(files_list[0])[-1] + # test file exists + and os.path.exists( + os.path.join(stage_dir, files_list[0]) + ) + ): + return None, None new_stage_dir = None new_files_list = [] From 1736b5338fed9af89428a81220416b486c03277a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 25 Jan 2022 17:18:22 +0100 Subject: [PATCH 05/27] flame: trying export openclip wip --- openpype/hosts/flame/api/render_utils.py | 320 +++++++++++++++++++++++ 1 file changed, 320 insertions(+) diff --git a/openpype/hosts/flame/api/render_utils.py b/openpype/hosts/flame/api/render_utils.py index 1b086646cc..bc9ebb83d4 100644 --- a/openpype/hosts/flame/api/render_utils.py +++ b/openpype/hosts/flame/api/render_utils.py @@ -1,4 +1,10 @@ import os +import sys +import traceback +from xml.etree import ElementTree as ET +import shutil +import openpype.lib +import six def export_clip(export_path, clip, preset_path, **kwargs): @@ -123,3 +129,317 @@ def get_preset_path_by_xml_name(xml_preset_name): # if nothing found then return False return False + + +def get_open_clip( + openclip_file_path, feed_data, recursive=False): + + # establish media script path and test it + media_script_path = "/opt/Autodesk/mio/current/dl_get_media_info" + if not os.path.isfile(media_script_path): + raise IOError("Media Scirpt does not exist: `{}`".format( + media_script_path)) + + # new feed variables: + feed_path = feed_data["path"] + feed_basename = os.path.basename(feed_path) + feed_version_name = feed_data["version"] + + clip_uploaded = False + create_new_clip = False + + ext_whitelist = [ + "cin", "als", "jpg", "jpeg", "pict", "pct", "picio", + "sgi", "pic", "tga", "iff", "tdi", "tif", "tiff", "rla", + "cin.pxz", "tif.pxz", "tiff.pxz", "dpx", "dpx.pxz", + "hdr", "png", "exr", "exr.pxz", "psd" + ] + + feed_ext = os.path.splitext(feed_basename)[1][1:].lower() + + if feed_ext not in ext_whitelist: + print("File extension `{}` is not supported".format(feed_ext)) + return False + + if not os.path.isfile(openclip_file_path): + # openclip does not exist yet and will be created + feed_path = os.path.abspath(feed_path) + tmp_file = openclip_file_path + create_new_clip = True + clip_uploaded = True + else: + # openclip will be updated via temp.clip file + tmp_name = "tmp.clip" + feed_path = os.path.abspath(feed_path) + feed_dir = os.path.dirname(feed_path) + + # output a temp file + tmp_file = os.path.join(feed_dir, tmp_name) + if os.path.isfile(tmp_file): + os.remove(tmp_file) + + print("Temp File: {}".format(tmp_file)) + + # Write output of getMediaScript to file + cmd_args = [media_script_path, feed_path] + if recursive: + print("recursive enabled on dl_get_media_info") + cmd_args = [media_script_path, "-r", feed_path] + + # execute creation of clip xml template data + try: + output = openpype.lib.run_subprocess(cmd_args) + except TypeError: + print("Error createing tmp_file") + six.reraise(*sys.exc_info()) + + with open(tmp_file, "w") as f: + f.write("{}".format(output)) + + # Check media type for valid extension + try: + tmp_xml = ET.parse(tmp_file) + except: + print("XML is probably empty.") + print('{}'.format(traceback.print_exc())) + if os.path.isfile(tmp_file): + os.remove(tmp_file) + return False + + for newTrack in tmp_xml.iter('track'): + new_path_obj = newTrack.find("feeds/feed/spans/span/path") + new_path = new_path_obj.text + print("tmp_xml new_path: {}".format(new_path)) + + new_path_ext = os.path.splitext(new_path)[1][1:].strip().lower() + if new_path_ext in ext_whitelist: + print("Found media `{}`".format(new_path_ext)) + else: + print("Extension {} is not supported".format( + new_path_ext)) + if os.path.isfile(tmp_file): + os.remove(tmp_file) + return False + + if not create_new_clip: + print("Updating openClip ..") + + try: + source_xml = ET.parse(openclip_file_path) + except: + print("XML is probably empty.") + print('%s' % traceback.print_exc()) + if os.path.isfile(tmp_file): + os.remove(tmp_file) + return False + + try: + new_xml = ET.parse(tmp_file) + except: + print("XML is probably empty.") + print('%s' % traceback.print_exc()) + if os.path.isfile(tmp_file): + os.remove(tmp_file) + return False + + try: + feed_exists = False + feed_added = 0 + + src_editRateNumerator = None + src_editRateDenominator = None + src_nbTicks = None + src_rate = None + src_dropMode = None + + for srcTrack in source_xml.iter('track'): + src_editRateNumeratorObj = srcTrack.find('editRate/numerator') + src_editRateNumerator = src_editRateNumeratorObj.text + src_editRateDenominatorObj = srcTrack.find( + 'editRate/denominator') + src_editRateDenominator = src_editRateDenominatorObj.text + + for srcFeed in srcTrack.iter('feed'): + src_nbTicksObj = srcFeed.find('startTimecode/nbTicks') + src_nbTicks = src_nbTicksObj.text + src_rateObj = srcFeed.find('startTimecode/rate') + src_rate = src_rateObj.text + src_dropModeObj = srcFeed.find('startTimecode/dropMode') + src_dropMode = src_dropModeObj.text + break + else: + continue + break + + print("Source editRate/numerator: %s" % src_editRateNumerator) + print("Source editRate/denominator: %s" % src_editRateDenominator) + print("Source startTimecode/nbTicks: %s" % src_nbTicks) + print("Source startTimecode/rate: %s" % src_rate) + print("Source startTimecode/dropMode: %s" % src_dropMode) + + # Get new feed from file + for newTrack in new_xml.iter('track'): + uid = newTrack.get('uid') + newFeed = newTrack.find('feeds/feed') + + feedHandler = newFeed.find("./handler") + newFeed.remove(feedHandler) + + if src_editRateNumerator: + new_editRateNumeratorObject = newTrack.find( + "feeds/feed/sampleRate/numerator") + new_editRateNumeratorObject.text = src_editRateNumerator + if src_editRateDenominator: + new_editRateDenominatorObject = newTrack.find( + "feeds/feed/sampleRate/denominator") + new_editRateDenominatorObject.text = src_editRateDenominator + if src_rate: + new_rateObject = newTrack.find( + "feeds/feed/startTimecode/rate") + new_rateObject.text = src_rate + if src_nbTicks: + new_nbTicksObject = newTrack.find( + "feeds/feed/startTimecode/nbTicks") + new_nbTicksObject.text = src_nbTicks + if src_dropMode: + new_dropModeObj = newTrack.find( + "feeds/feed/startTimecode/dropMode") + new_dropModeObj.text = src_dropMode + + new_path_obj = newTrack.find("feeds/feed/spans/span/path") + new_path = new_path_obj.text + + print(">> uid: {}".format(uid)) + print(">> new_path: {}".format(new_path)) + + # Check for path in sourceFile + # If Path exists ... skip append + for srcPath in source_xml.iter('path'): + if new_path == srcPath.text: + print("Element exists in clip... skipping append") + feed_exists = True + + if not feed_exists: + # Append new feed to source track + for srcTrack in source_xml.iter('track'): + newFeed.set('vuid', feed_version_name) + srcTrack.find('feeds').append(newFeed) + print( + "Appending new feed: {}".format(feed_version_name)) + feed_added += 1 + + if feed_added > 0: + # Append vUID to versions + newVersion = source_xml.find('versions') + newVersionElement = ET.Element( + "version", {"type": "version", "uid": feed_version_name}) + newVersion.insert(0, newVersionElement) + xmlRoot = source_xml.getroot() + + # Clean tmp_file - brute force remove errant + print("Removing Handler") + for handler in xmlRoot.findall("./handler"): + print("Handler found") + xmlRoot.remove(handler) + + resultXML = ET.tostring(xmlRoot).decode('utf-8') + + # fist create backup + create_openclip_backup_file(openclip_file_path) + + out_file = openclip_file_path + + print("Adding feed version: {}".format(feed_version_name)) + + with open(out_file, "w") as f: + f.write(resultXML) + + print("openClip Updated: {}".format(out_file)) + + clip_uploaded = True + + if os.path.isfile(tmp_file): + os.remove(tmp_file) + + except: + print("Failed reading XML") + print('%s' % traceback.print_exc()) + if os.path.isfile(tmp_file): + os.remove(tmp_file) + return False + + else: + # New openClip + print("Building new openClip") + + # Update uid name with element_name + try: + new_xml = ET.parse(tmp_file) + except: + print("Failed reading XML") + print('%s' % traceback.print_exc()) + if os.path.isfile(tmp_file): + os.remove(tmp_file) + return False + + try: + for newFeed in new_xml.iter('feeds'): + feed = newFeed.find('feed') + feed.set('vuid', feed_basename) + + feedHandler = feed.find("./handler") + feed.remove(feedHandler) + + for newVersion in new_xml.iter('versions'): + newVersion.set('currentVersion', feed_basename) + version = newVersion.find('version') + version.set('uid', feed_basename) + version.set('type', 'version') + + xmlRoot = new_xml.getroot() + + # Clean tmp_file - brute force remove errant + print("Removing Handler") + for handler in xmlRoot.findall("./handler"): + print("Handler found") + xmlRoot.remove(handler) + + resultXML = ET.tostring(xmlRoot).decode('utf-8') + + print("Adding feed version: %s" % feed_basename) + + with open(tmp_file, "w") as f: + f.write(resultXML) + + print("openClip Updated: %s" % tmp_file) + + clip_uploaded = True + + except: + print("Failed to update openClip: %s" % tmp_file) + print('%s' % traceback.print_exc()) + + return clip_uploaded + + +def create_openclip_backup_file(file): + bck_file = "{}.bak".format(file) + # if backup does not exist + if not os.path.isfile(bck_file): + shutil.copy2(file, bck_file) + else: + # in case it exists and is already multiplied + created = False + for _i in range(1, 99): + bck_file = "{name}.bak.{idx:0>2}".format( + name=file, + idx=_i) + # create numbered backup file + if not os.path.isfile(bck_file): + shutil.copy2(file, bck_file) + created = True + break + # in case numbered does not exists + if not created: + bck_file = "{}.bak.last".format(file) + shutil.copy2(file, bck_file) From 447b3f835feba2ef72dfcf14ed9e1b84effa2e8a Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 25 Jan 2022 17:57:36 +0100 Subject: [PATCH 06/27] flame: loading with openclip wip --- openpype/hosts/flame/api/render_utils.py | 195 +++++++++++------------ 1 file changed, 90 insertions(+), 105 deletions(-) diff --git a/openpype/hosts/flame/api/render_utils.py b/openpype/hosts/flame/api/render_utils.py index bc9ebb83d4..e6283b725a 100644 --- a/openpype/hosts/flame/api/render_utils.py +++ b/openpype/hosts/flame/api/render_utils.py @@ -199,6 +199,7 @@ def get_open_clip( # Check media type for valid extension try: tmp_xml = ET.parse(tmp_file) + print(tmp_xml) except: print("XML is probably empty.") print('{}'.format(traceback.print_exc())) @@ -224,34 +225,23 @@ def get_open_clip( if not create_new_clip: print("Updating openClip ..") - try: - source_xml = ET.parse(openclip_file_path) - except: - print("XML is probably empty.") - print('%s' % traceback.print_exc()) - if os.path.isfile(tmp_file): - os.remove(tmp_file) - return False + source_xml = ET.parse(openclip_file_path) + new_xml = ET.parse(tmp_file) + + print(">> source_xml: {}".format(source_xml)) + print(">> new_xml: {}".format(new_xml)) + + + feed_exists = False + feed_added = 0 + + src_editRateNumerator = None + src_editRateDenominator = None + src_nbTicks = None + src_rate = None + src_dropMode = None try: - new_xml = ET.parse(tmp_file) - except: - print("XML is probably empty.") - print('%s' % traceback.print_exc()) - if os.path.isfile(tmp_file): - os.remove(tmp_file) - return False - - try: - feed_exists = False - feed_added = 0 - - src_editRateNumerator = None - src_editRateDenominator = None - src_nbTicks = None - src_rate = None - src_dropMode = None - for srcTrack in source_xml.iter('track'): src_editRateNumeratorObj = srcTrack.find('editRate/numerator') src_editRateNumerator = src_editRateNumeratorObj.text @@ -270,103 +260,98 @@ def get_open_clip( else: continue break + except Exception as msg: + print(msg) - print("Source editRate/numerator: %s" % src_editRateNumerator) - print("Source editRate/denominator: %s" % src_editRateDenominator) - print("Source startTimecode/nbTicks: %s" % src_nbTicks) - print("Source startTimecode/rate: %s" % src_rate) - print("Source startTimecode/dropMode: %s" % src_dropMode) + print("Source editRate/numerator: %s" % src_editRateNumerator) + print("Source editRate/denominator: %s" % src_editRateDenominator) + print("Source startTimecode/nbTicks: %s" % src_nbTicks) + print("Source startTimecode/rate: %s" % src_rate) + print("Source startTimecode/dropMode: %s" % src_dropMode) - # Get new feed from file - for newTrack in new_xml.iter('track'): - uid = newTrack.get('uid') - newFeed = newTrack.find('feeds/feed') + # Get new feed from file + for newTrack in new_xml.iter('track'): + uid = newTrack.get('uid') + newFeed = newTrack.find('feeds/feed') - feedHandler = newFeed.find("./handler") - newFeed.remove(feedHandler) + feedHandler = newFeed.find("./handler") + newFeed.remove(feedHandler) - if src_editRateNumerator: - new_editRateNumeratorObject = newTrack.find( - "feeds/feed/sampleRate/numerator") - new_editRateNumeratorObject.text = src_editRateNumerator - if src_editRateDenominator: - new_editRateDenominatorObject = newTrack.find( - "feeds/feed/sampleRate/denominator") - new_editRateDenominatorObject.text = src_editRateDenominator - if src_rate: - new_rateObject = newTrack.find( - "feeds/feed/startTimecode/rate") - new_rateObject.text = src_rate - if src_nbTicks: - new_nbTicksObject = newTrack.find( - "feeds/feed/startTimecode/nbTicks") - new_nbTicksObject.text = src_nbTicks - if src_dropMode: - new_dropModeObj = newTrack.find( - "feeds/feed/startTimecode/dropMode") - new_dropModeObj.text = src_dropMode + if src_editRateNumerator: + new_editRateNumeratorObject = newTrack.find( + "feeds/feed/sampleRate/numerator") + new_editRateNumeratorObject.text = src_editRateNumerator + if src_editRateDenominator: + new_editRateDenominatorObject = newTrack.find( + "feeds/feed/sampleRate/denominator") + new_editRateDenominatorObject.text = src_editRateDenominator + if src_rate: + new_rateObject = newTrack.find( + "feeds/feed/startTimecode/rate") + new_rateObject.text = src_rate + if src_nbTicks: + new_nbTicksObject = newTrack.find( + "feeds/feed/startTimecode/nbTicks") + new_nbTicksObject.text = src_nbTicks + if src_dropMode: + new_dropModeObj = newTrack.find( + "feeds/feed/startTimecode/dropMode") + new_dropModeObj.text = src_dropMode - new_path_obj = newTrack.find("feeds/feed/spans/span/path") - new_path = new_path_obj.text + new_path_obj = newTrack.find("feeds/feed/spans/span/path") + new_path = new_path_obj.text - print(">> uid: {}".format(uid)) - print(">> new_path: {}".format(new_path)) + print(">> uid: {}".format(uid)) + print(">> new_path: {}".format(new_path)) - # Check for path in sourceFile - # If Path exists ... skip append - for srcPath in source_xml.iter('path'): - if new_path == srcPath.text: - print("Element exists in clip... skipping append") - feed_exists = True + # Check for path in sourceFile + # If Path exists ... skip append + for srcPath in source_xml.iter('path'): + if new_path == srcPath.text: + print("Element exists in clip... skipping append") + feed_exists = True - if not feed_exists: - # Append new feed to source track - for srcTrack in source_xml.iter('track'): - newFeed.set('vuid', feed_version_name) - srcTrack.find('feeds').append(newFeed) - print( - "Appending new feed: {}".format(feed_version_name)) - feed_added += 1 + if not feed_exists: + # Append new feed to source track + for srcTrack in source_xml.iter('track'): + newFeed.set('vuid', feed_version_name) + srcTrack.find('feeds').append(newFeed) + print( + "Appending new feed: {}".format(feed_version_name)) + feed_added += 1 - if feed_added > 0: - # Append vUID to versions - newVersion = source_xml.find('versions') - newVersionElement = ET.Element( - "version", {"type": "version", "uid": feed_version_name}) - newVersion.insert(0, newVersionElement) - xmlRoot = source_xml.getroot() + if feed_added > 0: + # Append vUID to versions + newVersion = source_xml.find('versions') + newVersionElement = ET.Element( + "version", {"type": "version", "uid": feed_version_name}) + newVersion.insert(0, newVersionElement) + xmlRoot = source_xml.getroot() - # Clean tmp_file - brute force remove errant - print("Removing Handler") - for handler in xmlRoot.findall("./handler"): - print("Handler found") - xmlRoot.remove(handler) + # Clean tmp_file - brute force remove errant + print("Removing Handler") + for handler in xmlRoot.findall("./handler"): + print("Handler found") + xmlRoot.remove(handler) - resultXML = ET.tostring(xmlRoot).decode('utf-8') + resultXML = ET.tostring(xmlRoot).decode('utf-8') - # fist create backup - create_openclip_backup_file(openclip_file_path) + # fist create backup + create_openclip_backup_file(openclip_file_path) - out_file = openclip_file_path + out_file = openclip_file_path - print("Adding feed version: {}".format(feed_version_name)) + print("Adding feed version: {}".format(feed_version_name)) - with open(out_file, "w") as f: - f.write(resultXML) + with open(out_file, "w") as f: + f.write(resultXML) - print("openClip Updated: {}".format(out_file)) + print("openClip Updated: {}".format(out_file)) - clip_uploaded = True + clip_uploaded = True - if os.path.isfile(tmp_file): - os.remove(tmp_file) - - except: - print("Failed reading XML") - print('%s' % traceback.print_exc()) - if os.path.isfile(tmp_file): - os.remove(tmp_file) - return False + if os.path.isfile(tmp_file): + os.remove(tmp_file) else: # New openClip From 8527e4691fa12d0b47fefd3a117d0f1a4c0e3c28 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 26 Jan 2022 17:15:58 +0100 Subject: [PATCH 07/27] flame: openclip creator --- openpype/hosts/flame/api/render_utils.py | 255 ++++++++++------------- 1 file changed, 112 insertions(+), 143 deletions(-) diff --git a/openpype/hosts/flame/api/render_utils.py b/openpype/hosts/flame/api/render_utils.py index e6283b725a..dac69c5405 100644 --- a/openpype/hosts/flame/api/render_utils.py +++ b/openpype/hosts/flame/api/render_utils.py @@ -132,7 +132,7 @@ def get_preset_path_by_xml_name(xml_preset_name): def get_open_clip( - openclip_file_path, feed_data, recursive=False): + name, openclip_file_path, feed_data): # establish media script path and test it media_script_path = "/opt/Autodesk/mio/current/dl_get_media_info" @@ -140,27 +140,23 @@ def get_open_clip( raise IOError("Media Scirpt does not exist: `{}`".format( media_script_path)) + # openclip will be updated via temp.clip file + tmp_name = "_tmp.clip" + # new feed variables: feed_path = feed_data["path"] - feed_basename = os.path.basename(feed_path) feed_version_name = feed_data["version"] + feed_colorspace = feed_data.get("colorspace") + + # derivate other feed variables + feed_basename = os.path.basename(feed_path) + feed_dir = os.path.dirname(feed_path) clip_uploaded = False create_new_clip = False - ext_whitelist = [ - "cin", "als", "jpg", "jpeg", "pict", "pct", "picio", - "sgi", "pic", "tga", "iff", "tdi", "tif", "tiff", "rla", - "cin.pxz", "tif.pxz", "tiff.pxz", "dpx", "dpx.pxz", - "hdr", "png", "exr", "exr.pxz", "psd" - ] - feed_ext = os.path.splitext(feed_basename)[1][1:].lower() - if feed_ext not in ext_whitelist: - print("File extension `{}` is not supported".format(feed_ext)) - return False - if not os.path.isfile(openclip_file_path): # openclip does not exist yet and will be created feed_path = os.path.abspath(feed_path) @@ -168,11 +164,6 @@ def get_open_clip( create_new_clip = True clip_uploaded = True else: - # openclip will be updated via temp.clip file - tmp_name = "tmp.clip" - feed_path = os.path.abspath(feed_path) - feed_dir = os.path.dirname(feed_path) - # output a temp file tmp_file = os.path.join(feed_dir, tmp_name) if os.path.isfile(tmp_file): @@ -180,22 +171,21 @@ def get_open_clip( print("Temp File: {}".format(tmp_file)) - # Write output of getMediaScript to file - cmd_args = [media_script_path, feed_path] - if recursive: - print("recursive enabled on dl_get_media_info") - cmd_args = [media_script_path, "-r", feed_path] + # Create cmd arguments for gettig xml file info file + cmd_args = [ + media_script_path, + "-e", feed_ext, + "-o", tmp_file, + feed_dir + ] # execute creation of clip xml template data try: - output = openpype.lib.run_subprocess(cmd_args) + openpype.lib.run_subprocess(cmd_args) except TypeError: print("Error createing tmp_file") six.reraise(*sys.exc_info()) - with open(tmp_file, "w") as f: - f.write("{}".format(output)) - # Check media type for valid extension try: tmp_xml = ET.parse(tmp_file) @@ -212,17 +202,49 @@ def get_open_clip( new_path = new_path_obj.text print("tmp_xml new_path: {}".format(new_path)) - new_path_ext = os.path.splitext(new_path)[1][1:].strip().lower() - if new_path_ext in ext_whitelist: - print("Found media `{}`".format(new_path_ext)) - else: - print("Extension {} is not supported".format( - new_path_ext)) - if os.path.isfile(tmp_file): - os.remove(tmp_file) - return False + if create_new_clip: + # New openClip + print("Building new openClip") - if not create_new_clip: + new_xml = ET.parse(tmp_file) + + for new_feed in new_xml.iter('feeds'): + feed = new_feed.find('feed') + feed.set('vuid', feed_basename) + + # add colorspace if any is set + if feed_colorspace: + _add_colorspace(feed, feed_colorspace) + + feedHandler = feed.find("./handler") + feed.remove(feedHandler) + + for newVersion in new_xml.iter('versions'): + newVersion.set('currentVersion', feed_basename) + version = newVersion.find('version') + version.set('uid', feed_basename) + version.set('type', 'version') + + xmlRoot = new_xml.getroot() + + # Clean tmp_file - brute force remove errant + print("Removing Handler") + for handler in xmlRoot.findall("./handler"): + print("Handler found") + xmlRoot.remove(handler) + + resultXML = ET.tostring(xmlRoot).decode('utf-8') + + print("Adding feed version: {}".format(feed_basename)) + + with open(tmp_file, "w") as f: + f.write(resultXML) + + print("openClip Updated: %s" % tmp_file) + + clip_uploaded = True + + else: print("Updating openClip ..") source_xml = ET.parse(openclip_file_path) @@ -231,31 +253,25 @@ def get_open_clip( print(">> source_xml: {}".format(source_xml)) print(">> new_xml: {}".format(new_xml)) - feed_exists = False feed_added = 0 - src_editRateNumerator = None - src_editRateDenominator = None - src_nbTicks = None - src_rate = None - src_dropMode = None + feed_src_nb_ticks = None + feed_src_fps = None + feed_src_drop_mode = None try: - for srcTrack in source_xml.iter('track'): - src_editRateNumeratorObj = srcTrack.find('editRate/numerator') - src_editRateNumerator = src_editRateNumeratorObj.text - src_editRateDenominatorObj = srcTrack.find( - 'editRate/denominator') - src_editRateDenominator = src_editRateDenominatorObj.text - - for srcFeed in srcTrack.iter('feed'): - src_nbTicksObj = srcFeed.find('startTimecode/nbTicks') - src_nbTicks = src_nbTicksObj.text - src_rateObj = srcFeed.find('startTimecode/rate') - src_rate = src_rateObj.text - src_dropModeObj = srcFeed.find('startTimecode/dropMode') - src_dropMode = src_dropModeObj.text + for src_track in source_xml.iter('track'): + for srcFeed in src_track.iter('feed'): + feed_src_nb_ticksObj = srcFeed.find( + 'startTimecode/nbTicks') + feed_src_nb_ticks = feed_src_nb_ticksObj.text + feed_src_fpsObj = srcFeed.find( + 'startTimecode/rate') + feed_src_fps = feed_src_fpsObj.text + feed_src_drop_modeObj = srcFeed.find( + 'startTimecode/dropMode') + feed_src_drop_mode = feed_src_drop_modeObj.text break else: continue @@ -263,59 +279,52 @@ def get_open_clip( except Exception as msg: print(msg) - print("Source editRate/numerator: %s" % src_editRateNumerator) - print("Source editRate/denominator: %s" % src_editRateDenominator) - print("Source startTimecode/nbTicks: %s" % src_nbTicks) - print("Source startTimecode/rate: %s" % src_rate) - print("Source startTimecode/dropMode: %s" % src_dropMode) + print("Source startTimecode/nbTicks: %s" % feed_src_nb_ticks) + print("Source startTimecode/rate: %s" % feed_src_fps) + print("Source startTimecode/dropMode: %s" % feed_src_drop_mode) # Get new feed from file for newTrack in new_xml.iter('track'): uid = newTrack.get('uid') - newFeed = newTrack.find('feeds/feed') + new_feed = newTrack.find('feeds/feed') - feedHandler = newFeed.find("./handler") - newFeed.remove(feedHandler) + feedHandler = new_feed.find("./handler") + new_feed.remove(feedHandler) - if src_editRateNumerator: - new_editRateNumeratorObject = newTrack.find( - "feeds/feed/sampleRate/numerator") - new_editRateNumeratorObject.text = src_editRateNumerator - if src_editRateDenominator: - new_editRateDenominatorObject = newTrack.find( - "feeds/feed/sampleRate/denominator") - new_editRateDenominatorObject.text = src_editRateDenominator - if src_rate: + if feed_src_fps: new_rateObject = newTrack.find( "feeds/feed/startTimecode/rate") - new_rateObject.text = src_rate - if src_nbTicks: + new_rateObject.text = feed_src_fps + if feed_src_nb_ticks: new_nbTicksObject = newTrack.find( "feeds/feed/startTimecode/nbTicks") - new_nbTicksObject.text = src_nbTicks - if src_dropMode: + new_nbTicksObject.text = feed_src_nb_ticks + if feed_src_drop_mode: new_dropModeObj = newTrack.find( "feeds/feed/startTimecode/dropMode") - new_dropModeObj.text = src_dropMode + new_dropModeObj.text = feed_src_drop_mode - new_path_obj = newTrack.find("feeds/feed/spans/span/path") + new_path_obj = newTrack.find( + "feeds/feed/spans/span/path") new_path = new_path_obj.text - print(">> uid: {}".format(uid)) - print(">> new_path: {}".format(new_path)) - - # Check for path in sourceFile - # If Path exists ... skip append - for srcPath in source_xml.iter('path'): - if new_path == srcPath.text: - print("Element exists in clip... skipping append") + # loop all available feed paths and check if + # the path is not already in file + for src_path in source_xml.iter('path'): + if new_path == src_path.text: + print("Not appending file as it already is in .clip file") feed_exists = True if not feed_exists: - # Append new feed to source track - for srcTrack in source_xml.iter('track'): - newFeed.set('vuid', feed_version_name) - srcTrack.find('feeds').append(newFeed) + # Append new temp file feed to .clip source xml tree + for src_track in source_xml.iter('track'): + new_feed.set('vuid', feed_version_name) + + # add colorspace if any is set + if feed_colorspace: + _add_colorspace(new_feed, feed_colorspace) + + src_track.find('feeds').append(new_feed) print( "Appending new feed: {}".format(feed_version_name)) feed_added += 1 @@ -353,57 +362,6 @@ def get_open_clip( if os.path.isfile(tmp_file): os.remove(tmp_file) - else: - # New openClip - print("Building new openClip") - - # Update uid name with element_name - try: - new_xml = ET.parse(tmp_file) - except: - print("Failed reading XML") - print('%s' % traceback.print_exc()) - if os.path.isfile(tmp_file): - os.remove(tmp_file) - return False - - try: - for newFeed in new_xml.iter('feeds'): - feed = newFeed.find('feed') - feed.set('vuid', feed_basename) - - feedHandler = feed.find("./handler") - feed.remove(feedHandler) - - for newVersion in new_xml.iter('versions'): - newVersion.set('currentVersion', feed_basename) - version = newVersion.find('version') - version.set('uid', feed_basename) - version.set('type', 'version') - - xmlRoot = new_xml.getroot() - - # Clean tmp_file - brute force remove errant - print("Removing Handler") - for handler in xmlRoot.findall("./handler"): - print("Handler found") - xmlRoot.remove(handler) - - resultXML = ET.tostring(xmlRoot).decode('utf-8') - - print("Adding feed version: %s" % feed_basename) - - with open(tmp_file, "w") as f: - f.write(resultXML) - - print("openClip Updated: %s" % tmp_file) - - clip_uploaded = True - - except: - print("Failed to update openClip: %s" % tmp_file) - print('%s' % traceback.print_exc()) - return clip_uploaded @@ -428,3 +386,14 @@ def create_openclip_backup_file(file): if not created: bck_file = "{}.bak.last".format(file) shutil.copy2(file, bck_file) + + +def _add_colorspace(feed_obj, profile_name): + feed_storage_obj = feed_obj.find("storageFormat") + feed_clr_obj = feed_storage_obj.find("colourSpace") + if not feed_clr_obj: + feed_clr_obj = ET.Element( + "colourSpace", {"type": "string"}) + feed_storage_obj.append(feed_clr_obj) + + feed_clr_obj.text = profile_name From 1b771160c00b2d3b9fe1bac1b173a58366264fdc Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 28 Jan 2022 16:58:16 +0100 Subject: [PATCH 08/27] flame: convert open clip to class --- openpype/hosts/flame/api/render_utils.py | 413 +++++++++++------------ 1 file changed, 195 insertions(+), 218 deletions(-) diff --git a/openpype/hosts/flame/api/render_utils.py b/openpype/hosts/flame/api/render_utils.py index dac69c5405..3b7e2cf8b2 100644 --- a/openpype/hosts/flame/api/render_utils.py +++ b/openpype/hosts/flame/api/render_utils.py @@ -131,269 +131,246 @@ def get_preset_path_by_xml_name(xml_preset_name): return False -def get_open_clip( - name, openclip_file_path, feed_data): - - # establish media script path and test it +class OpenClip: media_script_path = "/opt/Autodesk/mio/current/dl_get_media_info" - if not os.path.isfile(media_script_path): - raise IOError("Media Scirpt does not exist: `{}`".format( - media_script_path)) - - # openclip will be updated via temp.clip file tmp_name = "_tmp.clip" - - # new feed variables: - feed_path = feed_data["path"] - feed_version_name = feed_data["version"] - feed_colorspace = feed_data.get("colorspace") - - # derivate other feed variables - feed_basename = os.path.basename(feed_path) - feed_dir = os.path.dirname(feed_path) - - clip_uploaded = False + tmp_file = None create_new_clip = False - feed_ext = os.path.splitext(feed_basename)[1][1:].lower() + out_feed_nb_ticks = None + out_feed_fps = None + out_feed_drop_mode = None - if not os.path.isfile(openclip_file_path): - # openclip does not exist yet and will be created - feed_path = os.path.abspath(feed_path) - tmp_file = openclip_file_path - create_new_clip = True - clip_uploaded = True - else: - # output a temp file - tmp_file = os.path.join(feed_dir, tmp_name) - if os.path.isfile(tmp_file): - os.remove(tmp_file) + def __init__(self, name, openclip_file_path, feed_data): + # test if media script paht exists + self._validate_media_script_path() - print("Temp File: {}".format(tmp_file)) - # Create cmd arguments for gettig xml file info file - cmd_args = [ - media_script_path, - "-e", feed_ext, - "-o", tmp_file, - feed_dir - ] + # new feed variables: + feed_path = feed_data["path"] + self.feed_version_name = feed_data["version"] + self.feed_colorspace = feed_data.get("colorspace") - # execute creation of clip xml template data - try: - openpype.lib.run_subprocess(cmd_args) - except TypeError: - print("Error createing tmp_file") - six.reraise(*sys.exc_info()) + # derivate other feed variables + self.feed_basename = os.path.basename(feed_path) + self.feed_dir = os.path.dirname(feed_path) + self.feed_ext = os.path.splitext(self.feed_basename)[1][1:].lower() - # Check media type for valid extension - try: - tmp_xml = ET.parse(tmp_file) - print(tmp_xml) - except: - print("XML is probably empty.") - print('{}'.format(traceback.print_exc())) - if os.path.isfile(tmp_file): - os.remove(tmp_file) - return False + if not os.path.isfile(openclip_file_path): + # openclip does not exist yet and will be created + self.tmp_file = self.out_file = openclip_file_path + self.create_new_clip = True - for newTrack in tmp_xml.iter('track'): - new_path_obj = newTrack.find("feeds/feed/spans/span/path") - new_path = new_path_obj.text - print("tmp_xml new_path: {}".format(new_path)) + else: + # output a temp file + self.out_file = openclip_file_path + self.tmp_file = os.path.join(self.feed_dir, self.tmp_name) + self._clear_tmp_file() - if create_new_clip: - # New openClip + print("Temp File: {}".format(self.tmp_file)) + + def _validate_media_script_path(self): + if not os.path.isfile(self.media_script_path): + raise IOError("Media Scirpt does not exist: `{}`".format( + self.media_script_path)) + + def _get_media_info_args(self): + # Create cmd arguments for gettig xml file info file + cmd_args = [ + self.media_script_path, + "-e", self.feed_ext, + "-o", self.tmp_file, + self.feed_dir + ] + + # execute creation of clip xml template data + try: + openpype.lib.run_subprocess(cmd_args) + except TypeError: + print("Error createing self.tmp_file") + six.reraise(*sys.exc_info()) + + def _clear_tmp_file(self): + if os.path.isfile(self.tmp_file): + os.remove(self.tmp_file) + + def _clear_handler(self, xml_object): + for handler in xml_object.findall("./handler"): + print("Handler found") + xml_object.remove(handler) + + def _create_new_open_clip(self): print("Building new openClip") - new_xml = ET.parse(tmp_file) + tmp_xml = ET.parse(self.tmp_file) - for new_feed in new_xml.iter('feeds'): - feed = new_feed.find('feed') - feed.set('vuid', feed_basename) + for tmp_xml_feed in tmp_xml.iter('feeds'): + feed = tmp_xml_feed.find('feed') + feed.set('vuid', self.feed_basename) # add colorspace if any is set - if feed_colorspace: - _add_colorspace(feed, feed_colorspace) + if self.feed_colorspace: + self._add_colorspace(feed, self.feed_colorspace) - feedHandler = feed.find("./handler") - feed.remove(feedHandler) + self._clear_handler(feed) - for newVersion in new_xml.iter('versions'): - newVersion.set('currentVersion', feed_basename) - version = newVersion.find('version') - version.set('uid', feed_basename) + tmp_xml_versions_obj = tmp_xml.find('versions') + tmp_xml_versions_obj.set('currentVersion', self.feed_version_name) + for xml_new_version in tmp_xml_versions_obj: + version = xml_new_version.find('version') + version.set('uid', self.feed_version_name) version.set('type', 'version') - xmlRoot = new_xml.getroot() + xml_data = self._fix_xml_data(tmp_xml) + print("Adding feed version: {}".format(self.feed_basename)) - # Clean tmp_file - brute force remove errant - print("Removing Handler") - for handler in xmlRoot.findall("./handler"): - print("Handler found") - xmlRoot.remove(handler) + self._write_result_xml_to_file(xml_data) - resultXML = ET.tostring(xmlRoot).decode('utf-8') + print("openClip Updated: %s" % self.tmp_file) - print("Adding feed version: {}".format(feed_basename)) - - with open(tmp_file, "w") as f: - f.write(resultXML) - - print("openClip Updated: %s" % tmp_file) - - clip_uploaded = True - - else: + def _update_open_clip(self): print("Updating openClip ..") - source_xml = ET.parse(openclip_file_path) - new_xml = ET.parse(tmp_file) + out_xml = ET.parse(self.out_file) + tmp_xml = ET.parse(self.tmp_file) - print(">> source_xml: {}".format(source_xml)) - print(">> new_xml: {}".format(new_xml)) + print(">> out_xml: {}".format(out_xml)) + print(">> tmp_xml: {}".format(tmp_xml)) - feed_exists = False - feed_added = 0 + # Get new feed from tmp file + tmp_xml_feed = tmp_xml.find('tracks/track/feeds/feed') - feed_src_nb_ticks = None - feed_src_fps = None - feed_src_drop_mode = None + self._clear_handler(tmp_xml_feed) + self._get_time_info_from_origin(out_xml) + if self.out_feed_fps: + tmp_feed_fps_obj = tmp_xml_feed.find( + "startTimecode/rate") + tmp_feed_fps_obj.text = self.out_feed_fps + if self.out_feed_nb_ticks: + tmp_feed_nb_ticks_obj = tmp_xml_feed.find( + "startTimecode/nbTicks") + tmp_feed_nb_ticks_obj.text = self.out_feed_nb_ticks + if self.out_feed_drop_mode: + tmp_feed_drop_mode_obj = tmp_xml_feed.find( + "startTimecode/dropMode") + tmp_feed_drop_mode_obj.text = self.out_feed_drop_mode + + new_path_obj = tmp_xml_feed.find( + "spans/span/path") + new_path = new_path_obj.text + + feed_added = False + if not self._feed_exists(out_xml, new_path): + tmp_xml_feed.set('vuid', self.feed_version_name) + # Append new temp file feed to .clip source out xml + out_track = out_xml.find("tracks/track") + # add colorspace if any is set + if self.feed_colorspace: + self._add_colorspace(tmp_xml_feed, self.feed_colorspace) + + out_track.find('feeds').append(tmp_xml_feed) + print( + "Appending new feed: {}".format( + self.feed_version_name)) + feed_added = True + + if feed_added: + # Append vUID to versions + out_xml_versions_obj = out_xml.find('versions') + out_xml_versions_obj.set( + 'currentVersion', self.feed_version_name) + new_version_obj = ET.Element( + "version", {"type": "version", "uid": self.feed_version_name}) + out_xml_versions_obj.insert(0, new_version_obj) + + xml_data = self._fix_xml_data(out_xml) + + # fist create backup + self._create_openclip_backup_file(self.out_file) + + print("Adding feed version: {}".format(self.feed_version_name)) + + self._write_result_xml_to_file(xml_data) + + print("openClip Updated: {}".format(self.out_file)) + + self._clear_tmp_file() + + def _get_time_info_from_origin(self, xml_data): try: - for src_track in source_xml.iter('track'): - for srcFeed in src_track.iter('feed'): - feed_src_nb_ticksObj = srcFeed.find( + for out_track in xml_data.iter('track'): + for out_feed in out_track.iter('feed'): + out_feed_nb_ticks_obj = out_feed.find( 'startTimecode/nbTicks') - feed_src_nb_ticks = feed_src_nb_ticksObj.text - feed_src_fpsObj = srcFeed.find( + self.out_feed_nb_ticks = out_feed_nb_ticks_obj.text + out_feed_fps_obj = out_feed.find( 'startTimecode/rate') - feed_src_fps = feed_src_fpsObj.text - feed_src_drop_modeObj = srcFeed.find( + self.out_feed_fps = out_feed_fps_obj.text + out_feed_drop_mode_obj = out_feed.find( 'startTimecode/dropMode') - feed_src_drop_mode = feed_src_drop_modeObj.text + self.out_feed_drop_mode = out_feed_drop_mode_obj.text break else: continue - break except Exception as msg: print(msg) - print("Source startTimecode/nbTicks: %s" % feed_src_nb_ticks) - print("Source startTimecode/rate: %s" % feed_src_fps) - print("Source startTimecode/dropMode: %s" % feed_src_drop_mode) + def _feed_exists(self, xml_data, path): + # loop all available feed paths and check if + # the path is not already in file + for src_path in xml_data.iter('path'): + if path == src_path.text: + print("Not appending file as it already is in .clip file") + return True - # Get new feed from file - for newTrack in new_xml.iter('track'): - uid = newTrack.get('uid') - new_feed = newTrack.find('feeds/feed') + def _fix_xml_data(self, xml_data): + xml_root = xml_data.getroot() + self._clear_handler(xml_root) + return ET.tostring(xml_root).decode('utf-8') - feedHandler = new_feed.find("./handler") - new_feed.remove(feedHandler) + def maintain_clip(self): + self._get_media_info_args() - if feed_src_fps: - new_rateObject = newTrack.find( - "feeds/feed/startTimecode/rate") - new_rateObject.text = feed_src_fps - if feed_src_nb_ticks: - new_nbTicksObject = newTrack.find( - "feeds/feed/startTimecode/nbTicks") - new_nbTicksObject.text = feed_src_nb_ticks - if feed_src_drop_mode: - new_dropModeObj = newTrack.find( - "feeds/feed/startTimecode/dropMode") - new_dropModeObj.text = feed_src_drop_mode + if self.create_new_clip: + # New openClip + self._create_new_open_clip() + else: + self._update_open_clip() - new_path_obj = newTrack.find( - "feeds/feed/spans/span/path") - new_path = new_path_obj.text + def _write_result_xml_to_file(self, xml_data): + with open(self.out_file, "w") as f: + f.write(xml_data) - # loop all available feed paths and check if - # the path is not already in file - for src_path in source_xml.iter('path'): - if new_path == src_path.text: - print("Not appending file as it already is in .clip file") - feed_exists = True - - if not feed_exists: - # Append new temp file feed to .clip source xml tree - for src_track in source_xml.iter('track'): - new_feed.set('vuid', feed_version_name) - - # add colorspace if any is set - if feed_colorspace: - _add_colorspace(new_feed, feed_colorspace) - - src_track.find('feeds').append(new_feed) - print( - "Appending new feed: {}".format(feed_version_name)) - feed_added += 1 - - if feed_added > 0: - # Append vUID to versions - newVersion = source_xml.find('versions') - newVersionElement = ET.Element( - "version", {"type": "version", "uid": feed_version_name}) - newVersion.insert(0, newVersionElement) - xmlRoot = source_xml.getroot() - - # Clean tmp_file - brute force remove errant - print("Removing Handler") - for handler in xmlRoot.findall("./handler"): - print("Handler found") - xmlRoot.remove(handler) - - resultXML = ET.tostring(xmlRoot).decode('utf-8') - - # fist create backup - create_openclip_backup_file(openclip_file_path) - - out_file = openclip_file_path - - print("Adding feed version: {}".format(feed_version_name)) - - with open(out_file, "w") as f: - f.write(resultXML) - - print("openClip Updated: {}".format(out_file)) - - clip_uploaded = True - - if os.path.isfile(tmp_file): - os.remove(tmp_file) - - return clip_uploaded - - -def create_openclip_backup_file(file): - bck_file = "{}.bak".format(file) - # if backup does not exist - if not os.path.isfile(bck_file): - shutil.copy2(file, bck_file) - else: - # in case it exists and is already multiplied - created = False - for _i in range(1, 99): - bck_file = "{name}.bak.{idx:0>2}".format( - name=file, - idx=_i) - # create numbered backup file - if not os.path.isfile(bck_file): - shutil.copy2(file, bck_file) - created = True - break - # in case numbered does not exists - if not created: - bck_file = "{}.bak.last".format(file) + def _create_openclip_backup_file(self, file): + bck_file = "{}.bak".format(file) + # if backup does not exist + if not os.path.isfile(bck_file): shutil.copy2(file, bck_file) + else: + # in case it exists and is already multiplied + created = False + for _i in range(1, 99): + bck_file = "{name}.bak.{idx:0>2}".format( + name=file, + idx=_i) + # create numbered backup file + if not os.path.isfile(bck_file): + shutil.copy2(file, bck_file) + created = True + break + # in case numbered does not exists + if not created: + bck_file = "{}.bak.last".format(file) + shutil.copy2(file, bck_file) -def _add_colorspace(feed_obj, profile_name): - feed_storage_obj = feed_obj.find("storageFormat") - feed_clr_obj = feed_storage_obj.find("colourSpace") - if not feed_clr_obj: - feed_clr_obj = ET.Element( - "colourSpace", {"type": "string"}) - feed_storage_obj.append(feed_clr_obj) + def _add_colorspace(self, feed_obj, profile_name): + feed_storage_obj = feed_obj.find("storageFormat") + feed_clr_obj = feed_storage_obj.find("colourSpace") + if not feed_clr_obj: + feed_clr_obj = ET.Element( + "colourSpace", {"type": "string"}) + feed_storage_obj.append(feed_clr_obj) - feed_clr_obj.text = profile_name + feed_clr_obj.text = profile_name From 142451f74aeb91023debde53f12bce21fbebb74f Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Sat, 29 Jan 2022 19:40:18 +0100 Subject: [PATCH 09/27] flame: fixing openclip creator to add version --- openpype/hosts/flame/api/render_utils.py | 25 ++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/openpype/hosts/flame/api/render_utils.py b/openpype/hosts/flame/api/render_utils.py index 3b7e2cf8b2..fe406f1c94 100644 --- a/openpype/hosts/flame/api/render_utils.py +++ b/openpype/hosts/flame/api/render_utils.py @@ -141,11 +141,10 @@ class OpenClip: out_feed_fps = None out_feed_drop_mode = None - def __init__(self, name, openclip_file_path, feed_data): + def __init__(self, name, openclip_file_path, feed_data): # test if media script paht exists self._validate_media_script_path() - # new feed variables: feed_path = feed_data["path"] self.feed_version_name = feed_data["version"] @@ -204,22 +203,22 @@ class OpenClip: tmp_xml = ET.parse(self.tmp_file) - for tmp_xml_feed in tmp_xml.iter('feeds'): - feed = tmp_xml_feed.find('feed') - feed.set('vuid', self.feed_basename) + tmp_xml_feeds = tmp_xml.find('tracks/track/feeds') + tmp_xml_feeds.set('currentVersion', self.feed_version_name) + for tmp_feed in tmp_xml_feeds: + tmp_feed.set('vuid', self.feed_version_name) # add colorspace if any is set if self.feed_colorspace: - self._add_colorspace(feed, self.feed_colorspace) + self._add_colorspace(tmp_feed, self.feed_colorspace) - self._clear_handler(feed) + self._clear_handler(tmp_feed) tmp_xml_versions_obj = tmp_xml.find('versions') tmp_xml_versions_obj.set('currentVersion', self.feed_version_name) for xml_new_version in tmp_xml_versions_obj: - version = xml_new_version.find('version') - version.set('uid', self.feed_version_name) - version.set('type', 'version') + xml_new_version.set('uid', self.feed_version_name) + xml_new_version.set('type', 'version') xml_data = self._fix_xml_data(tmp_xml) print("Adding feed version: {}".format(self.feed_basename)) @@ -269,7 +268,10 @@ class OpenClip: if self.feed_colorspace: self._add_colorspace(tmp_xml_feed, self.feed_colorspace) - out_track.find('feeds').append(tmp_xml_feed) + out_feeds = out_track.find('feeds') + out_feeds.set('currentVersion', self.feed_version_name) + out_feeds.append(tmp_xml_feed) + print( "Appending new feed: {}".format( self.feed_version_name)) @@ -364,7 +366,6 @@ class OpenClip: bck_file = "{}.bak.last".format(file) shutil.copy2(file, bck_file) - def _add_colorspace(self, feed_obj, profile_name): feed_storage_obj = feed_obj.find("storageFormat") feed_clr_obj = feed_storage_obj.find("colourSpace") From 14b704fcd774547bc249c3b88ab1dd30ee2fda83 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 31 Jan 2022 12:03:58 +0100 Subject: [PATCH 10/27] flame: moving openclip solver to plugins modul - starting with loader class functionality --- openpype/hosts/flame/api/__init__.py | 7 +- openpype/hosts/flame/api/plugin.py | 291 +++++++++++++++++++++++ openpype/hosts/flame/api/render_utils.py | 252 -------------------- 3 files changed, 297 insertions(+), 253 deletions(-) diff --git a/openpype/hosts/flame/api/__init__.py b/openpype/hosts/flame/api/__init__.py index 8e5418c78b..2aeb0d9c16 100644 --- a/openpype/hosts/flame/api/__init__.py +++ b/openpype/hosts/flame/api/__init__.py @@ -52,7 +52,10 @@ from .menu import ( ) from .plugin import ( Creator, - PublishableClip + PublishableClip, + ClipLoader, + OpenClipSolver + ) from .workio import ( open_file, @@ -122,6 +125,8 @@ __all__ = [ # plugin "Creator", "PublishableClip", + "ClipLoader", + "OpenClipSolver", # workio "open_file", diff --git a/openpype/hosts/flame/api/plugin.py b/openpype/hosts/flame/api/plugin.py index f34999bcf3..a83f9a3b28 100644 --- a/openpype/hosts/flame/api/plugin.py +++ b/openpype/hosts/flame/api/plugin.py @@ -1,7 +1,15 @@ +import os import re +import shutil +import sys +from avalon.vendor import qargparse +from xml.etree import ElementTree as ET +import shutil +import six from Qt import QtWidgets, QtCore import openpype.api as openpype from openpype import style +import avalon.api as avalon from . import ( lib as flib, pipeline as fpipeline, @@ -644,3 +652,286 @@ class PublishableClip: # Publishing plugin functions # Loader plugin functions + +class ClipLoader(avalon.Loader): + """A basic clip loader for Flame + + This will implement the basic behavior for a loader to inherit from that + will containerize the reference and will implement the `remove` and + `update` logic. + + """ + + options = [ + qargparse.Boolean( + "handles", + label="Set handles", + default=0, + help="Also set handles to clip as In/Out marks" + ) + ] + + def load( + self, + context, + name=None, + namespace=None, + options=None + ): + pass + + def update(self, container, representation): + """Update an existing `container` + """ + pass + + def remove(self, container): + """Remove an existing `container` + """ + pass + + +class OpenClipSolver: + media_script_path = "/opt/Autodesk/mio/current/dl_get_media_info" + tmp_name = "_tmp.clip" + tmp_file = None + create_new_clip = False + + out_feed_nb_ticks = None + out_feed_fps = None + out_feed_drop_mode = None + + def __init__(self, name, openclip_file_path, feed_data): + # test if media script paht exists + self._validate_media_script_path() + + # new feed variables: + feed_path = feed_data["path"] + self.feed_version_name = feed_data["version"] + self.feed_colorspace = feed_data.get("colorspace") + + # derivate other feed variables + self.feed_basename = os.path.basename(feed_path) + self.feed_dir = os.path.dirname(feed_path) + self.feed_ext = os.path.splitext(self.feed_basename)[1][1:].lower() + + if not os.path.isfile(openclip_file_path): + # openclip does not exist yet and will be created + self.tmp_file = self.out_file = openclip_file_path + self.create_new_clip = True + + else: + # output a temp file + self.out_file = openclip_file_path + self.tmp_file = os.path.join(self.feed_dir, self.tmp_name) + self._clear_tmp_file() + + print("Temp File: {}".format(self.tmp_file)) + + def _validate_media_script_path(self): + if not os.path.isfile(self.media_script_path): + raise IOError("Media Scirpt does not exist: `{}`".format( + self.media_script_path)) + + def _get_media_info_args(self): + # Create cmd arguments for gettig xml file info file + cmd_args = [ + self.media_script_path, + "-e", self.feed_ext, + "-o", self.tmp_file, + self.feed_dir + ] + + # execute creation of clip xml template data + try: + flib.run_subprocess(cmd_args) + except TypeError: + print("Error createing self.tmp_file") + six.reraise(*sys.exc_info()) + + def _clear_tmp_file(self): + if os.path.isfile(self.tmp_file): + os.remove(self.tmp_file) + + def _clear_handler(self, xml_object): + for handler in xml_object.findall("./handler"): + print("Handler found") + xml_object.remove(handler) + + def _create_new_open_clip(self): + print("Building new openClip") + + tmp_xml = ET.parse(self.tmp_file) + + tmp_xml_feeds = tmp_xml.find('tracks/track/feeds') + tmp_xml_feeds.set('currentVersion', self.feed_version_name) + for tmp_feed in tmp_xml_feeds: + tmp_feed.set('vuid', self.feed_version_name) + + # add colorspace if any is set + if self.feed_colorspace: + self._add_colorspace(tmp_feed, self.feed_colorspace) + + self._clear_handler(tmp_feed) + + tmp_xml_versions_obj = tmp_xml.find('versions') + tmp_xml_versions_obj.set('currentVersion', self.feed_version_name) + for xml_new_version in tmp_xml_versions_obj: + xml_new_version.set('uid', self.feed_version_name) + xml_new_version.set('type', 'version') + + xml_data = self._fix_xml_data(tmp_xml) + print("Adding feed version: {}".format(self.feed_basename)) + + self._write_result_xml_to_file(xml_data) + + print("openClip Updated: %s" % self.tmp_file) + + def _update_open_clip(self): + print("Updating openClip ..") + + out_xml = ET.parse(self.out_file) + tmp_xml = ET.parse(self.tmp_file) + + print(">> out_xml: {}".format(out_xml)) + print(">> tmp_xml: {}".format(tmp_xml)) + + # Get new feed from tmp file + tmp_xml_feed = tmp_xml.find('tracks/track/feeds/feed') + + self._clear_handler(tmp_xml_feed) + self._get_time_info_from_origin(out_xml) + + if self.out_feed_fps: + tmp_feed_fps_obj = tmp_xml_feed.find( + "startTimecode/rate") + tmp_feed_fps_obj.text = self.out_feed_fps + if self.out_feed_nb_ticks: + tmp_feed_nb_ticks_obj = tmp_xml_feed.find( + "startTimecode/nbTicks") + tmp_feed_nb_ticks_obj.text = self.out_feed_nb_ticks + if self.out_feed_drop_mode: + tmp_feed_drop_mode_obj = tmp_xml_feed.find( + "startTimecode/dropMode") + tmp_feed_drop_mode_obj.text = self.out_feed_drop_mode + + new_path_obj = tmp_xml_feed.find( + "spans/span/path") + new_path = new_path_obj.text + + feed_added = False + if not self._feed_exists(out_xml, new_path): + tmp_xml_feed.set('vuid', self.feed_version_name) + # Append new temp file feed to .clip source out xml + out_track = out_xml.find("tracks/track") + # add colorspace if any is set + if self.feed_colorspace: + self._add_colorspace(tmp_xml_feed, self.feed_colorspace) + + out_feeds = out_track.find('feeds') + out_feeds.set('currentVersion', self.feed_version_name) + out_feeds.append(tmp_xml_feed) + + print( + "Appending new feed: {}".format( + self.feed_version_name)) + feed_added = True + + if feed_added: + # Append vUID to versions + out_xml_versions_obj = out_xml.find('versions') + out_xml_versions_obj.set( + 'currentVersion', self.feed_version_name) + new_version_obj = ET.Element( + "version", {"type": "version", "uid": self.feed_version_name}) + out_xml_versions_obj.insert(0, new_version_obj) + + xml_data = self._fix_xml_data(out_xml) + + # fist create backup + self._create_openclip_backup_file(self.out_file) + + print("Adding feed version: {}".format(self.feed_version_name)) + + self._write_result_xml_to_file(xml_data) + + print("openClip Updated: {}".format(self.out_file)) + + self._clear_tmp_file() + + def _get_time_info_from_origin(self, xml_data): + try: + for out_track in xml_data.iter('track'): + for out_feed in out_track.iter('feed'): + out_feed_nb_ticks_obj = out_feed.find( + 'startTimecode/nbTicks') + self.out_feed_nb_ticks = out_feed_nb_ticks_obj.text + out_feed_fps_obj = out_feed.find( + 'startTimecode/rate') + self.out_feed_fps = out_feed_fps_obj.text + out_feed_drop_mode_obj = out_feed.find( + 'startTimecode/dropMode') + self.out_feed_drop_mode = out_feed_drop_mode_obj.text + break + else: + continue + except Exception as msg: + print(msg) + + def _feed_exists(self, xml_data, path): + # loop all available feed paths and check if + # the path is not already in file + for src_path in xml_data.iter('path'): + if path == src_path.text: + print("Not appending file as it already is in .clip file") + return True + + def _fix_xml_data(self, xml_data): + xml_root = xml_data.getroot() + self._clear_handler(xml_root) + return ET.tostring(xml_root).decode('utf-8') + + def maintain_clip(self): + self._get_media_info_args() + + if self.create_new_clip: + # New openClip + self._create_new_open_clip() + else: + self._update_open_clip() + + def _write_result_xml_to_file(self, xml_data): + with open(self.out_file, "w") as f: + f.write(xml_data) + + def _create_openclip_backup_file(self, file): + bck_file = "{}.bak".format(file) + # if backup does not exist + if not os.path.isfile(bck_file): + shutil.copy2(file, bck_file) + else: + # in case it exists and is already multiplied + created = False + for _i in range(1, 99): + bck_file = "{name}.bak.{idx:0>2}".format( + name=file, + idx=_i) + # create numbered backup file + if not os.path.isfile(bck_file): + shutil.copy2(file, bck_file) + created = True + break + # in case numbered does not exists + if not created: + bck_file = "{}.bak.last".format(file) + shutil.copy2(file, bck_file) + + def _add_colorspace(self, feed_obj, profile_name): + feed_storage_obj = feed_obj.find("storageFormat") + feed_clr_obj = feed_storage_obj.find("colourSpace") + if not feed_clr_obj: + feed_clr_obj = ET.Element( + "colourSpace", {"type": "string"}) + feed_storage_obj.append(feed_clr_obj) + + feed_clr_obj.text = profile_name diff --git a/openpype/hosts/flame/api/render_utils.py b/openpype/hosts/flame/api/render_utils.py index fe406f1c94..1b086646cc 100644 --- a/openpype/hosts/flame/api/render_utils.py +++ b/openpype/hosts/flame/api/render_utils.py @@ -1,10 +1,4 @@ import os -import sys -import traceback -from xml.etree import ElementTree as ET -import shutil -import openpype.lib -import six def export_clip(export_path, clip, preset_path, **kwargs): @@ -129,249 +123,3 @@ def get_preset_path_by_xml_name(xml_preset_name): # if nothing found then return False return False - - -class OpenClip: - media_script_path = "/opt/Autodesk/mio/current/dl_get_media_info" - tmp_name = "_tmp.clip" - tmp_file = None - create_new_clip = False - - out_feed_nb_ticks = None - out_feed_fps = None - out_feed_drop_mode = None - - def __init__(self, name, openclip_file_path, feed_data): - # test if media script paht exists - self._validate_media_script_path() - - # new feed variables: - feed_path = feed_data["path"] - self.feed_version_name = feed_data["version"] - self.feed_colorspace = feed_data.get("colorspace") - - # derivate other feed variables - self.feed_basename = os.path.basename(feed_path) - self.feed_dir = os.path.dirname(feed_path) - self.feed_ext = os.path.splitext(self.feed_basename)[1][1:].lower() - - if not os.path.isfile(openclip_file_path): - # openclip does not exist yet and will be created - self.tmp_file = self.out_file = openclip_file_path - self.create_new_clip = True - - else: - # output a temp file - self.out_file = openclip_file_path - self.tmp_file = os.path.join(self.feed_dir, self.tmp_name) - self._clear_tmp_file() - - print("Temp File: {}".format(self.tmp_file)) - - def _validate_media_script_path(self): - if not os.path.isfile(self.media_script_path): - raise IOError("Media Scirpt does not exist: `{}`".format( - self.media_script_path)) - - def _get_media_info_args(self): - # Create cmd arguments for gettig xml file info file - cmd_args = [ - self.media_script_path, - "-e", self.feed_ext, - "-o", self.tmp_file, - self.feed_dir - ] - - # execute creation of clip xml template data - try: - openpype.lib.run_subprocess(cmd_args) - except TypeError: - print("Error createing self.tmp_file") - six.reraise(*sys.exc_info()) - - def _clear_tmp_file(self): - if os.path.isfile(self.tmp_file): - os.remove(self.tmp_file) - - def _clear_handler(self, xml_object): - for handler in xml_object.findall("./handler"): - print("Handler found") - xml_object.remove(handler) - - def _create_new_open_clip(self): - print("Building new openClip") - - tmp_xml = ET.parse(self.tmp_file) - - tmp_xml_feeds = tmp_xml.find('tracks/track/feeds') - tmp_xml_feeds.set('currentVersion', self.feed_version_name) - for tmp_feed in tmp_xml_feeds: - tmp_feed.set('vuid', self.feed_version_name) - - # add colorspace if any is set - if self.feed_colorspace: - self._add_colorspace(tmp_feed, self.feed_colorspace) - - self._clear_handler(tmp_feed) - - tmp_xml_versions_obj = tmp_xml.find('versions') - tmp_xml_versions_obj.set('currentVersion', self.feed_version_name) - for xml_new_version in tmp_xml_versions_obj: - xml_new_version.set('uid', self.feed_version_name) - xml_new_version.set('type', 'version') - - xml_data = self._fix_xml_data(tmp_xml) - print("Adding feed version: {}".format(self.feed_basename)) - - self._write_result_xml_to_file(xml_data) - - print("openClip Updated: %s" % self.tmp_file) - - def _update_open_clip(self): - print("Updating openClip ..") - - out_xml = ET.parse(self.out_file) - tmp_xml = ET.parse(self.tmp_file) - - print(">> out_xml: {}".format(out_xml)) - print(">> tmp_xml: {}".format(tmp_xml)) - - # Get new feed from tmp file - tmp_xml_feed = tmp_xml.find('tracks/track/feeds/feed') - - self._clear_handler(tmp_xml_feed) - self._get_time_info_from_origin(out_xml) - - if self.out_feed_fps: - tmp_feed_fps_obj = tmp_xml_feed.find( - "startTimecode/rate") - tmp_feed_fps_obj.text = self.out_feed_fps - if self.out_feed_nb_ticks: - tmp_feed_nb_ticks_obj = tmp_xml_feed.find( - "startTimecode/nbTicks") - tmp_feed_nb_ticks_obj.text = self.out_feed_nb_ticks - if self.out_feed_drop_mode: - tmp_feed_drop_mode_obj = tmp_xml_feed.find( - "startTimecode/dropMode") - tmp_feed_drop_mode_obj.text = self.out_feed_drop_mode - - new_path_obj = tmp_xml_feed.find( - "spans/span/path") - new_path = new_path_obj.text - - feed_added = False - if not self._feed_exists(out_xml, new_path): - tmp_xml_feed.set('vuid', self.feed_version_name) - # Append new temp file feed to .clip source out xml - out_track = out_xml.find("tracks/track") - # add colorspace if any is set - if self.feed_colorspace: - self._add_colorspace(tmp_xml_feed, self.feed_colorspace) - - out_feeds = out_track.find('feeds') - out_feeds.set('currentVersion', self.feed_version_name) - out_feeds.append(tmp_xml_feed) - - print( - "Appending new feed: {}".format( - self.feed_version_name)) - feed_added = True - - if feed_added: - # Append vUID to versions - out_xml_versions_obj = out_xml.find('versions') - out_xml_versions_obj.set( - 'currentVersion', self.feed_version_name) - new_version_obj = ET.Element( - "version", {"type": "version", "uid": self.feed_version_name}) - out_xml_versions_obj.insert(0, new_version_obj) - - xml_data = self._fix_xml_data(out_xml) - - # fist create backup - self._create_openclip_backup_file(self.out_file) - - print("Adding feed version: {}".format(self.feed_version_name)) - - self._write_result_xml_to_file(xml_data) - - print("openClip Updated: {}".format(self.out_file)) - - self._clear_tmp_file() - - def _get_time_info_from_origin(self, xml_data): - try: - for out_track in xml_data.iter('track'): - for out_feed in out_track.iter('feed'): - out_feed_nb_ticks_obj = out_feed.find( - 'startTimecode/nbTicks') - self.out_feed_nb_ticks = out_feed_nb_ticks_obj.text - out_feed_fps_obj = out_feed.find( - 'startTimecode/rate') - self.out_feed_fps = out_feed_fps_obj.text - out_feed_drop_mode_obj = out_feed.find( - 'startTimecode/dropMode') - self.out_feed_drop_mode = out_feed_drop_mode_obj.text - break - else: - continue - except Exception as msg: - print(msg) - - def _feed_exists(self, xml_data, path): - # loop all available feed paths and check if - # the path is not already in file - for src_path in xml_data.iter('path'): - if path == src_path.text: - print("Not appending file as it already is in .clip file") - return True - - def _fix_xml_data(self, xml_data): - xml_root = xml_data.getroot() - self._clear_handler(xml_root) - return ET.tostring(xml_root).decode('utf-8') - - def maintain_clip(self): - self._get_media_info_args() - - if self.create_new_clip: - # New openClip - self._create_new_open_clip() - else: - self._update_open_clip() - - def _write_result_xml_to_file(self, xml_data): - with open(self.out_file, "w") as f: - f.write(xml_data) - - def _create_openclip_backup_file(self, file): - bck_file = "{}.bak".format(file) - # if backup does not exist - if not os.path.isfile(bck_file): - shutil.copy2(file, bck_file) - else: - # in case it exists and is already multiplied - created = False - for _i in range(1, 99): - bck_file = "{name}.bak.{idx:0>2}".format( - name=file, - idx=_i) - # create numbered backup file - if not os.path.isfile(bck_file): - shutil.copy2(file, bck_file) - created = True - break - # in case numbered does not exists - if not created: - bck_file = "{}.bak.last".format(file) - shutil.copy2(file, bck_file) - - def _add_colorspace(self, feed_obj, profile_name): - feed_storage_obj = feed_obj.find("storageFormat") - feed_clr_obj = feed_storage_obj.find("colourSpace") - if not feed_clr_obj: - feed_clr_obj = ET.Element( - "colourSpace", {"type": "string"}) - feed_storage_obj.append(feed_clr_obj) - - feed_clr_obj.text = profile_name From 19574980d513b296f30f52dc30fcd1aaf2681c73 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 31 Jan 2022 12:07:02 +0100 Subject: [PATCH 11/27] flame: loader clip wip --- .../hosts/flame/plugins/load/load_clip.py | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 openpype/hosts/flame/plugins/load/load_clip.py diff --git a/openpype/hosts/flame/plugins/load/load_clip.py b/openpype/hosts/flame/plugins/load/load_clip.py new file mode 100644 index 0000000000..6594f0e284 --- /dev/null +++ b/openpype/hosts/flame/plugins/load/load_clip.py @@ -0,0 +1,185 @@ +from avalon import io, api +import openpype.hosts.flame.api as opfapi + + +class LoadClip(opfapi.ClipLoader): + """Load a subset to timeline as clip + + Place clip to timeline on its asset origin timings collected + during conforming to project + """ + + families = ["render2d", "source", "plate", "render", "review"] + representations = ["exr", "dpx", "jpg", "jpeg", "png", "h264"] + + label = "Load as clip" + order = -10 + icon = "code-fork" + color = "orange" + + clip_name_template = "{asset}_{subset}_{representation}" + + def load(self, context, name, namespace, options): + + # load clip to timeline and get main variables + namespace = namespace + version = context['version'] + version_data = version.get("data", {}) + version_name = version.get("name", None) + colorspace = version_data.get("colorspace", None) + clip_name = self.clip_name_template.format( + **context["representation"]["context"]) + + # todo: settings in imageio + # convert colorspace with ocio to flame mapping + # in imageio flame section + colorspace = colorspace + + # create new workfile version in conform task for _v###.clip + # every new version is also the *_latest.clip + openclip_name = clip_name + + # prepare Reel group in actual desktop + reel_object = "prepared reel object" + + # prepare clip data from context ad send it to openClipLoader + loading_context = { + "path": self.fname.replace("\\", "/"), + "colorspace": colorspace, + "clip_name": openclip_name, + "reel_object": reel_object + + } + + # with maintained openclip as opc + opc = "loaded open pype clip " + # opc set in and out marks if handles + + # opc refresh versions + + # add additional metadata from the version to imprint Avalon knob + add_keys = [ + "frameStart", "frameEnd", "source", "author", + "fps", "handleStart", "handleEnd" + ] + + # move all version data keys to tag data + data_imprint = {} + for key in add_keys: + data_imprint.update({ + key: version_data.get(key, str(None)) + }) + + # add variables related to version context + data_imprint.update({ + "version": version_name, + "colorspace": colorspace, + "objectName": clip_name + }) + + # unwrap segment from clip + open_clip_segment = self._get_segment_from_clip(opc) + + return opfapi.containerise( + open_clip_segment, + name, namespace, context, + self.__class__.__name__, + data_imprint) + + def _get_segment_from_clip(self, clip): + # unwrapping segment from input clip + pass + + def switch(self, container, representation): + self.update(container, representation) + + def update(self, container, representation): + """ Updating previously loaded clips + """ + + # load clip to timeline and get main variables + name = container['name'] + namespace = container['namespace'] + track_item = phiero.get_track_items( + track_item_name=namespace) + version = io.find_one({ + "type": "version", + "_id": representation["parent"] + }) + version_data = version.get("data", {}) + version_name = version.get("name", None) + colorspace = version_data.get("colorspace", None) + object_name = "{}_{}".format(name, namespace) + file = api.get_representation_path(representation).replace("\\", "/") + clip = track_item.source() + + # reconnect media to new path + clip.reconnectMedia(file) + + # set colorspace + if colorspace: + clip.setSourceMediaColourTransform(colorspace) + + # add additional metadata from the version to imprint Avalon knob + add_keys = [ + "frameStart", "frameEnd", "source", "author", + "fps", "handleStart", "handleEnd" + ] + + # move all version data keys to tag data + data_imprint = {} + for key in add_keys: + data_imprint.update({ + key: version_data.get(key, str(None)) + }) + + # add variables related to version context + data_imprint.update({ + "representation": str(representation["_id"]), + "version": version_name, + "colorspace": colorspace, + "objectName": object_name + }) + + # update color of clip regarding the version order + self.set_item_color(track_item, version) + + return phiero.update_container(track_item, data_imprint) + + def remove(self, container): + """ Removing previously loaded clips + """ + # load clip to timeline and get main variables + namespace = container['namespace'] + track_item = phiero.get_track_items( + track_item_name=namespace) + track = track_item.parent() + + # remove track item from track + track.removeItem(track_item) + + @classmethod + def multiselection(cls, track_item): + if not cls.track: + cls.track = track_item.parent() + cls.sequence = cls.track.parent() + + @classmethod + def set_item_color(cls, track_item, version): + + clip = track_item.source() + # define version name + version_name = version.get("name", None) + # get all versions in list + versions = io.find({ + "type": "version", + "parent": version["parent"] + }).distinct('name') + + max_version = max(versions) + + # set clip colour + if version_name == max_version: + clip.binItem().setColor(cls.clip_color_last) + else: + clip.binItem().setColor(cls.clip_color) From 49499c82b41c24fd4b7379560e3bb682f82da9a8 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 31 Jan 2022 14:06:13 +0100 Subject: [PATCH 12/27] flame: load openclip to desktop wip --- openpype/hosts/flame/api/pipeline.py | 27 ++- openpype/hosts/flame/api/plugin.py | 20 +- .../hosts/flame/plugins/load/load_clip.py | 228 +++++++++++------- 3 files changed, 169 insertions(+), 106 deletions(-) diff --git a/openpype/hosts/flame/api/pipeline.py b/openpype/hosts/flame/api/pipeline.py index 30c70b491b..476a65e59b 100644 --- a/openpype/hosts/flame/api/pipeline.py +++ b/openpype/hosts/flame/api/pipeline.py @@ -4,7 +4,9 @@ Basic avalon integration import os import contextlib from avalon import api as avalon +from avalon.pipeline import AVALON_CONTAINER_ID from pyblish import api as pyblish +from collections import OrderedDict from openpype.api import Logger from .lib import ( set_segment_data_marker, @@ -68,14 +70,33 @@ def uninstall(): log.info("OpenPype Flame host uninstalled ...") -def containerise(tl_segment, +def containerise(flame_clip, name, namespace, context, loader=None, data=None): - # TODO: containerise - pass + + data_imprint = OrderedDict({ + "schema": "openpype:container-2.0", + "id": AVALON_CONTAINER_ID, + "name": str(name), + "namespace": str(namespace), + "loader": str(loader), + "representation": str(context["representation"]["_id"]), + }) + + if data: + for k, v in data.items(): + data_imprint.update({k: v}) + + log.debug("_ data_imprint: {}".format(data_imprint)) + + segment = flame_clip.versions[-1].tracks[-1].segments[-1] + + set_segment_data_marker(segment, data_imprint) + + return flame_clip def ls(): diff --git a/openpype/hosts/flame/api/plugin.py b/openpype/hosts/flame/api/plugin.py index a83f9a3b28..503971fef7 100644 --- a/openpype/hosts/flame/api/plugin.py +++ b/openpype/hosts/flame/api/plugin.py @@ -701,7 +701,7 @@ class OpenClipSolver: out_feed_fps = None out_feed_drop_mode = None - def __init__(self, name, openclip_file_path, feed_data): + def __init__(self, openclip_file_path, feed_data): # test if media script paht exists self._validate_media_script_path() @@ -728,6 +728,15 @@ class OpenClipSolver: print("Temp File: {}".format(self.tmp_file)) + def make(self): + self._get_media_info_args() + + if self.create_new_clip: + # New openClip + self._create_new_open_clip() + else: + self._update_open_clip() + def _validate_media_script_path(self): if not os.path.isfile(self.media_script_path): raise IOError("Media Scirpt does not exist: `{}`".format( @@ -891,15 +900,6 @@ class OpenClipSolver: self._clear_handler(xml_root) return ET.tostring(xml_root).decode('utf-8') - def maintain_clip(self): - self._get_media_info_args() - - if self.create_new_clip: - # New openClip - self._create_new_open_clip() - else: - self._update_open_clip() - def _write_result_xml_to_file(self, xml_data): with open(self.out_file, "w") as f: f.write(xml_data) diff --git a/openpype/hosts/flame/plugins/load/load_clip.py b/openpype/hosts/flame/plugins/load/load_clip.py index 6594f0e284..dd34bc8adb 100644 --- a/openpype/hosts/flame/plugins/load/load_clip.py +++ b/openpype/hosts/flame/plugins/load/load_clip.py @@ -1,3 +1,5 @@ +import os +import flame from avalon import io, api import openpype.hosts.flame.api as opfapi @@ -17,10 +19,18 @@ class LoadClip(opfapi.ClipLoader): icon = "code-fork" color = "orange" + # settings + reel_group_name = "OpenPype_Reels" + reel_name = "Loaded" clip_name_template = "{asset}_{subset}_{representation}" + def load(self, context, name, namespace, options): + # get flame objects + fproject = flame.project.current_project + self.fpd = fproject.current_workspace.desktop + # load clip to timeline and get main variables namespace = namespace version = context['version'] @@ -35,27 +45,28 @@ class LoadClip(opfapi.ClipLoader): # in imageio flame section colorspace = colorspace - # create new workfile version in conform task for _v###.clip - # every new version is also the *_latest.clip - openclip_name = clip_name - - # prepare Reel group in actual desktop - reel_object = "prepared reel object" + # create workfile path + workfile_dir = os.environ["AVALON_WORKDIR"] + openclip_path = os.path.join( + workfile_dir, clip_name, clip_name + ".clip" + ) # prepare clip data from context ad send it to openClipLoader loading_context = { "path": self.fname.replace("\\", "/"), "colorspace": colorspace, - "clip_name": openclip_name, - "reel_object": reel_object + "version": version_name } - # with maintained openclip as opc - opc = "loaded open pype clip " - # opc set in and out marks if handles + # make openpype clip file + opfapi.OpenClipSolver(openclip_path, loading_context).make() - # opc refresh versions + # prepare Reel group in actual desktop + opc = self._get_clip( + clip_name, + openclip_path + ) # add additional metadata from the version to imprint Avalon knob add_keys = [ @@ -77,109 +88,140 @@ class LoadClip(opfapi.ClipLoader): "objectName": clip_name }) - # unwrap segment from clip - open_clip_segment = self._get_segment_from_clip(opc) - return opfapi.containerise( - open_clip_segment, + opc, name, namespace, context, self.__class__.__name__, data_imprint) + def _get_clip(self, name, clip_path): + reel = self._get_reel() + # with maintained openclip as opc + matching_clip = [cl for cl in reel.clips + if cl.name.get_value() == name] + if matching_clip: + return matching_clip.pop() + else: + return flame.import_clips(clip_path, reel) + + def _get_reel(self): + + matching_rgroup = [ + rg for rg in self.fpd.reel_groups + if rg.name.get_value() == self.reel_group_name + ] + + if not matching_rgroup: + reel_group = self.fpd.create_reel_group(self.reel_group_name) + else: + reel_group = matching_rgroup.pop() + + matching_reel = [ + re for re in reel_group.reels + if re.name.get_value() == self.reel_name + ] + + if not matching_reel: + reel_group = reel_group.create_reel(self.reel_name) + else: + reel_group = matching_reel.pop() + + return reel_group + def _get_segment_from_clip(self, clip): # unwrapping segment from input clip pass - def switch(self, container, representation): - self.update(container, representation) + # def switch(self, container, representation): + # self.update(container, representation) - def update(self, container, representation): - """ Updating previously loaded clips - """ + # def update(self, container, representation): + # """ Updating previously loaded clips + # """ - # load clip to timeline and get main variables - name = container['name'] - namespace = container['namespace'] - track_item = phiero.get_track_items( - track_item_name=namespace) - version = io.find_one({ - "type": "version", - "_id": representation["parent"] - }) - version_data = version.get("data", {}) - version_name = version.get("name", None) - colorspace = version_data.get("colorspace", None) - object_name = "{}_{}".format(name, namespace) - file = api.get_representation_path(representation).replace("\\", "/") - clip = track_item.source() + # # load clip to timeline and get main variables + # name = container['name'] + # namespace = container['namespace'] + # track_item = phiero.get_track_items( + # track_item_name=namespace) + # version = io.find_one({ + # "type": "version", + # "_id": representation["parent"] + # }) + # version_data = version.get("data", {}) + # version_name = version.get("name", None) + # colorspace = version_data.get("colorspace", None) + # object_name = "{}_{}".format(name, namespace) + # file = api.get_representation_path(representation).replace("\\", "/") + # clip = track_item.source() - # reconnect media to new path - clip.reconnectMedia(file) + # # reconnect media to new path + # clip.reconnectMedia(file) - # set colorspace - if colorspace: - clip.setSourceMediaColourTransform(colorspace) + # # set colorspace + # if colorspace: + # clip.setSourceMediaColourTransform(colorspace) - # add additional metadata from the version to imprint Avalon knob - add_keys = [ - "frameStart", "frameEnd", "source", "author", - "fps", "handleStart", "handleEnd" - ] + # # add additional metadata from the version to imprint Avalon knob + # add_keys = [ + # "frameStart", "frameEnd", "source", "author", + # "fps", "handleStart", "handleEnd" + # ] - # move all version data keys to tag data - data_imprint = {} - for key in add_keys: - data_imprint.update({ - key: version_data.get(key, str(None)) - }) + # # move all version data keys to tag data + # data_imprint = {} + # for key in add_keys: + # data_imprint.update({ + # key: version_data.get(key, str(None)) + # }) - # add variables related to version context - data_imprint.update({ - "representation": str(representation["_id"]), - "version": version_name, - "colorspace": colorspace, - "objectName": object_name - }) + # # add variables related to version context + # data_imprint.update({ + # "representation": str(representation["_id"]), + # "version": version_name, + # "colorspace": colorspace, + # "objectName": object_name + # }) - # update color of clip regarding the version order - self.set_item_color(track_item, version) + # # update color of clip regarding the version order + # self.set_item_color(track_item, version) - return phiero.update_container(track_item, data_imprint) + # return phiero.update_container(track_item, data_imprint) - def remove(self, container): - """ Removing previously loaded clips - """ - # load clip to timeline and get main variables - namespace = container['namespace'] - track_item = phiero.get_track_items( - track_item_name=namespace) - track = track_item.parent() + # def remove(self, container): + # """ Removing previously loaded clips + # """ + # # load clip to timeline and get main variables + # namespace = container['namespace'] + # track_item = phiero.get_track_items( + # track_item_name=namespace) + # track = track_item.parent() - # remove track item from track - track.removeItem(track_item) + # # remove track item from track + # track.removeItem(track_item) - @classmethod - def multiselection(cls, track_item): - if not cls.track: - cls.track = track_item.parent() - cls.sequence = cls.track.parent() + # @classmethod + # def multiselection(cls, track_item): + # if not cls.track: + # cls.track = track_item.parent() + # cls.sequence = cls.track.parent() - @classmethod - def set_item_color(cls, track_item, version): + # @classmethod + # def set_item_color(cls, track_item, version): - clip = track_item.source() - # define version name - version_name = version.get("name", None) - # get all versions in list - versions = io.find({ - "type": "version", - "parent": version["parent"] - }).distinct('name') + # clip = track_item.source() + # # define version name + # version_name = version.get("name", None) + # # get all versions in list + # versions = io.find({ + # "type": "version", + # "parent": version["parent"] + # }).distinct('name') - max_version = max(versions) + # max_version = max(versions) - # set clip colour - if version_name == max_version: - clip.binItem().setColor(cls.clip_color_last) - else: - clip.binItem().setColor(cls.clip_color) + # # set clip colour + # if version_name == max_version: + # clip.binItem().setColor(cls.clip_color_last) + # else: + # clip.binItem().setColor(cls.clip_color) From a7c1815760687291e6cce3666665cb64b5ce40e9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 31 Jan 2022 14:22:40 +0100 Subject: [PATCH 13/27] flame: adding settings for loader --- .../defaults/project_settings/flame.json | 25 +++++++++ .../projects_schema/schema_project_flame.json | 55 +++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/openpype/settings/defaults/project_settings/flame.json b/openpype/settings/defaults/project_settings/flame.json index 3caf190e37..b601f9bcba 100644 --- a/openpype/settings/defaults/project_settings/flame.json +++ b/openpype/settings/defaults/project_settings/flame.json @@ -32,5 +32,30 @@ } } } + }, + "load": { + "LoadClip": { + "enabled": true, + "families": [ + "render2d", + "source", + "plate", + "render", + "review" + ], + "representations": [ + "exr", + "dpx", + "jpg", + "jpeg", + "png", + "h264", + "mov", + "mp4" + ], + "reel_group_name": "OpenPype_Reels", + "reel_name": "Loaded", + "clip_name_template": "{asset}_{subset}_{representation}" + } } } \ No newline at end of file diff --git a/openpype/settings/entities/schemas/projects_schema/schema_project_flame.json b/openpype/settings/entities/schemas/projects_schema/schema_project_flame.json index 4cb1a0bb2b..9ef05fa832 100644 --- a/openpype/settings/entities/schemas/projects_schema/schema_project_flame.json +++ b/openpype/settings/entities/schemas/projects_schema/schema_project_flame.json @@ -194,6 +194,61 @@ ] } ] + }, + { + "type": "dict", + "collapsible": true, + "key": "load", + "label": "Loader plugins", + "children": [ + { + "type": "dict", + "collapsible": true, + "key": "LoadClip", + "label": "Load Clip", + "checkbox_key": "enabled", + "children": [ + { + "type": "boolean", + "key": "enabled", + "label": "Enabled" + }, + { + "type": "list", + "key": "families", + "label": "Families", + "object_type": "text" + }, + { + "type": "list", + "key": "representations", + "label": "Representations", + "object_type": "text" + }, + { + "type": "separator" + }, + { + "type": "text", + "key": "reel_group_name", + "label": "Reel group name" + }, + { + "type": "text", + "key": "reel_name", + "label": "Reel name" + }, + { + "type": "separator" + }, + { + "type": "text", + "key": "clip_name_template", + "label": "Clip name template" + } + ] + } + ] } ] } From 1a624b99a7172ea9f0be4c760d62e00171dc4339 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 31 Jan 2022 21:00:39 +0100 Subject: [PATCH 14/27] flame: finalization clip loader --- openpype/hosts/flame/api/plugin.py | 39 +++++++++++-------- .../hosts/flame/plugins/load/load_clip.py | 31 +++++++++++---- 2 files changed, 46 insertions(+), 24 deletions(-) diff --git a/openpype/hosts/flame/api/plugin.py b/openpype/hosts/flame/api/plugin.py index 503971fef7..c28ab0f556 100644 --- a/openpype/hosts/flame/api/plugin.py +++ b/openpype/hosts/flame/api/plugin.py @@ -701,6 +701,8 @@ class OpenClipSolver: out_feed_fps = None out_feed_drop_mode = None + log = log + def __init__(self, openclip_file_path, feed_data): # test if media script paht exists self._validate_media_script_path() @@ -710,6 +712,9 @@ class OpenClipSolver: self.feed_version_name = feed_data["version"] self.feed_colorspace = feed_data.get("colorspace") + if feed_data.get("logger"): + self.log = feed_data["logger"] + # derivate other feed variables self.feed_basename = os.path.basename(feed_path) self.feed_dir = os.path.dirname(feed_path) @@ -726,7 +731,7 @@ class OpenClipSolver: self.tmp_file = os.path.join(self.feed_dir, self.tmp_name) self._clear_tmp_file() - print("Temp File: {}".format(self.tmp_file)) + self.log.info("Temp File: {}".format(self.tmp_file)) def make(self): self._get_media_info_args() @@ -753,9 +758,9 @@ class OpenClipSolver: # execute creation of clip xml template data try: - flib.run_subprocess(cmd_args) + openpype.run_subprocess(cmd_args) except TypeError: - print("Error createing self.tmp_file") + self.log.error("Error createing self.tmp_file") six.reraise(*sys.exc_info()) def _clear_tmp_file(self): @@ -764,11 +769,11 @@ class OpenClipSolver: def _clear_handler(self, xml_object): for handler in xml_object.findall("./handler"): - print("Handler found") + self.log.debug("Handler found") xml_object.remove(handler) def _create_new_open_clip(self): - print("Building new openClip") + self.log.info("Building new openClip") tmp_xml = ET.parse(self.tmp_file) @@ -790,20 +795,20 @@ class OpenClipSolver: xml_new_version.set('type', 'version') xml_data = self._fix_xml_data(tmp_xml) - print("Adding feed version: {}".format(self.feed_basename)) + self.log.info("Adding feed version: {}".format(self.feed_basename)) self._write_result_xml_to_file(xml_data) - print("openClip Updated: %s" % self.tmp_file) + self.log.info("openClip Updated: {}".format(self.tmp_file)) def _update_open_clip(self): - print("Updating openClip ..") + self.log.info("Updating openClip ..") out_xml = ET.parse(self.out_file) tmp_xml = ET.parse(self.tmp_file) - print(">> out_xml: {}".format(out_xml)) - print(">> tmp_xml: {}".format(tmp_xml)) + self.log.debug(">> out_xml: {}".format(out_xml)) + self.log.debug(">> tmp_xml: {}".format(tmp_xml)) # Get new feed from tmp file tmp_xml_feed = tmp_xml.find('tracks/track/feeds/feed') @@ -841,7 +846,7 @@ class OpenClipSolver: out_feeds.set('currentVersion', self.feed_version_name) out_feeds.append(tmp_xml_feed) - print( + self.log.info( "Appending new feed: {}".format( self.feed_version_name)) feed_added = True @@ -860,11 +865,12 @@ class OpenClipSolver: # fist create backup self._create_openclip_backup_file(self.out_file) - print("Adding feed version: {}".format(self.feed_version_name)) + self.log.info("Adding feed version: {}".format( + self.feed_version_name)) self._write_result_xml_to_file(xml_data) - print("openClip Updated: {}".format(self.out_file)) + self.log.info("openClip Updated: {}".format(self.out_file)) self._clear_tmp_file() @@ -885,14 +891,15 @@ class OpenClipSolver: else: continue except Exception as msg: - print(msg) + self.log.warning(msg) def _feed_exists(self, xml_data, path): # loop all available feed paths and check if # the path is not already in file for src_path in xml_data.iter('path'): if path == src_path.text: - print("Not appending file as it already is in .clip file") + self.log.warning( + "Not appending file as it already is in .clip file") return True def _fix_xml_data(self, xml_data): @@ -929,7 +936,7 @@ class OpenClipSolver: def _add_colorspace(self, feed_obj, profile_name): feed_storage_obj = feed_obj.find("storageFormat") feed_clr_obj = feed_storage_obj.find("colourSpace") - if not feed_clr_obj: + if feed_clr_obj is not None: feed_clr_obj = ET.Element( "colourSpace", {"type": "string"}) feed_storage_obj.append(feed_clr_obj) diff --git a/openpype/hosts/flame/plugins/load/load_clip.py b/openpype/hosts/flame/plugins/load/load_clip.py index dd34bc8adb..112571bf09 100644 --- a/openpype/hosts/flame/plugins/load/load_clip.py +++ b/openpype/hosts/flame/plugins/load/load_clip.py @@ -1,6 +1,6 @@ import os import flame -from avalon import io, api +from pprint import pformat import openpype.hosts.flame.api as opfapi @@ -24,7 +24,6 @@ class LoadClip(opfapi.ClipLoader): reel_name = "Loaded" clip_name_template = "{asset}_{subset}_{representation}" - def load(self, context, name, namespace, options): # get flame objects @@ -47,17 +46,27 @@ class LoadClip(opfapi.ClipLoader): # create workfile path workfile_dir = os.environ["AVALON_WORKDIR"] - openclip_path = os.path.join( - workfile_dir, clip_name, clip_name + ".clip" + openclip_dir = os.path.join( + workfile_dir, clip_name ) + openclip_path = os.path.join( + openclip_dir, clip_name + ".clip" + ) + if not os.path.exists(openclip_dir): + os.makedirs(openclip_dir) # prepare clip data from context ad send it to openClipLoader loading_context = { "path": self.fname.replace("\\", "/"), "colorspace": colorspace, - "version": version_name + "version": "v{:0>3}".format(version_name), + "logger": self.log } + self.log.debug(pformat( + loading_context + )) + self.log.debug(openclip_path) # make openpype clip file opfapi.OpenClipSolver(openclip_path, loading_context).make() @@ -102,7 +111,8 @@ class LoadClip(opfapi.ClipLoader): if matching_clip: return matching_clip.pop() else: - return flame.import_clips(clip_path, reel) + created_clips = flame.import_clips(str(clip_path), reel) + return created_clips.pop() def _get_reel(self): @@ -112,7 +122,12 @@ class LoadClip(opfapi.ClipLoader): ] if not matching_rgroup: - reel_group = self.fpd.create_reel_group(self.reel_group_name) + reel_group = self.fpd.create_reel_group(str(self.reel_group_name)) + for _r in reel_group.reels: + if "reel" not in _r.name.get_value().lower(): + continue + self.log.debug("Removing: {}".format(_r.name)) + flame.delete(_r) else: reel_group = matching_rgroup.pop() @@ -122,7 +137,7 @@ class LoadClip(opfapi.ClipLoader): ] if not matching_reel: - reel_group = reel_group.create_reel(self.reel_name) + reel_group = reel_group.create_reel(str(self.reel_name)) else: reel_group = matching_reel.pop() From 255bf9e6ea3e1b47f4ca2877ce73127113762bb6 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 3 Feb 2022 13:41:14 +0100 Subject: [PATCH 15/27] flame: adding exception to ftrack plugin --- .../openpype_flame_to_ftrack/openpype_flame_to_ftrack.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openpype/hosts/flame/api/utility_scripts/openpype_flame_to_ftrack/openpype_flame_to_ftrack.py b/openpype/hosts/flame/api/utility_scripts/openpype_flame_to_ftrack/openpype_flame_to_ftrack.py index 688b8b6ae3..ecc16fde6e 100644 --- a/openpype/hosts/flame/api/utility_scripts/openpype_flame_to_ftrack/openpype_flame_to_ftrack.py +++ b/openpype/hosts/flame/api/utility_scripts/openpype_flame_to_ftrack/openpype_flame_to_ftrack.py @@ -3,6 +3,11 @@ from __future__ import print_function import os import sys +try: + import six +except ImportError: + raise ImportError("Cannot import this module") + SCRIPT_DIR = os.path.dirname(__file__) PACKAGE_DIR = os.path.join(SCRIPT_DIR, "modules") sys.path.append(PACKAGE_DIR) From e9b7501a1730f3bf65871a2cf0120b591d74c8cf Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 10 Feb 2022 12:58:50 +0100 Subject: [PATCH 16/27] addressing PR comments --- openpype/hosts/flame/api/pipeline.py | 7 +++---- openpype/hosts/flame/api/plugin.py | 15 ++------------- .../openpype_flame_to_ftrack.py | 6 +++--- 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/openpype/hosts/flame/api/pipeline.py b/openpype/hosts/flame/api/pipeline.py index 476a65e59b..21cb7422de 100644 --- a/openpype/hosts/flame/api/pipeline.py +++ b/openpype/hosts/flame/api/pipeline.py @@ -6,7 +6,6 @@ import contextlib from avalon import api as avalon from avalon.pipeline import AVALON_CONTAINER_ID from pyblish import api as pyblish -from collections import OrderedDict from openpype.api import Logger from .lib import ( set_segment_data_marker, @@ -77,18 +76,18 @@ def containerise(flame_clip, loader=None, data=None): - data_imprint = OrderedDict({ + data_imprint = { "schema": "openpype:container-2.0", "id": AVALON_CONTAINER_ID, "name": str(name), "namespace": str(namespace), "loader": str(loader), "representation": str(context["representation"]["_id"]), - }) + } if data: for k, v in data.items(): - data_imprint.update({k: v}) + data_imprint[k] = v log.debug("_ data_imprint: {}".format(data_imprint)) diff --git a/openpype/hosts/flame/api/plugin.py b/openpype/hosts/flame/api/plugin.py index c28ab0f556..aba83c543a 100644 --- a/openpype/hosts/flame/api/plugin.py +++ b/openpype/hosts/flame/api/plugin.py @@ -4,7 +4,6 @@ import shutil import sys from avalon.vendor import qargparse from xml.etree import ElementTree as ET -import shutil import six from Qt import QtWidgets, QtCore import openpype.api as openpype @@ -680,16 +679,6 @@ class ClipLoader(avalon.Loader): ): pass - def update(self, container, representation): - """Update an existing `container` - """ - pass - - def remove(self, container): - """Remove an existing `container` - """ - pass - class OpenClipSolver: media_script_path = "/opt/Autodesk/mio/current/dl_get_media_info" @@ -734,7 +723,7 @@ class OpenClipSolver: self.log.info("Temp File: {}".format(self.tmp_file)) def make(self): - self._get_media_info_args() + self._generate_media_info_file() if self.create_new_clip: # New openClip @@ -747,7 +736,7 @@ class OpenClipSolver: raise IOError("Media Scirpt does not exist: `{}`".format( self.media_script_path)) - def _get_media_info_args(self): + def _generate_media_info_file(self): # Create cmd arguments for gettig xml file info file cmd_args = [ self.media_script_path, diff --git a/openpype/hosts/flame/api/utility_scripts/openpype_flame_to_ftrack/openpype_flame_to_ftrack.py b/openpype/hosts/flame/api/utility_scripts/openpype_flame_to_ftrack/openpype_flame_to_ftrack.py index ecc16fde6e..65c1840a72 100644 --- a/openpype/hosts/flame/api/utility_scripts/openpype_flame_to_ftrack/openpype_flame_to_ftrack.py +++ b/openpype/hosts/flame/api/utility_scripts/openpype_flame_to_ftrack/openpype_flame_to_ftrack.py @@ -4,9 +4,9 @@ import os import sys try: - import six -except ImportError: - raise ImportError("Cannot import this module") + import six # noqa +except ImportError as msg: + raise ImportError("Cannot import this module: {}".format(msg)) from msg SCRIPT_DIR = os.path.dirname(__file__) PACKAGE_DIR = os.path.join(SCRIPT_DIR, "modules") From 59106179435cdc267a1dc13a6f7d6b76ca470bc3 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 10 Feb 2022 13:01:27 +0100 Subject: [PATCH 17/27] addresing comment https://github.com/pypeclub/OpenPype/pull/2622#discussion_r797535248 --- openpype/hosts/flame/api/plugin.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/openpype/hosts/flame/api/plugin.py b/openpype/hosts/flame/api/plugin.py index aba83c543a..c39ac9108f 100644 --- a/openpype/hosts/flame/api/plugin.py +++ b/openpype/hosts/flame/api/plugin.py @@ -670,15 +670,6 @@ class ClipLoader(avalon.Loader): ) ] - def load( - self, - context, - name=None, - namespace=None, - options=None - ): - pass - class OpenClipSolver: media_script_path = "/opt/Autodesk/mio/current/dl_get_media_info" From 8e12ef43df359a1aeafc4abb8d78307a8c86edf0 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 10 Feb 2022 15:28:19 +0100 Subject: [PATCH 18/27] flame: add clip segment unpacking method --- openpype/hosts/flame/api/__init__.py | 4 +++- openpype/hosts/flame/api/lib.py | 15 +++++++++++++++ openpype/hosts/flame/api/pipeline.py | 8 +++----- openpype/hosts/flame/plugins/load/load_clip.py | 4 +++- yarn.lock | 4 ++++ 5 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 yarn.lock diff --git a/openpype/hosts/flame/api/__init__.py b/openpype/hosts/flame/api/__init__.py index 2aeb0d9c16..56bbadd2fc 100644 --- a/openpype/hosts/flame/api/__init__.py +++ b/openpype/hosts/flame/api/__init__.py @@ -28,7 +28,8 @@ from .lib import ( get_reformated_filename, get_frame_from_filename, get_padding_from_filename, - maintained_object_duplication + maintained_object_duplication, + get_clip_segment ) from .utils import ( setup, @@ -99,6 +100,7 @@ __all__ = [ "get_frame_from_filename", "get_padding_from_filename", "maintained_object_duplication", + "get_clip_segment", # pipeline "install", diff --git a/openpype/hosts/flame/api/lib.py b/openpype/hosts/flame/api/lib.py index f3c918caab..bbb7c38119 100644 --- a/openpype/hosts/flame/api/lib.py +++ b/openpype/hosts/flame/api/lib.py @@ -692,3 +692,18 @@ def maintained_object_duplication(item): finally: # delete the item at the end flame.delete(duplicate) + + +def get_clip_segment(flame_clip): + name = flame_clip.name.get_value() + version = flame_clip.versions[0] + track = version.tracks[0] + segments = track.segments + + if len(segments) < 1: + raise ValueError("Clip `{}` has no segments!".format(name)) + + if len(segments) > 1: + raise ValueError("Clip `{}` has too many segments!".format(name)) + + return segments[0] diff --git a/openpype/hosts/flame/api/pipeline.py b/openpype/hosts/flame/api/pipeline.py index 21cb7422de..fa007e63af 100644 --- a/openpype/hosts/flame/api/pipeline.py +++ b/openpype/hosts/flame/api/pipeline.py @@ -69,7 +69,7 @@ def uninstall(): log.info("OpenPype Flame host uninstalled ...") -def containerise(flame_clip, +def containerise(flame_clip_segment, name, namespace, context, @@ -91,11 +91,9 @@ def containerise(flame_clip, log.debug("_ data_imprint: {}".format(data_imprint)) - segment = flame_clip.versions[-1].tracks[-1].segments[-1] + set_segment_data_marker(flame_clip_segment, data_imprint) - set_segment_data_marker(segment, data_imprint) - - return flame_clip + return True def ls(): diff --git a/openpype/hosts/flame/plugins/load/load_clip.py b/openpype/hosts/flame/plugins/load/load_clip.py index 112571bf09..23598cdb27 100644 --- a/openpype/hosts/flame/plugins/load/load_clip.py +++ b/openpype/hosts/flame/plugins/load/load_clip.py @@ -97,8 +97,10 @@ class LoadClip(opfapi.ClipLoader): "objectName": clip_name }) + opc_segment = opfapi.get_clip_segment(opc) + return opfapi.containerise( - opc, + opc_segment, name, namespace, context, self.__class__.__name__, data_imprint) diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000000..fb57ccd13a --- /dev/null +++ b/yarn.lock @@ -0,0 +1,4 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + From c545938e2a1d912c24a0306d01ad58b6da817629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Mon, 14 Feb 2022 12:09:51 +0100 Subject: [PATCH 19/27] Update openpype/hosts/flame/api/plugin.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/hosts/flame/api/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/flame/api/plugin.py b/openpype/hosts/flame/api/plugin.py index c39ac9108f..db1793cba8 100644 --- a/openpype/hosts/flame/api/plugin.py +++ b/openpype/hosts/flame/api/plugin.py @@ -740,7 +740,7 @@ class OpenClipSolver: try: openpype.run_subprocess(cmd_args) except TypeError: - self.log.error("Error createing self.tmp_file") + self.log.error("Error creating self.tmp_file") six.reraise(*sys.exc_info()) def _clear_tmp_file(self): From 6664db839fa0f9516916b80cddccfc17be6b0eb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Mon, 14 Feb 2022 12:10:03 +0100 Subject: [PATCH 20/27] Update openpype/hosts/flame/plugins/publish/extract_subset_resources.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../hosts/flame/plugins/publish/extract_subset_resources.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index e00f97d8ea..5abbbb4b15 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -49,10 +49,9 @@ class ExtractSubsetResources(openpype.api.Extractor): def process(self, instance): try: self._process(instance) - # bring ui back - self.hide_ui_on_process = False except Exception as msg: self.log.error(msg) + finally: # bring ui back self.hide_ui_on_process = False From 91f9d41c39a91310c1c647ce7ef32131128dedf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Mon, 14 Feb 2022 12:11:04 +0100 Subject: [PATCH 21/27] Update openpype/hosts/flame/plugins/publish/extract_subset_resources.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- .../flame/plugins/publish/extract_subset_resources.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index 5abbbb4b15..d774b07fca 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -249,10 +249,10 @@ class ExtractSubsetResources(openpype.api.Extractor): if not new_stage_dir: new_stage_dir = root - if new_stage_dir: - return new_stage_dir, new_files_list - else: - raise IOError( + if not new_stage_dir: + raise AssertionError( "Files in `{}` are not correct! Check `{}`".format( files_list, stage_dir) ) + + return new_stage_dir, new_files_list From 84a711dd7a3167fd573526dd341caf77038a593e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 14 Feb 2022 18:00:30 +0100 Subject: [PATCH 22/27] flame: load containerized postponed to next dev --- openpype/hosts/flame/plugins/load/load_clip.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/openpype/hosts/flame/plugins/load/load_clip.py b/openpype/hosts/flame/plugins/load/load_clip.py index 23598cdb27..c0c6bf95c3 100644 --- a/openpype/hosts/flame/plugins/load/load_clip.py +++ b/openpype/hosts/flame/plugins/load/load_clip.py @@ -3,7 +3,6 @@ import flame from pprint import pformat import openpype.hosts.flame.api as opfapi - class LoadClip(opfapi.ClipLoader): """Load a subset to timeline as clip @@ -97,13 +96,16 @@ class LoadClip(opfapi.ClipLoader): "objectName": clip_name }) - opc_segment = opfapi.get_clip_segment(opc) + # TODO: finish the containerisation + # opc_segment = opfapi.get_clip_segment(opc) - return opfapi.containerise( - opc_segment, - name, namespace, context, - self.__class__.__name__, - data_imprint) + # return opfapi.containerise( + # opc_segment, + # name, namespace, context, + # self.__class__.__name__, + # data_imprint) + + return opc def _get_clip(self, name, clip_path): reel = self._get_reel() From 72439dd4f6d6249fd38d781a18ad34a966354fd7 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 16 Feb 2022 11:03:34 +0100 Subject: [PATCH 23/27] flame: simplification of module fail mechanism --- .../openpype_flame_to_ftrack/openpype_flame_to_ftrack.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/flame/api/utility_scripts/openpype_flame_to_ftrack/openpype_flame_to_ftrack.py b/openpype/hosts/flame/api/utility_scripts/openpype_flame_to_ftrack/openpype_flame_to_ftrack.py index 65c1840a72..5a72706ba1 100644 --- a/openpype/hosts/flame/api/utility_scripts/openpype_flame_to_ftrack/openpype_flame_to_ftrack.py +++ b/openpype/hosts/flame/api/utility_scripts/openpype_flame_to_ftrack/openpype_flame_to_ftrack.py @@ -3,10 +3,9 @@ from __future__ import print_function import os import sys -try: - import six # noqa -except ImportError as msg: - raise ImportError("Cannot import this module: {}".format(msg)) from msg +# only testing dependency for nested modules in package +import six # noqa + SCRIPT_DIR = os.path.dirname(__file__) PACKAGE_DIR = os.path.join(SCRIPT_DIR, "modules") From 671c1563737ef2a87b4f9c20544af178a24e7e91 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 16 Feb 2022 11:05:55 +0100 Subject: [PATCH 24/27] hound: suggestion --- openpype/hosts/flame/plugins/load/load_clip.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openpype/hosts/flame/plugins/load/load_clip.py b/openpype/hosts/flame/plugins/load/load_clip.py index c0c6bf95c3..8ba01d6937 100644 --- a/openpype/hosts/flame/plugins/load/load_clip.py +++ b/openpype/hosts/flame/plugins/load/load_clip.py @@ -3,6 +3,7 @@ import flame from pprint import pformat import openpype.hosts.flame.api as opfapi + class LoadClip(opfapi.ClipLoader): """Load a subset to timeline as clip From 4cc7d84cd41de71ab1734e7e1d43038bcbd856f5 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 16 Feb 2022 11:12:35 +0100 Subject: [PATCH 25/27] flame: removing redundant exception --- .../flame/plugins/publish/extract_subset_resources.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py index d774b07fca..db85bede85 100644 --- a/openpype/hosts/flame/plugins/publish/extract_subset_resources.py +++ b/openpype/hosts/flame/plugins/publish/extract_subset_resources.py @@ -47,16 +47,6 @@ class ExtractSubsetResources(openpype.api.Extractor): export_presets_mapping = {} def process(self, instance): - try: - self._process(instance) - except Exception as msg: - self.log.error(msg) - finally: - # bring ui back - self.hide_ui_on_process = False - - def _process(self, instance): - if ( self.keep_original_representation and "representations" not in instance.data From 2c5338af843905e16952213196e44a15d5ecb21d Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Wed, 16 Feb 2022 11:17:09 +0100 Subject: [PATCH 26/27] make sure window is visible after plugin process --- openpype/tools/pyblish_pype/window.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/openpype/tools/pyblish_pype/window.py b/openpype/tools/pyblish_pype/window.py index 7bb11745d6..9c4d4b10f4 100644 --- a/openpype/tools/pyblish_pype/window.py +++ b/openpype/tools/pyblish_pype/window.py @@ -1039,6 +1039,8 @@ class Window(QtWidgets.QDialog): and not self.controller.stopped ) self.button_suspend_logs.setEnabled(suspend_log_bool) + if not self.isVisible(): + self.setVisible(True) def on_was_skipped(self, plugin): plugin_item = self.plugin_model.plugin_items[plugin.id] @@ -1112,6 +1114,9 @@ class Window(QtWidgets.QDialog): plugin_item, instance_item ) + if not self.isVisible(): + self.setVisible(True) + # ------------------------------------------------------------------------- # # Functions From 1e0c67c7bdccf65f6419ab3a3d9cca8380ba84f9 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 16 Feb 2022 11:18:51 +0100 Subject: [PATCH 27/27] removing yarn.lock accidentally commited --- yarn.lock | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 yarn.lock diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index fb57ccd13a..0000000000 --- a/yarn.lock +++ /dev/null @@ -1,4 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - -