From bba0d10e9165b859a0cfd050adf4d8a1c886abfb Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 30 Dec 2019 15:09:05 +0100 Subject: [PATCH 01/26] feat(nuke): adding back plugin renaming to only mov creation in running nuke session --- .../nuke/publish/extract_review_mov.py | 181 ++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 pype/plugins/nuke/publish/extract_review_mov.py diff --git a/pype/plugins/nuke/publish/extract_review_mov.py b/pype/plugins/nuke/publish/extract_review_mov.py new file mode 100644 index 0000000000..ed3101951c --- /dev/null +++ b/pype/plugins/nuke/publish/extract_review_mov.py @@ -0,0 +1,181 @@ +import os +import nuke +import pyblish.api +import pype\ + +class ExtractReviewData(pype.api.Extractor): + """Extracts movie and thumbnail with baked in luts + + must be run after extract_render_local.py + + """ + + order = pyblish.api.ExtractorOrder + 0.01 + label = "Extract Review Data" + + families = ["review"] + hosts = ["nuke"] + + def process(self, instance): + + # Store selection + selection = [i for i in nuke.allNodes() if i["selected"].getValue()] + # Deselect all nodes to prevent external connections + [i["selected"].setValue(False) for i in nuke.allNodes()] + self.log.debug("creating staging dir:") + self.staging_dir(instance) + + self.log.debug("instance: {}".format(instance)) + self.log.debug("instance.data[families]: {}".format( + instance.data["families"])) + + self.render_review_representation(instance, representation="mov") + + # Restore selection + [i["selected"].setValue(False) for i in nuke.allNodes()] + [i["selected"].setValue(True) for i in selection] + + def render_review_representation(self, + instance, + representation="mov"): + + assert instance.data['representations'][0]['files'], "Instance data files should't be empty!" + + temporary_nodes = [] + stagingDir = instance.data[ + 'representations'][0]["stagingDir"].replace("\\", "/") + self.log.debug("StagingDir `{0}`...".format(stagingDir)) + + collection = instance.data.get("collection", None) + + if collection: + # get path + fname = os.path.basename(collection.format( + "{head}{padding}{tail}")) + fhead = collection.format("{head}") + + # get first and last frame + first_frame = min(collection.indexes) + last_frame = max(collection.indexes) + else: + fname = os.path.basename(instance.data.get("path", None)) + fhead = os.path.splitext(fname)[0] + "." + first_frame = instance.data.get("frameStart", None) + last_frame = instance.data.get("frameEnd", None) + + rnode = nuke.createNode("Read") + + rnode["file"].setValue( + os.path.join(stagingDir, fname).replace("\\", "/")) + + rnode["first"].setValue(first_frame) + rnode["origfirst"].setValue(first_frame) + rnode["last"].setValue(last_frame) + rnode["origlast"].setValue(last_frame) + temporary_nodes.append(rnode) + previous_node = rnode + + # get input process and connect it to baking + ipn = self.get_view_process_node() + if ipn is not None: + ipn.setInput(0, previous_node) + previous_node = ipn + temporary_nodes.append(ipn) + + reformat_node = nuke.createNode("Reformat") + + ref_node = self.nodes.get("Reformat", None) + if ref_node: + for k, v in ref_node: + self.log.debug("k,v: {0}:{1}".format(k,v)) + if isinstance(v, unicode): + v = str(v) + reformat_node[k].setValue(v) + + reformat_node.setInput(0, previous_node) + previous_node = reformat_node + temporary_nodes.append(reformat_node) + + dag_node = nuke.createNode("OCIODisplay") + dag_node.setInput(0, previous_node) + previous_node = dag_node + temporary_nodes.append(dag_node) + + # create write node + write_node = nuke.createNode("Write") + + if representation in "mov": + file = fhead + "baked.mov" + name = "baked" + path = os.path.join(stagingDir, file).replace("\\", "/") + self.log.debug("Path: {}".format(path)) + instance.data["baked_colorspace_movie"] = path + write_node["file"].setValue(path) + write_node["file_type"].setValue("mov") + write_node["raw"].setValue(1) + write_node.setInput(0, previous_node) + temporary_nodes.append(write_node) + tags = ["review", "delete"] + + elif representation in "jpeg": + file = fhead + "jpeg" + name = "thumbnail" + path = os.path.join(stagingDir, file).replace("\\", "/") + instance.data["thumbnail"] = path + write_node["file"].setValue(path) + write_node["file_type"].setValue("jpeg") + write_node["raw"].setValue(1) + write_node.setInput(0, previous_node) + temporary_nodes.append(write_node) + tags = ["thumbnail"] + + # retime for + first_frame = int(last_frame) / 2 + last_frame = int(last_frame) / 2 + + repre = { + 'name': name, + 'ext': representation, + 'files': file, + "stagingDir": stagingDir, + "frameStart": first_frame, + "frameEnd": last_frame, + "anatomy_template": "render", + "tags": tags + } + instance.data["representations"].append(repre) + + # Render frames + nuke.execute(write_node.name(), int(first_frame), int(last_frame)) + + self.log.debug("representations: {}".format(instance.data["representations"])) + + # Clean up + for node in temporary_nodes: + nuke.delete(node) + + def get_view_process_node(self): + + # Select only the target node + if nuke.selectedNodes(): + [n.setSelected(False) for n in nuke.selectedNodes()] + + ipn_orig = None + for v in [n for n in nuke.allNodes() + if "Viewer" in n.Class()]: + ip = v['input_process'].getValue() + ipn = v['input_process_node'].getValue() + if "VIEWER_INPUT" not in ipn and ip: + ipn_orig = nuke.toNode(ipn) + ipn_orig.setSelected(True) + + if ipn_orig: + nuke.nodeCopy('%clipboard%') + + [n.setSelected(False) for n in nuke.selectedNodes()] # Deselect all + + nuke.nodePaste('%clipboard%') + + ipn = nuke.selectedNode() + + return ipn From cd4ad045e6e53bb2ad9963e56d2acfac3c045ea2 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Sat, 4 Jan 2020 17:14:31 +0100 Subject: [PATCH 02/26] fix(nks): workio on save_as if Untitled didnt do anything --- pype/nukestudio/workio.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/pype/nukestudio/workio.py b/pype/nukestudio/workio.py index 1681d8a2ab..c7484b826b 100644 --- a/pype/nukestudio/workio.py +++ b/pype/nukestudio/workio.py @@ -22,19 +22,16 @@ def has_unsaved_changes(): def save_file(filepath): + file = os.path.basename(filepath) project = hiero.core.projects()[-1] - # close `Untitled` project - if "Untitled" not in project.name(): - log.info("Saving project: `{}`".format(project.name())) + if project: + log.info("Saving project: `{}` as '{}'".format(project.name(), file)) project.saveAs(filepath) - elif not project: + else: log.info("Creating new project...") project = hiero.core.newProject() project.saveAs(filepath) - else: - log.info("Dropping `Untitled` project...") - return def open_file(filepath): From 730fbdd5090d06c55a9890d73e62c91e30ab1453 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 6 Jan 2020 00:45:22 +0100 Subject: [PATCH 03/26] fix(global): reformat didn't return correct data --- pype/plugins/global/publish/extract_review.py | 46 ++++++++++++------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/pype/plugins/global/publish/extract_review.py b/pype/plugins/global/publish/extract_review.py index f621df0c66..0c39af64ed 100644 --- a/pype/plugins/global/publish/extract_review.py +++ b/pype/plugins/global/publish/extract_review.py @@ -1,5 +1,4 @@ import os -import math import pyblish.api import clique import pype.api @@ -25,14 +24,16 @@ class ExtractReview(pyblish.api.InstancePlugin): ext_filter = [] def process(self, instance): + to_width = 1920 + to_height = 1080 output_profiles = self.outputs or {} inst_data = instance.data fps = inst_data.get("fps") start_frame = inst_data.get("frameStart") - resolution_height = instance.data.get("resolutionHeight", 1080) - resolution_width = instance.data.get("resolutionWidth", 1920) + resolution_width = instance.data.get("resolutionWidth", to_width) + resolution_height = instance.data.get("resolutionHeight", to_height) pixel_aspect = instance.data.get("pixelAspect", 1) self.log.debug("Families In: `{}`".format(instance.data["families"])) @@ -172,22 +173,35 @@ class ExtractReview(pyblish.api.InstancePlugin): self.log.debug("__ pixel_aspect: `{}`".format(pixel_aspect)) self.log.debug("__ resolution_width: `{}`".format(resolution_width)) self.log.debug("__ resolution_height: `{}`".format(resolution_height)) + # scaling none square pixels and 1920 width if "reformat" in p_tags: - width_scale = 1920 - width_half_pad = 0 - res_w = int(float(resolution_width) * pixel_aspect) - height_half_pad = int(( - (res_w - 1920) / ( - res_w * .01) * ( - 1080 * .01)) / 2 - ) - height_scale = 1080 - (height_half_pad * 2) - if height_scale > 1080: + resolution_ratio = float(resolution_width / ( + resolution_height * pixel_aspect)) + delivery_ratio = float(to_width) / float(to_height) + self.log.debug(resolution_ratio) + self.log.debug(delivery_ratio) + + if resolution_ratio < delivery_ratio: + self.log.debug("lower then delivery") + scale_factor = to_height / ( + resolution_height * pixel_aspect) + self.log.debug(scale_factor) + width_scale = int(to_width * scale_factor) + width_half_pad = int(( + to_width - width_scale)/2) + height_scale = to_height height_half_pad = 0 - height_scale = 1080 - width_half_pad = (1920 - (float(resolution_width) * (1080 / float(resolution_height))) ) / 2 - width_scale = int(1920 - (width_half_pad * 2)) + else: + self.log.debug("heigher then delivery") + width_scale = to_width + width_half_pad = 0 + scale_factor = to_width / resolution_width + self.log.debug(scale_factor) + height_scale = int( + resolution_height * scale_factor) + height_half_pad = int( + (to_height - height_scale)/2) self.log.debug("__ width_scale: `{}`".format(width_scale)) self.log.debug("__ width_half_pad: `{}`".format(width_half_pad)) From 68c8a253bfd3f82c3d535b4c5810324b9c88fa16 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 6 Jan 2020 12:43:43 +0100 Subject: [PATCH 04/26] feat(nuke): lock range on setting frame ranges --- pype/nuke/lib.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pype/nuke/lib.py b/pype/nuke/lib.py index f213b596ad..12a083eca1 100644 --- a/pype/nuke/lib.py +++ b/pype/nuke/lib.py @@ -707,9 +707,11 @@ class WorkfileSettings(object): frame_start = int(data["frameStart"]) - handle_start frame_end = int(data["frameEnd"]) + handle_end + self._root_node["lock_range"].setValue(False) self._root_node["fps"].setValue(fps) self._root_node["first_frame"].setValue(frame_start) self._root_node["last_frame"].setValue(frame_end) + self._root_node["lock_range"].setValue(True) # setting active viewers try: From 9009e99712e339fb03476780517ff2a0b2e5d0ae Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Mon, 6 Jan 2020 14:07:11 +0100 Subject: [PATCH 05/26] fix(global): passing resolution to context --- pype/plugins/global/publish/collect_filesequences.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pype/plugins/global/publish/collect_filesequences.py b/pype/plugins/global/publish/collect_filesequences.py index d0ff5722a3..e658cd434c 100644 --- a/pype/plugins/global/publish/collect_filesequences.py +++ b/pype/plugins/global/publish/collect_filesequences.py @@ -150,6 +150,8 @@ class CollectRenderedFrames(pyblish.api.ContextPlugin): if instance: instance_family = instance.get("family") pixel_aspect = instance.get("pixelAspect", 1) + resolution_width = instance.get("resolutionWidth", 1920) + resolution_height = instance.get("resolutionHeight", 1080) lut_path = instance.get("lutPath", None) @@ -229,6 +231,8 @@ class CollectRenderedFrames(pyblish.api.ContextPlugin): "fps": fps, "source": data.get('source', ''), "pixelAspect": pixel_aspect, + "resolutionWidth": resolution_width, + "resolutionHeight": resolution_height }) if lut_path: instance.data.update({"lutPath": lut_path}) From a6af3ca90bb72c4bf430fa2d41f71590ab77ef04 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 7 Jan 2020 11:12:42 +0100 Subject: [PATCH 06/26] fix(global): reformat didnt compare properly resolution float and int --- pype/plugins/global/publish/extract_review.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/plugins/global/publish/extract_review.py b/pype/plugins/global/publish/extract_review.py index 0c39af64ed..deceaa93a5 100644 --- a/pype/plugins/global/publish/extract_review.py +++ b/pype/plugins/global/publish/extract_review.py @@ -196,7 +196,7 @@ class ExtractReview(pyblish.api.InstancePlugin): self.log.debug("heigher then delivery") width_scale = to_width width_half_pad = 0 - scale_factor = to_width / resolution_width + scale_factor = float(to_width) / float(resolution_width) self.log.debug(scale_factor) height_scale = int( resolution_height * scale_factor) From 26f2f882e2997f8e10f8098216edbe241b0cc144 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 7 Jan 2020 13:12:29 +0100 Subject: [PATCH 07/26] fix(otio): burnin right side didnt format properly --- pype/scripts/otio_burnin.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pype/scripts/otio_burnin.py b/pype/scripts/otio_burnin.py index 3e8cb3b0c4..89b74e258e 100644 --- a/pype/scripts/otio_burnin.py +++ b/pype/scripts/otio_burnin.py @@ -139,12 +139,13 @@ class ModifiedBurnins(ffmpeg_burnins.Burnins): options['frame_offset'] = start_frame expr = r'%%{eif\:n+%d\:d}' % options['frame_offset'] + _text = str(int(self.end_frame + options['frame_offset'])) if text and isinstance(text, str): text = r"{}".format(text) expr = text.replace("{current_frame}", expr) + text = text.replace("{current_frame}", _text) options['expression'] = expr - text = str(int(self.end_frame + options['frame_offset'])) self._add_burnin(text, align, options, ffmpeg_burnins.DRAWTEXT) def add_timecode(self, align, options=None, start_frame=None): From ade2a26e84b80c01fd3ea4b39bc216b483f786ab Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 8 Jan 2020 00:02:14 +0100 Subject: [PATCH 08/26] feat(nuke): adding back baking mov from nuke --- pype/nuke/lib.py | 275 ++++++++++++++---- .../global/publish/collect_filesequences.py | 2 + .../nuke/publish/extract_review_data_lut.py | 3 +- .../nuke/publish/extract_review_data_mov.py | 57 ++++ .../nuke/publish/extract_review_mov.py | 181 ------------ 5 files changed, 273 insertions(+), 245 deletions(-) create mode 100644 pype/plugins/nuke/publish/extract_review_data_mov.py delete mode 100644 pype/plugins/nuke/publish/extract_review_mov.py diff --git a/pype/nuke/lib.py b/pype/nuke/lib.py index 12a083eca1..9201e9c63e 100644 --- a/pype/nuke/lib.py +++ b/pype/nuke/lib.py @@ -1199,13 +1199,13 @@ class BuildWorkfile(WorkfileSettings): self.ypos -= (self.ypos_size * multiply) + self.ypos_gap -class Exporter_review_lut: +class Exporter_review: """ - Generator object for review lut from Nuke + Base class object for generating review data from Nuke Args: klass (pyblish.plugin): pyblish plugin parent - + instance (pyblish.context.instance): """ _temp_nodes = [] @@ -1213,6 +1213,101 @@ class Exporter_review_lut: "representations": list() }) + def __init__(self, + klass, + instance + ): + + self.log = klass.log + self.instance = instance + self.path_in = self.instance.data.get("path", None) + self.staging_dir = self.instance.data["stagingDir"] + self.collection = self.instance.data.get("collection", None) + + def get_file_info(self): + if self.collection: + self.log.debug("Collection: `{}`".format(self.collection)) + # get path + self.fname = os.path.basename(self.collection.format( + "{head}{padding}{tail}")) + self.fhead = self.collection.format("{head}") + + # get first and last frame + self.first_frame = min(self.collection.indexes) + self.last_frame = max(self.collection.indexes) + else: + self.fname = os.path.basename(self.path_in) + self.fhead = os.path.splitext(self.fname)[0] + "." + self.first_frame = self.instance.data.get("frameStart", None) + self.last_frame = self.instance.data.get("frameEnd", None) + + if "#" in self.fhead: + self.fhead = self.fhead.replace("#", "")[:-1] + + def get_representation_data(self, tags=None, range=False): + add_tags = [] + if tags: + add_tags = tags + + repre = { + 'name': self.name, + 'ext': self.ext, + 'files': self.file, + "stagingDir": self.staging_dir, + "anatomy_template": "publish", + "tags": [self.name.replace("_", "-")] + add_tags + } + + if range: + repre.update({ + "frameStart": self.first_frame, + "frameEnd": self.last_frame, + }) + + self.data["representations"].append(repre) + + def get_view_process_node(self): + """ + Will get any active view process. + + Arguments: + self (class): in object definition + + Returns: + nuke.Node: copy node of Input Process node + """ + anlib.reset_selection() + ipn_orig = None + for v in [n for n in nuke.allNodes() + if "Viewer" in n.Class()]: + ip = v['input_process'].getValue() + ipn = v['input_process_node'].getValue() + if "VIEWER_INPUT" not in ipn and ip: + ipn_orig = nuke.toNode(ipn) + ipn_orig.setSelected(True) + + if ipn_orig: + # copy selected to clipboard + nuke.nodeCopy('%clipboard%') + # reset selection + anlib.reset_selection() + # paste node and selection is on it only + nuke.nodePaste('%clipboard%') + # assign to variable + ipn = nuke.selectedNode() + + return ipn + + +class Exporter_review_lut(Exporter_review): + """ + Generator object for review lut from Nuke + + Args: + klass (pyblish.plugin): pyblish plugin parent + + + """ def __init__(self, klass, instance, @@ -1221,9 +1316,8 @@ class Exporter_review_lut: cube_size=None, lut_size=None, lut_style=None): - - self.log = klass.log - self.instance = instance + # initialize parent class + Exporter_review.__init__(self, klass, instance) self.name = name or "baked_lut" self.ext = ext or "cube" @@ -1231,16 +1325,13 @@ class Exporter_review_lut: self.lut_size = lut_size or 1024 self.lut_style = lut_style or "linear" - self.stagingDir = self.instance.data["stagingDir"] - self.collection = self.instance.data.get("collection", None) - # set frame start / end and file name to self self.get_file_info() self.log.info("File info was set...") self.file = self.fhead + self.name + ".{}".format(self.ext) - self.path = os.path.join(self.stagingDir, self.file).replace("\\", "/") + self.path = os.path.join(self.staging_dir, self.file).replace("\\", "/") def generate_lut(self): # ---------- start nodes creation @@ -1303,70 +1394,128 @@ class Exporter_review_lut: return self.data - def get_file_info(self): - if self.collection: - self.log.debug("Collection: `{}`".format(self.collection)) - # get path - self.fname = os.path.basename(self.collection.format( - "{head}{padding}{tail}")) - self.fhead = self.collection.format("{head}") - # get first and last frame - self.first_frame = min(self.collection.indexes) - self.last_frame = max(self.collection.indexes) +class Exporter_review_mov(Exporter_review): + """ + Metaclass for generating review mov files + + Args: + klass (pyblish.plugin): pyblish plugin parent + + + """ + def __init__(self, + klass, + instance, + name=None, + ext=None, + ): + # initialize parent class + Exporter_review.__init__(self, klass, instance) + + # passing presets for nodes to self + if hasattr(klass, "nodes"): + self.nodes = klass.nodes else: - self.fname = os.path.basename(self.instance.data.get("path", None)) - self.fhead = os.path.splitext(self.fname)[0] + "." - self.first_frame = self.instance.data.get("frameStart", None) - self.last_frame = self.instance.data.get("frameEnd", None) + self.nodes = {} - if "#" in self.fhead: - self.fhead = self.fhead.replace("#", "")[:-1] + self.name = name or "baked" + self.ext = ext or "mov" - def get_representation_data(self): + # set frame start / end and file name to self + self.get_file_info() - repre = { - 'name': self.name, - 'ext': self.ext, - 'files': self.file, - "stagingDir": self.stagingDir, - "anatomy_template": "publish", - "tags": [self.name.replace("_", "-")] - } + self.log.info("File info was set...") - self.data["representations"].append(repre) + self.file = self.fhead + self.name + ".{}".format(self.ext) + self.path = os.path.join(self.staging_dir, self.file).replace("\\", "/") - def get_view_process_node(self): - """ - Will get any active view process. + def generate_mov(self, farm=False): + # ---------- start nodes creation - Arguments: - self (class): in object definition + # Read node + r_node = nuke.createNode("Read") + r_node["file"].setValue(self.path_in) + r_node["first"].setValue(self.first_frame) + r_node["origfirst"].setValue(self.first_frame) + r_node["last"].setValue(self.last_frame) + r_node["origlast"].setValue(self.last_frame) + # connect + self._temp_nodes.append(r_node) + self.previous_node = r_node + self.log.debug("Read... `{}`".format(self._temp_nodes)) - Returns: - nuke.Node: copy node of Input Process node - """ - anlib.reset_selection() - ipn_orig = None - for v in [n for n in nuke.allNodes() - if "Viewer" in n.Class()]: - ip = v['input_process'].getValue() - ipn = v['input_process_node'].getValue() - if "VIEWER_INPUT" not in ipn and ip: - ipn_orig = nuke.toNode(ipn) - ipn_orig.setSelected(True) + # View Process node + ipn = self.get_view_process_node() + if ipn is not None: + # connect + ipn.setInput(0, self.previous_node) + self._temp_nodes.append(ipn) + self.previous_node = ipn + self.log.debug("ViewProcess... `{}`".format(self._temp_nodes)) - if ipn_orig: - # copy selected to clipboard - nuke.nodeCopy('%clipboard%') - # reset selection - anlib.reset_selection() - # paste node and selection is on it only - nuke.nodePaste('%clipboard%') - # assign to variable - ipn = nuke.selectedNode() + # reformat_node = nuke.createNode("Reformat") + # rn_preset = self.nodes.get("Reformat", None) + # if rn_preset: + # self.log.debug("Reformat preset") + # for k, v in rn_preset: + # self.log.debug("k, v: {0}:{1}".format(k, v)) + # if isinstance(v, unicode): + # v = str(v) + # reformat_node[k].setValue(v) + # # connect + # reformat_node.setInput(0, self.previous_node) + # self._temp_nodes.append(reformat_node) + # self.previous_node = reformat_node + # self.log.debug("Reformat... `{}`".format(self._temp_nodes)) + + # OCIODisplay node + dag_node = nuke.createNode("OCIODisplay") + # connect + dag_node.setInput(0, self.previous_node) + self._temp_nodes.append(dag_node) + self.previous_node = dag_node + self.log.debug("OCIODisplay... `{}`".format(self._temp_nodes)) + + # Write node + write_node = nuke.createNode("Write") + self.log.debug("Path: {}".format(self.path)) + self.instance.data["baked_colorspace_movie"] = self.path + write_node["file"].setValue(self.path) + write_node["file_type"].setValue(self.ext) + write_node["raw"].setValue(1) + # connect + write_node.setInput(0, self.previous_node) + self._temp_nodes.append(write_node) + self.log.debug("Write... `{}`".format(self._temp_nodes)) + + # ---------- end nodes creation + + if not farm: + self.log.info("Rendering... ") + # Render Write node + nuke.execute( + write_node.name(), + int(self.first_frame), + int(self.last_frame)) + + self.log.info("Rendered...") + + # ---------- generate representation data + self.get_representation_data( + tags=["review", "delete"], + range=True + ) + + self.log.debug("Representation... `{}`".format(self.data)) + + # ---------- Clean up + # for node in self._temp_nodes: + # nuke.delete(node) + # self.log.info("Deleted nodes...") + + return self.data - return ipn def get_dependent_nodes(nodes): """Get all dependent nodes connected to the list of nodes. diff --git a/pype/plugins/global/publish/collect_filesequences.py b/pype/plugins/global/publish/collect_filesequences.py index e658cd434c..6a59f5dffc 100644 --- a/pype/plugins/global/publish/collect_filesequences.py +++ b/pype/plugins/global/publish/collect_filesequences.py @@ -148,6 +148,8 @@ class CollectRenderedFrames(pyblish.api.ContextPlugin): os.environ.update(session) instance = metadata.get("instance") if instance: + # here is the place to add ability for nuke noninteractive + # ______________________________________ instance_family = instance.get("family") pixel_aspect = instance.get("pixelAspect", 1) resolution_width = instance.get("resolutionWidth", 1920) diff --git a/pype/plugins/nuke/publish/extract_review_data_lut.py b/pype/plugins/nuke/publish/extract_review_data_lut.py index dfc10952cd..f5fc3e59db 100644 --- a/pype/plugins/nuke/publish/extract_review_data_lut.py +++ b/pype/plugins/nuke/publish/extract_review_data_lut.py @@ -6,7 +6,7 @@ import pype reload(pnlib) -class ExtractReviewLutData(pype.api.Extractor): +class ExtractReviewDataLut(pype.api.Extractor): """Extracts movie and thumbnail with baked in luts must be run after extract_render_local.py @@ -37,6 +37,7 @@ class ExtractReviewLutData(pype.api.Extractor): self.log.info( "StagingDir `{0}`...".format(instance.data["stagingDir"])) + # generate data with anlib.maintained_selection(): exporter = pnlib.Exporter_review_lut( self, instance diff --git a/pype/plugins/nuke/publish/extract_review_data_mov.py b/pype/plugins/nuke/publish/extract_review_data_mov.py new file mode 100644 index 0000000000..585bd3f108 --- /dev/null +++ b/pype/plugins/nuke/publish/extract_review_data_mov.py @@ -0,0 +1,57 @@ +import os +import nuke +import pyblish.api +from avalon.nuke import lib as anlib +from pype.nuke import lib as pnlib +import pype +reload(pnlib) + + +class ExtractReviewDataMov(pype.api.Extractor): + """Extracts movie and thumbnail with baked in luts + + must be run after extract_render_local.py + + """ + + order = pyblish.api.ExtractorOrder + 0.01 + label = "Extract Review Data Mov" + + families = ["review"] + hosts = ["nuke"] + + def process(self, instance): + families = instance.data["families"] + self.log.info("Creating staging dir...") + if "representations" in instance.data: + staging_dir = instance.data[ + "representations"][0]["stagingDir"].replace("\\", "/") + instance.data["stagingDir"] = staging_dir + instance.data["representations"][0]["tags"] = [] + else: + instance.data["representations"] = [] + # get output path + render_path = instance.data['path'] + staging_dir = os.path.normpath(os.path.dirname(render_path)) + instance.data["stagingDir"] = staging_dir + + self.log.info( + "StagingDir `{0}`...".format(instance.data["stagingDir"])) + + # generate data + with anlib.maintained_selection(): + exporter = pnlib.Exporter_review_mov( + self, instance) + + if "render.farm" in families: + instance.data["families"].remove("review") + instance.data["families"].remove("ftrack") + data = exporter.generate_mov(farm=True) + else: + data = exporter.generate_mov() + + # assign to representations + instance.data["representations"] += data["representations"] + + self.log.debug( + "_ representations: {}".format(instance.data["representations"])) diff --git a/pype/plugins/nuke/publish/extract_review_mov.py b/pype/plugins/nuke/publish/extract_review_mov.py deleted file mode 100644 index ed3101951c..0000000000 --- a/pype/plugins/nuke/publish/extract_review_mov.py +++ /dev/null @@ -1,181 +0,0 @@ -import os -import nuke -import pyblish.api -import pype\ - -class ExtractReviewData(pype.api.Extractor): - """Extracts movie and thumbnail with baked in luts - - must be run after extract_render_local.py - - """ - - order = pyblish.api.ExtractorOrder + 0.01 - label = "Extract Review Data" - - families = ["review"] - hosts = ["nuke"] - - def process(self, instance): - - # Store selection - selection = [i for i in nuke.allNodes() if i["selected"].getValue()] - # Deselect all nodes to prevent external connections - [i["selected"].setValue(False) for i in nuke.allNodes()] - self.log.debug("creating staging dir:") - self.staging_dir(instance) - - self.log.debug("instance: {}".format(instance)) - self.log.debug("instance.data[families]: {}".format( - instance.data["families"])) - - self.render_review_representation(instance, representation="mov") - - # Restore selection - [i["selected"].setValue(False) for i in nuke.allNodes()] - [i["selected"].setValue(True) for i in selection] - - def render_review_representation(self, - instance, - representation="mov"): - - assert instance.data['representations'][0]['files'], "Instance data files should't be empty!" - - temporary_nodes = [] - stagingDir = instance.data[ - 'representations'][0]["stagingDir"].replace("\\", "/") - self.log.debug("StagingDir `{0}`...".format(stagingDir)) - - collection = instance.data.get("collection", None) - - if collection: - # get path - fname = os.path.basename(collection.format( - "{head}{padding}{tail}")) - fhead = collection.format("{head}") - - # get first and last frame - first_frame = min(collection.indexes) - last_frame = max(collection.indexes) - else: - fname = os.path.basename(instance.data.get("path", None)) - fhead = os.path.splitext(fname)[0] + "." - first_frame = instance.data.get("frameStart", None) - last_frame = instance.data.get("frameEnd", None) - - rnode = nuke.createNode("Read") - - rnode["file"].setValue( - os.path.join(stagingDir, fname).replace("\\", "/")) - - rnode["first"].setValue(first_frame) - rnode["origfirst"].setValue(first_frame) - rnode["last"].setValue(last_frame) - rnode["origlast"].setValue(last_frame) - temporary_nodes.append(rnode) - previous_node = rnode - - # get input process and connect it to baking - ipn = self.get_view_process_node() - if ipn is not None: - ipn.setInput(0, previous_node) - previous_node = ipn - temporary_nodes.append(ipn) - - reformat_node = nuke.createNode("Reformat") - - ref_node = self.nodes.get("Reformat", None) - if ref_node: - for k, v in ref_node: - self.log.debug("k,v: {0}:{1}".format(k,v)) - if isinstance(v, unicode): - v = str(v) - reformat_node[k].setValue(v) - - reformat_node.setInput(0, previous_node) - previous_node = reformat_node - temporary_nodes.append(reformat_node) - - dag_node = nuke.createNode("OCIODisplay") - dag_node.setInput(0, previous_node) - previous_node = dag_node - temporary_nodes.append(dag_node) - - # create write node - write_node = nuke.createNode("Write") - - if representation in "mov": - file = fhead + "baked.mov" - name = "baked" - path = os.path.join(stagingDir, file).replace("\\", "/") - self.log.debug("Path: {}".format(path)) - instance.data["baked_colorspace_movie"] = path - write_node["file"].setValue(path) - write_node["file_type"].setValue("mov") - write_node["raw"].setValue(1) - write_node.setInput(0, previous_node) - temporary_nodes.append(write_node) - tags = ["review", "delete"] - - elif representation in "jpeg": - file = fhead + "jpeg" - name = "thumbnail" - path = os.path.join(stagingDir, file).replace("\\", "/") - instance.data["thumbnail"] = path - write_node["file"].setValue(path) - write_node["file_type"].setValue("jpeg") - write_node["raw"].setValue(1) - write_node.setInput(0, previous_node) - temporary_nodes.append(write_node) - tags = ["thumbnail"] - - # retime for - first_frame = int(last_frame) / 2 - last_frame = int(last_frame) / 2 - - repre = { - 'name': name, - 'ext': representation, - 'files': file, - "stagingDir": stagingDir, - "frameStart": first_frame, - "frameEnd": last_frame, - "anatomy_template": "render", - "tags": tags - } - instance.data["representations"].append(repre) - - # Render frames - nuke.execute(write_node.name(), int(first_frame), int(last_frame)) - - self.log.debug("representations: {}".format(instance.data["representations"])) - - # Clean up - for node in temporary_nodes: - nuke.delete(node) - - def get_view_process_node(self): - - # Select only the target node - if nuke.selectedNodes(): - [n.setSelected(False) for n in nuke.selectedNodes()] - - ipn_orig = None - for v in [n for n in nuke.allNodes() - if "Viewer" in n.Class()]: - ip = v['input_process'].getValue() - ipn = v['input_process_node'].getValue() - if "VIEWER_INPUT" not in ipn and ip: - ipn_orig = nuke.toNode(ipn) - ipn_orig.setSelected(True) - - if ipn_orig: - nuke.nodeCopy('%clipboard%') - - [n.setSelected(False) for n in nuke.selectedNodes()] # Deselect all - - nuke.nodePaste('%clipboard%') - - ipn = nuke.selectedNode() - - return ipn From fbb4c247f60d2d6210e38287f8206c2729e72779 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 8 Jan 2020 00:38:08 +0100 Subject: [PATCH 09/26] fix(global): fixing reformat and letter box --- pype/nuke/lib.py | 23 ++--------- pype/plugins/global/publish/extract_review.py | 38 ++++++++++++------- 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/pype/nuke/lib.py b/pype/nuke/lib.py index 9201e9c63e..c468343545 100644 --- a/pype/nuke/lib.py +++ b/pype/nuke/lib.py @@ -1454,21 +1454,6 @@ class Exporter_review_mov(Exporter_review): self.previous_node = ipn self.log.debug("ViewProcess... `{}`".format(self._temp_nodes)) - # reformat_node = nuke.createNode("Reformat") - # rn_preset = self.nodes.get("Reformat", None) - # if rn_preset: - # self.log.debug("Reformat preset") - # for k, v in rn_preset: - # self.log.debug("k, v: {0}:{1}".format(k, v)) - # if isinstance(v, unicode): - # v = str(v) - # reformat_node[k].setValue(v) - # # connect - # reformat_node.setInput(0, self.previous_node) - # self._temp_nodes.append(reformat_node) - # self.previous_node = reformat_node - # self.log.debug("Reformat... `{}`".format(self._temp_nodes)) - # OCIODisplay node dag_node = nuke.createNode("OCIODisplay") # connect @@ -1509,10 +1494,10 @@ class Exporter_review_mov(Exporter_review): self.log.debug("Representation... `{}`".format(self.data)) - # ---------- Clean up - # for node in self._temp_nodes: - # nuke.delete(node) - # self.log.info("Deleted nodes...") + ---------- Clean up + for node in self._temp_nodes: + nuke.delete(node) + self.log.info("Deleted nodes...") return self.data diff --git a/pype/plugins/global/publish/extract_review.py b/pype/plugins/global/publish/extract_review.py index deceaa93a5..28eb0289fa 100644 --- a/pype/plugins/global/publish/extract_review.py +++ b/pype/plugins/global/publish/extract_review.py @@ -156,13 +156,34 @@ class ExtractReview(pyblish.api.InstancePlugin): # preset's output data output_args.extend(profile.get('output', [])) + # defining image ratios + resolution_ratio = float(resolution_width / ( + resolution_height * pixel_aspect)) + delivery_ratio = float(to_width) / float(to_height) + self.log.debug(resolution_ratio) + self.log.debug(delivery_ratio) + + # get scale factor + scale_factor = to_height / ( + resolution_height * pixel_aspect) + self.log.debug(scale_factor) + # letter_box lb = profile.get('letter_box', 0) - if lb is not 0: + if lb != 0: + ffmpet_width = to_width + ffmpet_height = to_height if "reformat" not in p_tags: lb /= pixel_aspect + if resolution_ratio != delivery_ratio: + ffmpet_width = resolution_width + ffmpet_height = int( + resolution_height * pixel_aspect) + else: + lb /= scale_factor + output_args.append( - "-filter:v scale=1920x1080:flags=lanczos,setsar=1,drawbox=0:0:iw:round((ih-(iw*(1/{0})))/2):t=fill:c=black,drawbox=0:ih-round((ih-(iw*(1/{0})))/2):iw:round((ih-(iw*(1/{0})))/2):t=fill:c=black".format(lb)) + "-filter:v scale={0}x{1}:flags=lanczos,setsar=1,drawbox=0:0:iw:round((ih-(iw*(1/{2})))/2):t=fill:c=black,drawbox=0:ih-round((ih-(iw*(1/{2})))/2):iw:round((ih-(iw*(1/{2})))/2):t=fill:c=black".format(ffmpet_width, ffmpet_height, lb)) # In case audio is longer than video. output_args.append("-shortest") @@ -176,17 +197,8 @@ class ExtractReview(pyblish.api.InstancePlugin): # scaling none square pixels and 1920 width if "reformat" in p_tags: - resolution_ratio = float(resolution_width / ( - resolution_height * pixel_aspect)) - delivery_ratio = float(to_width) / float(to_height) - self.log.debug(resolution_ratio) - self.log.debug(delivery_ratio) - if resolution_ratio < delivery_ratio: self.log.debug("lower then delivery") - scale_factor = to_height / ( - resolution_height * pixel_aspect) - self.log.debug(scale_factor) width_scale = int(to_width * scale_factor) width_half_pad = int(( to_width - width_scale)/2) @@ -209,8 +221,8 @@ class ExtractReview(pyblish.api.InstancePlugin): self.log.debug("__ height_half_pad: `{}`".format(height_half_pad)) - scaling_arg = "scale={0}x{1}:flags=lanczos,pad=1920:1080:{2}:{3}:black,setsar=1".format( - width_scale, height_scale, width_half_pad, height_half_pad + scaling_arg = "scale={0}x{1}:flags=lanczos,pad={2}:{3}:{4}:{5}:black,setsar=1".format( + width_scale, height_scale, to_width, to_height, width_half_pad, height_half_pad ) vf_back = self.add_video_filter_args( From 5bf0f2973dad63d690d2201443159879b5326f22 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 6 Jan 2020 15:48:19 +0100 Subject: [PATCH 10/26] add custom attributes key to assetversion data in integrate frant instances --- pype/plugins/ftrack/publish/integrate_ftrack_instances.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pype/plugins/ftrack/publish/integrate_ftrack_instances.py b/pype/plugins/ftrack/publish/integrate_ftrack_instances.py index 5e680a172a..5b8c195730 100644 --- a/pype/plugins/ftrack/publish/integrate_ftrack_instances.py +++ b/pype/plugins/ftrack/publish/integrate_ftrack_instances.py @@ -125,6 +125,12 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): "thumbnail": comp['thumbnail'] } + # Add custom attributes for AssetVersion + assetversion_cust_attrs = {} + component_item["assetversion_data"]["custom_attributes"] = ( + assetversion_cust_attrs + ) + componentList.append(component_item) # Create copy with ftrack.unmanaged location if thumb or prev if comp.get('thumbnail') or comp.get('preview') \ From 19f2b8148cd4ab2ced775491318ff1a2190bfd3f Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 6 Jan 2020 15:49:18 +0100 Subject: [PATCH 11/26] add intent value from context to custom attributes if is set --- pype/plugins/ftrack/publish/integrate_ftrack_instances.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pype/plugins/ftrack/publish/integrate_ftrack_instances.py b/pype/plugins/ftrack/publish/integrate_ftrack_instances.py index 5b8c195730..78583b0a2f 100644 --- a/pype/plugins/ftrack/publish/integrate_ftrack_instances.py +++ b/pype/plugins/ftrack/publish/integrate_ftrack_instances.py @@ -127,6 +127,10 @@ class IntegrateFtrackInstance(pyblish.api.InstancePlugin): # Add custom attributes for AssetVersion assetversion_cust_attrs = {} + intent_val = instance.context.data.get("intent") + if intent_val: + assetversion_cust_attrs["intent"] = intent_val + component_item["assetversion_data"]["custom_attributes"] = ( assetversion_cust_attrs ) From 264a7c177ba985d3d5b72a0c5cdd4628754426d9 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 6 Jan 2020 15:49:34 +0100 Subject: [PATCH 12/26] set asset version custom attributes if there are any --- .../ftrack/publish/integrate_ftrack_api.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/pype/plugins/ftrack/publish/integrate_ftrack_api.py b/pype/plugins/ftrack/publish/integrate_ftrack_api.py index 9fe4fddebf..337562c1f5 100644 --- a/pype/plugins/ftrack/publish/integrate_ftrack_api.py +++ b/pype/plugins/ftrack/publish/integrate_ftrack_api.py @@ -144,8 +144,11 @@ class IntegrateFtrackApi(pyblish.api.InstancePlugin): "version": 0, "asset": asset_entity, } - - assetversion_data.update(data.get("assetversion_data", {})) + _assetversion_data = data.get("assetversion_data", {}) + assetversion_cust_attrs = _assetversion_data.pop( + "custom_attributes", {} + ) + assetversion_data.update(_assetversion_data) assetversion_entity = session.query( self.query("AssetVersion", assetversion_data) @@ -182,6 +185,18 @@ class IntegrateFtrackApi(pyblish.api.InstancePlugin): existing_assetversion_metadata.update(assetversion_metadata) assetversion_entity["metadata"] = existing_assetversion_metadata + # Adding Custom Attributes + for attr, val in assetversion_cust_attrs.items(): + if attr in assetversion_entity["custom_attributes"]: + assetversion_entity["custom_attributes"][attr] = val + continue + + self.log.warning(( + "Custom Attrubute \"{0}\"" + " is not available for AssetVersion." + " Can't set it's value to: \"{1}\"" + ).format(attr, str(val))) + # Have to commit the version and asset, because location can't # determine the final location without. try: From 023aec0a61d6f239970cd848f0fb3cac19ab1a15 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 16 Dec 2019 17:35:23 +0100 Subject: [PATCH 13/26] added template data to burnins data --- pype/plugins/global/publish/extract_burnin.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pype/plugins/global/publish/extract_burnin.py b/pype/plugins/global/publish/extract_burnin.py index 95a7144081..33935b4272 100644 --- a/pype/plugins/global/publish/extract_burnin.py +++ b/pype/plugins/global/publish/extract_burnin.py @@ -32,6 +32,7 @@ class ExtractBurnin(pype.api.Extractor): frame_start = int(instance.data.get("frameStart") or 0) frame_end = int(instance.data.get("frameEnd") or 1) duration = frame_end - frame_start + 1 + prep_data = { "username": instance.context.data['user'], "asset": os.environ['AVALON_ASSET'], @@ -39,8 +40,14 @@ class ExtractBurnin(pype.api.Extractor): "frame_start": frame_start, "frame_end": frame_end, "duration": duration, - "version": version + "version": version, + "comment": instance.context.data.get("comment"), + "intent": instance.context.data.get("intent") } + # Update data with template data + template_data = instance.data.get("assumedTemplateData") or {} + prep_data.update(template_data) + self.log.debug("__ prep_data: {}".format(prep_data)) for i, repre in enumerate(instance.data["representations"]): self.log.debug("__ i: `{}`, repre: `{}`".format(i, repre)) From f89c1d3dbc28d2f533eb4828e889ece1f68a33f0 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 16 Dec 2019 17:36:10 +0100 Subject: [PATCH 14/26] added filled anatomy to burnin data to be able use `anatomy[...][...]` in burnin presets --- pype/plugins/global/publish/extract_burnin.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/pype/plugins/global/publish/extract_burnin.py b/pype/plugins/global/publish/extract_burnin.py index 33935b4272..06a62dd98b 100644 --- a/pype/plugins/global/publish/extract_burnin.py +++ b/pype/plugins/global/publish/extract_burnin.py @@ -1,5 +1,6 @@ import os import json +import copy import pype.api import pyblish @@ -48,6 +49,9 @@ class ExtractBurnin(pype.api.Extractor): template_data = instance.data.get("assumedTemplateData") or {} prep_data.update(template_data) + # get anatomy project + anatomy = instance.context.data['anatomy'] + self.log.debug("__ prep_data: {}".format(prep_data)) for i, repre in enumerate(instance.data["representations"]): self.log.debug("__ i: `{}`, repre: `{}`".format(i, repre)) @@ -69,11 +73,17 @@ class ExtractBurnin(pype.api.Extractor): ) self.log.debug("__ full_burnin_path: {}".format(full_burnin_path)) + # create copy of prep_data for anatomy formatting + _prep_data = copy.deepcopy(prep_data) + _prep_data["representation"] = repre["name"] + _prep_data["anatomy"] = ( + anatomy.format_all(_prep_data).get("solved") or {} + ) burnin_data = { "input": full_movie_path.replace("\\", "/"), "codec": repre.get("codec", []), "output": full_burnin_path.replace("\\", "/"), - "burnin_data": prep_data + "burnin_data": _prep_data } self.log.debug("__ burnin_data2: {}".format(burnin_data)) From dde70634e1d8789b17db595560143d03ddd459a3 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Mon, 16 Dec 2019 17:49:42 +0100 Subject: [PATCH 15/26] replace backslash in hierararchy which may cause issues in burnin path --- pype/plugins/global/publish/collect_templates.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/plugins/global/publish/collect_templates.py b/pype/plugins/global/publish/collect_templates.py index 9b0c03fdee..48623eec22 100644 --- a/pype/plugins/global/publish/collect_templates.py +++ b/pype/plugins/global/publish/collect_templates.py @@ -75,7 +75,7 @@ class CollectTemplates(pyblish.api.InstancePlugin): "asset": asset_name, "subset": subset_name, "version": version_number, - "hierarchy": hierarchy, + "hierarchy": hierarchy.replace("\\", "/"), "representation": "TEMP"} instance.data["template"] = template From ccd491d99e436c2d9ea91a4b58b0f9115ddb2f19 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Wed, 8 Jan 2020 18:24:35 +0100 Subject: [PATCH 16/26] add remapping from mounted to network path to render publish job --- pype/plugins/global/publish/submit_publish_job.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/pype/plugins/global/publish/submit_publish_job.py b/pype/plugins/global/publish/submit_publish_job.py index 2a254b015c..9c72ece73c 100644 --- a/pype/plugins/global/publish/submit_publish_job.py +++ b/pype/plugins/global/publish/submit_publish_job.py @@ -21,6 +21,12 @@ def _get_script(): if module_path.endswith(".pyc"): module_path = module_path[:-len(".pyc")] + ".py" + module_path = os.path.normpath(module_path) + mount_root = os.path.normpath(os.environ['PYPE_STUDIO_CORE_MOUNT']) + network_root = os.path.normpath(os.environ['PYPE_STUDIO_CORE_PATH']) + + module_path = module_path.replace(mount_root, network_root) + return module_path @@ -164,6 +170,12 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): output_dir = instance.data["outputDir"] metadata_path = os.path.join(output_dir, metadata_filename) + metadata_path = os.path.normpath(metadata_path) + mount_root = os.path.normpath(os.environ['PYPE_STUDIO_PROJECTS_MOUNT']) + network_root = os.path.normpath(os.environ['PYPE_STUDIO_PROJECTS_PATH']) + + metadata_path = metadata_path.replace(mount_root, network_root) + # Generate the payload for Deadline submission payload = { "JobInfo": { From e6dc7c29a3dde61a8d27c03a862ef2dfce7a71c7 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Wed, 8 Jan 2020 22:13:48 +0100 Subject: [PATCH 17/26] feat(): --- .../global/publish/collect_filesequences.py | 249 +++++++++++++----- .../global/publish/submit_publish_job.py | 13 + 2 files changed, 192 insertions(+), 70 deletions(-) diff --git a/pype/plugins/global/publish/collect_filesequences.py b/pype/plugins/global/publish/collect_filesequences.py index 6a59f5dffc..1214657856 100644 --- a/pype/plugins/global/publish/collect_filesequences.py +++ b/pype/plugins/global/publish/collect_filesequences.py @@ -54,10 +54,6 @@ def collect(root, patterns=[pattern], minimum_items=1) - # Ignore any remainders - if remainder: - print("Skipping remainder {}".format(remainder)) - # Exclude any frames outside start and end frame. for collection in collections: for index in list(collection.indexes): @@ -71,7 +67,7 @@ def collect(root, # Keep only collections that have at least a single frame collections = [c for c in collections if c.indexes] - return collections + return collections, remainder class CollectRenderedFrames(pyblish.api.ContextPlugin): @@ -119,8 +115,10 @@ class CollectRenderedFrames(pyblish.api.ContextPlugin): try: data = json.load(f) except Exception as exc: - self.log.error("Error loading json: " - "{} - Exception: {}".format(path, exc)) + self.log.error( + "Error loading json: " + "{} - Exception: {}".format(path, exc) + ) raise cwd = os.path.dirname(path) @@ -156,7 +154,6 @@ class CollectRenderedFrames(pyblish.api.ContextPlugin): resolution_height = instance.get("resolutionHeight", 1080) lut_path = instance.get("lutPath", None) - else: # Search in directory data = dict() @@ -167,14 +164,17 @@ class CollectRenderedFrames(pyblish.api.ContextPlugin): if regex: self.log.info("Using regex: {}".format(regex)) - collections = collect(root=root, - regex=regex, - exclude_regex=data.get("exclude_regex"), - frame_start=data.get("frameStart"), - frame_end=data.get("frameEnd")) + collections, remainder = collect( + root=root, + regex=regex, + exclude_regex=data.get("exclude_regex"), + frame_start=data.get("frameStart"), + frame_end=data.get("frameEnd"), + ) self.log.info("Found collections: {}".format(collections)) + """ if data.get("subset"): # If subset is provided for this json then it must be a single # collection. @@ -182,81 +182,190 @@ class CollectRenderedFrames(pyblish.api.ContextPlugin): self.log.error("Forced subset can only work with a single " "found sequence") raise RuntimeError("Invalid sequence") + """ fps = data.get("fps", 25) + if data.get("user"): + context.data["user"] = data["user"] + # Get family from the data families = data.get("families", ["render"]) if "render" not in families: families.append("render") if "ftrack" not in families: families.append("ftrack") - if "review" not in families: - families.append("review") if "write" in instance_family: families.append("write") - for collection in collections: - instance = context.create_instance(str(collection)) - self.log.info("Collection: %s" % list(collection)) + if data.get("attachTo"): + # we need to attach found collections to existing + # subset version as review represenation. - # Ensure each instance gets a unique reference to the data + for attach in data.get("attachTo"): + self.log.info( + "Attaching render {}:v{}".format( + attach["subset"], attach["version"])) + instance = context.create_instance( + attach["subset"]) + instance.data.update( + { + "name": attach["subset"], + "version": attach["version"], + "family": 'review', + "families": ['review', 'ftrack'], + "asset": data.get( + "asset", api.Session["AVALON_ASSET"]), + "stagingDir": root, + "frameStart": data.get("frameStart"), + "frameEnd": data.get("frameEnd"), + "fps": fps, + "source": data.get("source", ""), + "pixelAspect": pixel_aspect + }) + + if "representations" not in instance.data: + instance.data["representations"] = [] + + for collection in collections: + self.log.info( + " - adding representation: {}".format( + str(collection)) + ) + ext = collection.tail.lstrip(".") + + representation = { + "name": ext, + "ext": "{}".format(ext), + "files": list(collection), + "stagingDir": root, + "anatomy_template": "render", + "fps": fps, + "tags": ["review"], + } + instance.data["representations"].append( + representation) + + elif data.get("subset"): + # if we have subset - add all collections and known + # reminder as representations + + self.log.info( + "Adding representations to subset {}".format( + data.get("subset"))) + + instance = context.create_instance(data.get("subset")) data = copy.deepcopy(data) - # If no subset provided, get it from collection's head - subset = data.get("subset", collection.head.rstrip("_. ")) - - # If no start or end frame provided, get it from collection - indices = list(collection.indexes) - start = data.get("frameStart", indices[0]) - end = data.get("frameEnd", indices[-1]) - - self.log.debug("Collected pixel_aspect:\n" - "{}".format(pixel_aspect)) - self.log.debug("type pixel_aspect:\n" - "{}".format(type(pixel_aspect))) - - # root = os.path.normpath(root) - # self.log.info("Source: {}}".format(data.get("source", ""))) - - ext = list(collection)[0].split('.')[-1] - - instance.data.update({ - "name": str(collection), - "family": families[0], # backwards compatibility / pyblish - "families": list(families), - "subset": subset, - "asset": data.get("asset", api.Session["AVALON_ASSET"]), - "stagingDir": root, - "frameStart": start, - "frameEnd": end, - "fps": fps, - "source": data.get('source', ''), - "pixelAspect": pixel_aspect, - "resolutionWidth": resolution_width, - "resolutionHeight": resolution_height - }) - if lut_path: - instance.data.update({"lutPath": lut_path}) - instance.append(collection) - instance.context.data['fps'] = fps + instance.data.update( + { + "name": data.get("subset"), + "family": families[0], + "families": list(families), + "subset": data.get("subset"), + "asset": data.get( + "asset", api.Session["AVALON_ASSET"]), + "stagingDir": root, + "frameStart": data.get("frameStart"), + "frameEnd": data.get("frameEnd"), + "fps": fps, + "source": data.get("source", ""), + "pixelAspect": pixel_aspect, + } + ) if "representations" not in instance.data: instance.data["representations"] = [] - representation = { - 'name': ext, - 'ext': '{}'.format(ext), - 'files': list(collection), - "stagingDir": root, - "anatomy_template": "render", - "fps": fps, - "tags": ['review'] - } - instance.data["representations"].append(representation) + for collection in collections: + self.log.info(" - {}".format(str(collection))) - if data.get('user'): - context.data["user"] = data['user'] + ext = collection.tail.lstrip(".") - self.log.debug("Collected instance:\n" - "{}".format(pformat(instance.data))) + representation = { + "name": ext, + "ext": "{}".format(ext), + "files": list(collection), + "stagingDir": root, + "anatomy_template": "render", + "fps": fps, + "tags": ["review"], + } + instance.data["representations"].append( + representation) + + # process reminders + for rem in remainder: + # add only known types to representation + if rem.split(".")[-1] in ['mov', 'jpg', 'mp4']: + self.log.info(" . {}".format(rem)) + representation = { + "name": rem.split(".")[-1], + "ext": "{}".format(rem.split(".")[-1]), + "files": rem, + "stagingDir": root, + "anatomy_template": "render", + "fps": fps, + "tags": ["review"], + } + instance.data["representations"].append( + representation) + + else: + # we have no subset so we take every collection and create one + # from it + for collection in collections: + instance = context.create_instance(str(collection)) + self.log.info("Creating subset from: %s" % str(collection)) + + # Ensure each instance gets a unique reference to the data + data = copy.deepcopy(data) + + # If no subset provided, get it from collection's head + subset = data.get("subset", collection.head.rstrip("_. ")) + + # If no start or end frame provided, get it from collection + indices = list(collection.indexes) + start = data.get("frameStart", indices[0]) + end = data.get("frameEnd", indices[-1]) + + ext = list(collection)[0].split(".")[-1] + + if "review" not in families: + families.append("review") + + instance.data.update( + { + "name": str(collection), + "family": families[0], # backwards compatibility + "families": list(families), + "subset": subset, + "asset": data.get( + "asset", api.Session["AVALON_ASSET"]), + "stagingDir": root, + "frameStart": start, + "frameEnd": end, + "fps": fps, + "source": data.get("source", ""), + "pixelAspect": pixel_aspect, + } + ) + if lut_path: + instance.data.update({"lutPath": lut_path}) + + instance.append(collection) + instance.context.data["fps"] = fps + + if "representations" not in instance.data: + instance.data["representations"] = [] + + representation = { + "name": ext, + "ext": "{}".format(ext), + "files": list(collection), + "stagingDir": root, + "anatomy_template": "render", + "fps": fps, + "tags": ["review"], + } + instance.data["representations"].append(representation) diff --git a/pype/plugins/global/publish/submit_publish_job.py b/pype/plugins/global/publish/submit_publish_job.py index 2a254b015c..e7d5fe3147 100644 --- a/pype/plugins/global/publish/submit_publish_job.py +++ b/pype/plugins/global/publish/submit_publish_job.py @@ -282,6 +282,19 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin): relative_path = os.path.relpath(source, api.registered_root()) source = os.path.join("{root}", relative_path).replace("\\", "/") + # find subsets and version to attach render to + attach_to = instance.data.get("attachTo") + attach_subset_versions = [] + if attach_to: + for subset in attach_to: + for instance in context: + if instance.data["subset"] != subset["subset"]: + continue + attach_subset_versions.append( + {"version": instance.data["version"], + "subset": subset["subset"], + "family": subset["family"]}) + # Write metadata for publish job metadata = { "asset": asset, From b2dfb6c95b77bf327291eccc6b50e9937e4c71a7 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Thu, 9 Jan 2020 10:36:35 +0100 Subject: [PATCH 18/26] be specific about task custom attributes to avoid asset version's cust attrs --- pype/ftrack/events/event_sync_to_avalon.py | 11 +++++++---- pype/ftrack/lib/avalon_sync.py | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/pype/ftrack/events/event_sync_to_avalon.py b/pype/ftrack/events/event_sync_to_avalon.py index 606866aba2..91355c6068 100644 --- a/pype/ftrack/events/event_sync_to_avalon.py +++ b/pype/ftrack/events/event_sync_to_avalon.py @@ -1438,9 +1438,11 @@ class SyncToAvalonEvent(BaseEvent): if attr["entity_type"] != ent_info["entityType"]: continue - if ent_info["entityType"] != "show": - if attr["object_type_id"] != ent_info["objectTypeId"]: - continue + if ( + ent_info["entityType"] == "task" and + attr["object_type_id"] != ent_info["objectTypeId"] + ): + continue configuration_id = attr["id"] entity_type_conf_ids[entity_type] = configuration_id @@ -1712,7 +1714,8 @@ class SyncToAvalonEvent(BaseEvent): if ca_ent_type == "show": cust_attrs_by_obj_id[ca_ent_type][key] = cust_attr - else: + + elif ca_ent_type == "task": obj_id = cust_attr["object_type_id"] cust_attrs_by_obj_id[obj_id][key] = cust_attr diff --git a/pype/ftrack/lib/avalon_sync.py b/pype/ftrack/lib/avalon_sync.py index 064ea1adb8..5839d36e64 100644 --- a/pype/ftrack/lib/avalon_sync.py +++ b/pype/ftrack/lib/avalon_sync.py @@ -699,7 +699,7 @@ class SyncEntitiesFactory: if ca_ent_type == "show": avalon_attrs[ca_ent_type][key] = cust_attr["default"] avalon_attrs_ca_id[ca_ent_type][key] = cust_attr["id"] - else: + elif ca_ent_type == "task": obj_id = cust_attr["object_type_id"] avalon_attrs[obj_id][key] = cust_attr["default"] avalon_attrs_ca_id[obj_id][key] = cust_attr["id"] @@ -708,7 +708,7 @@ class SyncEntitiesFactory: if ca_ent_type == "show": attrs_per_entity_type[ca_ent_type][key] = cust_attr["default"] attrs_per_entity_type_ca_id[ca_ent_type][key] = cust_attr["id"] - else: + elif ca_ent_type == "task": obj_id = cust_attr["object_type_id"] attrs_per_entity_type[obj_id][key] = cust_attr["default"] attrs_per_entity_type_ca_id[obj_id][key] = cust_attr["id"] From 64a0360ce90a699d86c4ee166c36268f9857dae8 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 9 Jan 2020 11:08:35 +0100 Subject: [PATCH 19/26] fix(global): letter box not created properly --- pype/plugins/global/publish/extract_review.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pype/plugins/global/publish/extract_review.py b/pype/plugins/global/publish/extract_review.py index 28eb0289fa..4eb7fa16ed 100644 --- a/pype/plugins/global/publish/extract_review.py +++ b/pype/plugins/global/publish/extract_review.py @@ -180,7 +180,11 @@ class ExtractReview(pyblish.api.InstancePlugin): ffmpet_height = int( resolution_height * pixel_aspect) else: - lb /= scale_factor + # TODO: it might still be failing in some cases + if resolution_ratio != delivery_ratio: + lb /= scale_factor + else: + lb /= pixel_aspect output_args.append( "-filter:v scale={0}x{1}:flags=lanczos,setsar=1,drawbox=0:0:iw:round((ih-(iw*(1/{2})))/2):t=fill:c=black,drawbox=0:ih-round((ih-(iw*(1/{2})))/2):iw:round((ih-(iw*(1/{2})))/2):t=fill:c=black".format(ffmpet_width, ffmpet_height, lb)) From 69015fb7fc08970c8a9619466556eb02f8a76ab7 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 9 Jan 2020 11:15:57 +0100 Subject: [PATCH 20/26] fix(nuke): updating nuke.lib and review data mov --- pype/nuke/lib.py | 121 ++++++++++++------ .../nuke/publish/extract_review_data_mov.py | 1 - 2 files changed, 81 insertions(+), 41 deletions(-) diff --git a/pype/nuke/lib.py b/pype/nuke/lib.py index c468343545..9ded8b75d0 100644 --- a/pype/nuke/lib.py +++ b/pype/nuke/lib.py @@ -1205,7 +1205,7 @@ class Exporter_review: Args: klass (pyblish.plugin): pyblish plugin parent - instance (pyblish.context.instance): + instance (pyblish.instance): instance of pyblish context """ _temp_nodes = [] @@ -1298,6 +1298,11 @@ class Exporter_review: return ipn + def clean_nodes(self): + for node in self._temp_nodes: + nuke.delete(node) + self.log.info("Deleted nodes...") + class Exporter_review_lut(Exporter_review): """ @@ -1305,6 +1310,7 @@ class Exporter_review_lut(Exporter_review): Args: klass (pyblish.plugin): pyblish plugin parent + instance (pyblish.instance): instance of pyblish context """ @@ -1319,6 +1325,12 @@ class Exporter_review_lut(Exporter_review): # initialize parent class Exporter_review.__init__(self, klass, instance) + # deal with now lut defined in viewer lut + if hasattr(klass, "viewer_lut_raw"): + self.viewer_lut_raw = klass.viewer_lut_raw + else: + self.viewer_lut_raw = False + self.name = name or "baked_lut" self.ext = ext or "cube" self.cube_size = cube_size or 32 @@ -1331,7 +1343,8 @@ class Exporter_review_lut(Exporter_review): self.log.info("File info was set...") self.file = self.fhead + self.name + ".{}".format(self.ext) - self.path = os.path.join(self.staging_dir, self.file).replace("\\", "/") + self.path = os.path.join( + self.staging_dir, self.file).replace("\\", "/") def generate_lut(self): # ---------- start nodes creation @@ -1353,13 +1366,14 @@ class Exporter_review_lut(Exporter_review): self.previous_node = ipn self.log.debug("ViewProcess... `{}`".format(self._temp_nodes)) - # OCIODisplay - dag_node = nuke.createNode("OCIODisplay") - # connect - dag_node.setInput(0, self.previous_node) - self._temp_nodes.append(dag_node) - self.previous_node = dag_node - self.log.debug("OCIODisplay... `{}`".format(self._temp_nodes)) + if not self.viewer_lut_raw: + # OCIODisplay + dag_node = nuke.createNode("OCIODisplay") + # connect + dag_node.setInput(0, self.previous_node) + self._temp_nodes.append(dag_node) + self.previous_node = dag_node + self.log.debug("OCIODisplay... `{}`".format(self._temp_nodes)) # GenerateLUT gen_lut_node = nuke.createNode("GenerateLUT") @@ -1388,9 +1402,7 @@ class Exporter_review_lut(Exporter_review): self.log.debug("Representation... `{}`".format(self.data)) # ---------- Clean up - for node in self._temp_nodes: - nuke.delete(node) - self.log.info("Deleted nodes...") + self.clean_nodes() return self.data @@ -1401,7 +1413,7 @@ class Exporter_review_mov(Exporter_review): Args: klass (pyblish.plugin): pyblish plugin parent - + instance (pyblish.instance): instance of pyblish context """ def __init__(self, @@ -1419,6 +1431,12 @@ class Exporter_review_mov(Exporter_review): else: self.nodes = {} + # deal with now lut defined in viewer lut + if hasattr(klass, "viewer_lut_raw"): + self.viewer_lut_raw = klass.viewer_lut_raw + else: + self.viewer_lut_raw = False + self.name = name or "baked" self.ext = ext or "mov" @@ -1428,7 +1446,31 @@ class Exporter_review_mov(Exporter_review): self.log.info("File info was set...") self.file = self.fhead + self.name + ".{}".format(self.ext) - self.path = os.path.join(self.staging_dir, self.file).replace("\\", "/") + self.path = os.path.join( + self.staging_dir, self.file).replace("\\", "/") + + def render(self, render_node_name): + self.log.info("Rendering... ") + # Render Write node + nuke.execute( + render_node_name, + int(self.first_frame), + int(self.last_frame)) + + self.log.info("Rendered...") + + def save_file(self): + with anlib.maintained_selection(): + self.log.info("Saving nodes as file... ") + # select temp nodes + anlib.select_nodes(self._temp_nodes) + # create nk path + path = os.path.splitext(self.path)[0] + ".nk" + # save file to the path + nuke.nodeCopy(path) + + self.log.info("Nodes exported...") + return path def generate_mov(self, farm=False): # ---------- start nodes creation @@ -1454,13 +1496,14 @@ class Exporter_review_mov(Exporter_review): self.previous_node = ipn self.log.debug("ViewProcess... `{}`".format(self._temp_nodes)) - # OCIODisplay node - dag_node = nuke.createNode("OCIODisplay") - # connect - dag_node.setInput(0, self.previous_node) - self._temp_nodes.append(dag_node) - self.previous_node = dag_node - self.log.debug("OCIODisplay... `{}`".format(self._temp_nodes)) + if not self.viewer_lut_raw: + # OCIODisplay node + dag_node = nuke.createNode("OCIODisplay") + # connect + dag_node.setInput(0, self.previous_node) + self._temp_nodes.append(dag_node) + self.previous_node = dag_node + self.log.debug("OCIODisplay... `{}`".format(self._temp_nodes)) # Write node write_node = nuke.createNode("Write") @@ -1476,28 +1519,26 @@ class Exporter_review_mov(Exporter_review): # ---------- end nodes creation - if not farm: - self.log.info("Rendering... ") - # Render Write node - nuke.execute( - write_node.name(), - int(self.first_frame), - int(self.last_frame)) - - self.log.info("Rendered...") - - # ---------- generate representation data - self.get_representation_data( - tags=["review", "delete"], - range=True - ) + # ---------- render or save to nk + if farm: + path_nk = self.save_file() + self.data.update({ + "bakeScriptPath": path_nk, + "bakeWriteNodeName": write_node.name(), + "bakeRenderPath": self.path + }) + else: + self.render(write_node.name()) + # ---------- generate representation data + self.get_representation_data( + tags=["review", "delete"], + range=True + ) self.log.debug("Representation... `{}`".format(self.data)) - ---------- Clean up - for node in self._temp_nodes: - nuke.delete(node) - self.log.info("Deleted nodes...") + #---------- Clean up + self.clean_nodes() return self.data diff --git a/pype/plugins/nuke/publish/extract_review_data_mov.py b/pype/plugins/nuke/publish/extract_review_data_mov.py index 585bd3f108..2208f8fa31 100644 --- a/pype/plugins/nuke/publish/extract_review_data_mov.py +++ b/pype/plugins/nuke/publish/extract_review_data_mov.py @@ -1,5 +1,4 @@ import os -import nuke import pyblish.api from avalon.nuke import lib as anlib from pype.nuke import lib as pnlib From 235079038965f1f3e038b60487e07447ed0bf039 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 9 Jan 2020 12:02:04 +0100 Subject: [PATCH 21/26] remove obsolete logge --- pype/plugins/nuke/create/create_read.py | 3 --- pype/plugins/nuke/create/create_write.py | 4 ---- 2 files changed, 7 deletions(-) diff --git a/pype/plugins/nuke/create/create_read.py b/pype/plugins/nuke/create/create_read.py index 87bb45a6ad..1aa7e68746 100644 --- a/pype/plugins/nuke/create/create_read.py +++ b/pype/plugins/nuke/create/create_read.py @@ -6,9 +6,6 @@ from pype import api as pype import nuke -log = pype.Logger().get_logger(__name__, "nuke") - - class CrateRead(avalon.nuke.Creator): # change this to template preset name = "ReadCopy" diff --git a/pype/plugins/nuke/create/create_write.py b/pype/plugins/nuke/create/create_write.py index 042826d4d9..f522c50511 100644 --- a/pype/plugins/nuke/create/create_write.py +++ b/pype/plugins/nuke/create/create_write.py @@ -7,10 +7,6 @@ from pypeapp import config import nuke - -log = pype.Logger().get_logger(__name__, "nuke") - - class CreateWriteRender(plugin.PypeCreator): # change this to template preset name = "WriteRender" From 3a4a6782abdf74e9278c029c0291abd889b1aa74 Mon Sep 17 00:00:00 2001 From: Milan Kolar Date: Thu, 9 Jan 2020 15:07:44 +0100 Subject: [PATCH 22/26] pep8 class names --- pype/nuke/lib.py | 10 +++++----- pype/plugins/nuke/publish/extract_review_data_lut.py | 2 +- pype/plugins/nuke/publish/extract_review_data_mov.py | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/pype/nuke/lib.py b/pype/nuke/lib.py index 9ded8b75d0..4faea1da36 100644 --- a/pype/nuke/lib.py +++ b/pype/nuke/lib.py @@ -1199,7 +1199,7 @@ class BuildWorkfile(WorkfileSettings): self.ypos -= (self.ypos_size * multiply) + self.ypos_gap -class Exporter_review: +class ExporterReview: """ Base class object for generating review data from Nuke @@ -1304,7 +1304,7 @@ class Exporter_review: self.log.info("Deleted nodes...") -class Exporter_review_lut(Exporter_review): +class ExporterReviewLut(ExporterReview): """ Generator object for review lut from Nuke @@ -1323,7 +1323,7 @@ class Exporter_review_lut(Exporter_review): lut_size=None, lut_style=None): # initialize parent class - Exporter_review.__init__(self, klass, instance) + ExporterReview.__init__(self, klass, instance) # deal with now lut defined in viewer lut if hasattr(klass, "viewer_lut_raw"): @@ -1407,7 +1407,7 @@ class Exporter_review_lut(Exporter_review): return self.data -class Exporter_review_mov(Exporter_review): +class ExporterReviewMov(ExporterReview): """ Metaclass for generating review mov files @@ -1423,7 +1423,7 @@ class Exporter_review_mov(Exporter_review): ext=None, ): # initialize parent class - Exporter_review.__init__(self, klass, instance) + ExporterReview.__init__(self, klass, instance) # passing presets for nodes to self if hasattr(klass, "nodes"): diff --git a/pype/plugins/nuke/publish/extract_review_data_lut.py b/pype/plugins/nuke/publish/extract_review_data_lut.py index f5fc3e59db..4373309363 100644 --- a/pype/plugins/nuke/publish/extract_review_data_lut.py +++ b/pype/plugins/nuke/publish/extract_review_data_lut.py @@ -39,7 +39,7 @@ class ExtractReviewDataLut(pype.api.Extractor): # generate data with anlib.maintained_selection(): - exporter = pnlib.Exporter_review_lut( + exporter = pnlib.ExporterReviewLut( self, instance ) data = exporter.generate_lut() diff --git a/pype/plugins/nuke/publish/extract_review_data_mov.py b/pype/plugins/nuke/publish/extract_review_data_mov.py index 2208f8fa31..333774bcd7 100644 --- a/pype/plugins/nuke/publish/extract_review_data_mov.py +++ b/pype/plugins/nuke/publish/extract_review_data_mov.py @@ -39,7 +39,7 @@ class ExtractReviewDataMov(pype.api.Extractor): # generate data with anlib.maintained_selection(): - exporter = pnlib.Exporter_review_mov( + exporter = pnlib.ExporterReviewMov( self, instance) if "render.farm" in families: From ce64e6fa0706f5db01ce147f510b34074d6936fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Samohel?= Date: Fri, 10 Jan 2020 00:30:20 +0000 Subject: [PATCH 23/26] fixing environment filtering --- pype/lib.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pype/lib.py b/pype/lib.py index 8772608b38..b19491adeb 100644 --- a/pype/lib.py +++ b/pype/lib.py @@ -18,13 +18,16 @@ def _subprocess(*args, **kwargs): """Convenience method for getting output errors for subprocess.""" # make sure environment contains only strings - filtered_env = {k: str(v) for k, v in os.environ.items()} + if not kwargs.get("env"): + filtered_env = {k: str(v) for k, v in os.environ.items()} + else: + filtered_env = {k: str(v) for k, v in kwargs.get("env").items()} # set overrides kwargs['stdout'] = kwargs.get('stdout', subprocess.PIPE) kwargs['stderr'] = kwargs.get('stderr', subprocess.STDOUT) kwargs['stdin'] = kwargs.get('stdin', subprocess.PIPE) - kwargs['env'] = kwargs.get('env',filtered_env) + kwargs['env'] = filtered_env proc = subprocess.Popen(*args, **kwargs) From 9bc2f557a39efb7aa1ebefbdb7025ff87b8c7515 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 10 Jan 2020 11:40:29 +0100 Subject: [PATCH 24/26] added new entityType `appointment` to ignored entity types --- pype/ftrack/events/event_sync_to_avalon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pype/ftrack/events/event_sync_to_avalon.py b/pype/ftrack/events/event_sync_to_avalon.py index 91355c6068..8d75d932f8 100644 --- a/pype/ftrack/events/event_sync_to_avalon.py +++ b/pype/ftrack/events/event_sync_to_avalon.py @@ -28,7 +28,7 @@ class SyncToAvalonEvent(BaseEvent): ignore_entTypes = [ "socialfeed", "socialnotification", "note", "assetversion", "job", "user", "reviewsessionobject", "timer", - "timelog", "auth_userrole" + "timelog", "auth_userrole", "appointment" ] ignore_ent_types = ["Milestone"] ignore_keys = ["statusid"] From 4bb66af2016951942f4cdc2c0ecd004c82681df2 Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 10 Jan 2020 11:40:53 +0100 Subject: [PATCH 25/26] added debug with project name to sync to avalon action --- pype/ftrack/lib/avalon_sync.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pype/ftrack/lib/avalon_sync.py b/pype/ftrack/lib/avalon_sync.py index 5839d36e64..8cebd12a59 100644 --- a/pype/ftrack/lib/avalon_sync.py +++ b/pype/ftrack/lib/avalon_sync.py @@ -314,6 +314,9 @@ class SyncEntitiesFactory: self.log.warning(msg) return {"success": False, "message": msg} + self.log.debug(( + "*** Synchronization initialization started <{}>." + ).format(project_full_name)) # Check if `avalon_mongo_id` custom attribute exist or is accessible if CustAttrIdKey not in ft_project["custom_attributes"]: items = [] From 77d71d4bf356f40ce2a06cf27899529e8df2613c Mon Sep 17 00:00:00 2001 From: iLLiCiTiT Date: Fri, 10 Jan 2020 11:43:07 +0100 Subject: [PATCH 26/26] it is tried to set intent value on ftrack entity and do not crash pyblish in integrate_ftrack_api --- .../plugins/ftrack/publish/integrate_ftrack_api.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/pype/plugins/ftrack/publish/integrate_ftrack_api.py b/pype/plugins/ftrack/publish/integrate_ftrack_api.py index 337562c1f5..c51685f84d 100644 --- a/pype/plugins/ftrack/publish/integrate_ftrack_api.py +++ b/pype/plugins/ftrack/publish/integrate_ftrack_api.py @@ -188,14 +188,18 @@ class IntegrateFtrackApi(pyblish.api.InstancePlugin): # Adding Custom Attributes for attr, val in assetversion_cust_attrs.items(): if attr in assetversion_entity["custom_attributes"]: - assetversion_entity["custom_attributes"][attr] = val - continue + try: + assetversion_entity["custom_attributes"][attr] = val + session.commit() + continue + except Exception: + session.rollback() self.log.warning(( "Custom Attrubute \"{0}\"" - " is not available for AssetVersion." - " Can't set it's value to: \"{1}\"" - ).format(attr, str(val))) + " is not available for AssetVersion <{1}>." + " Can't set it's value to: \"{2}\"" + ).format(attr, assetversion_entity["id"], str(val))) # Have to commit the version and asset, because location can't # determine the final location without.