diff --git a/pype/nuke/lib.py b/pype/nuke/lib.py index 38253a5f3f..515475276c 100644 --- a/pype/nuke/lib.py +++ b/pype/nuke/lib.py @@ -18,6 +18,7 @@ log = Logger().get_logger(__name__, "nuke") self = sys.modules[__name__] self._project = None + def onScriptLoad(): if nuke.env['LINUX']: nuke.tcl('load ffmpegReader') @@ -43,7 +44,7 @@ def checkInventoryVersions(): container = avalon.nuke.parse_container(each) if container: - node = container["_tool"] + node = container["_node"] avalon_knob_data = get_avalon_knob_data(node) # get representation from io @@ -102,6 +103,9 @@ def writes_version_sync(): node_new_file = node_file.replace(node_version, new_version) each['file'].setValue(node_new_file) + if not os.path.isdir(os.path.dirname(node_new_file)): + log.info("path does not exist") + os.makedirs(os.path.dirname(node_new_file), 0o766) except Exception as e: log.debug( "Write node: `{}` has no version in path: {}".format(each.name(), e)) @@ -172,7 +176,32 @@ def script_name(): return nuke.root().knob('name').value() -def create_write_node(name, data): +def create_write_node(name, data, prenodes=None): + '''Creating write node which is group node + + Arguments: + name (str): name of node + data (dict): data to be imprinted + prenodes (list, optional): list of lists, definitions for nodes + to be created before write + + Example: + prenodes = [( + "NameNode", # string + "NodeClass", # string + ( # OrderDict: knob and values pairs + ("knobName", "knobValue"), + ("knobName", "knobValue") + ), + ( # list inputs + "firstPrevNodeName", + "secondPrevNodeName" + ) + ) + ] + + ''' + nuke_dataflow_writes = get_node_dataflow_preset(**data) nuke_colorspace_writes = get_node_colorspace_preset(**data) application = lib.get_application(os.environ["AVALON_APP_NAME"]) @@ -191,16 +220,8 @@ def create_write_node(name, data): # build file path to workfiles fpath = str(anatomy_filled["work"]["folder"]).replace("\\", "/") - pattern = "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}" - # Workfile paths can be configured to have host name in file path. - # In this case we want to avoid duplicate folder names. - if "nuke" in fpath.lower(): - pattern = pattern.replace("nuke/", "") - - fpath = pattern.format( - work=fpath, - version=data["version"], - subset=data["subset"], + fpath = data["fpath_template"].format( + work=fpath, version=data["version"], subset=data["subset"], frame=data["frame"], ext=data["nuke_dataflow_writes"]["file_type"] ) @@ -228,14 +249,89 @@ def create_write_node(name, data): log.debug(_data) _data["frame_range"] = data.get("frame_range", None) - log.info("__ _data3: {}".format(_data)) - instance = avalon.nuke.lib.add_write_node( - name, - **_data - ) - instance = avalon.nuke.lib.imprint(instance, data["avalon"]) - add_rendering_knobs(instance) - return instance + + # todo: hange this to new way + GN = nuke.createNode("Group", "name {}".format(name)) + + prev_node = None + with GN: + # creating pre-write nodes `prenodes` + if prenodes: + for name, klass, properties, set_input_to in prenodes: + # create node + now_node = nuke.createNode(klass, "name {}".format(name)) + + # add data to knob + for k, v in properties: + if k and v: + now_node[k].serValue(str(v)) + + # connect to previous node + if set_input_to: + if isinstance(set_input_to, (tuple or list)): + for i, node_name in enumerate(set_input_to): + input_node = nuke.toNode(node_name) + now_node.setInput(1, input_node) + elif isinstance(set_input_to, str): + input_node = nuke.toNode(set_input_to) + now_node.setInput(0, input_node) + else: + now_node.setInput(0, prev_node) + + # swith actual node to previous + prev_node = now_node + else: + prev_node = nuke.createNode("Input", "name rgba") + + + # creating write node + now_node = avalon.nuke.lib.add_write_node("inside_{}".format(name), + **_data + ) + write_node = now_node + # connect to previous node + now_node.setInput(0, prev_node) + + # swith actual node to previous + prev_node = now_node + + now_node = nuke.createNode("Output", "name write") + + # connect to previous node + now_node.setInput(0, prev_node) + + # imprinting group node + GN = avalon.nuke.imprint(GN, data["avalon"]) + + divider = nuke.Text_Knob('') + GN.addKnob(divider) + + add_rendering_knobs(GN) + + divider = nuke.Text_Knob('') + GN.addKnob(divider) + + # set tile color + tile_color = _data.get("tile_color", "0xff0000ff") + GN["tile_color"].setValue(tile_color) + + + # add render button + lnk = nuke.Link_Knob("Render") + lnk.makeLink(write_node.name(), "Render") + lnk.setName("Render") + GN.addKnob(lnk) + + # linking knobs to group property panel + linking_knobs = ["first", "last", "use_limit"] + for k in linking_knobs: + lnk = nuke.Link_Knob(k) + lnk.makeLink(write_node.name(), k) + lnk.setName(k.replace('_', ' ').capitalize()) + lnk.clearFlag(nuke.STARTLINE) + GN.addKnob(lnk) + + return GN def add_rendering_knobs(node): @@ -414,8 +510,8 @@ def reset_frame_range_handles(): # adding handle_start/end to root avalon knob if not avalon.nuke.set_avalon_knob_data(root, { - "handle_start": handle_start, - "handle_end": handle_end + "handle_start": int(handle_start), + "handle_end": int(handle_end) }): log.warning("Cannot set Avalon knob to Root node!") @@ -436,34 +532,26 @@ def reset_resolution(): asset = api.Session["AVALON_ASSET"] asset = io.find_one({"name": asset, "type": "asset"}) - try: - width = asset.get('data', {}).get('resolution_width', 1920) - height = asset.get('data', {}).get('resolution_height', 1080) - pixel_aspect = asset.get('data', {}).get('pixel_aspect', 1) - bbox = asset.get('data', {}).get('crop', "0.0.1920.1080") + width = asset.get('data', {}).get('resolution_width') + height = asset.get('data', {}).get('resolution_height') + pixel_aspect = asset.get('data', {}).get('pixel_aspect') - if bbox not in "0.0.1920.1080": - try: - x, y, r, t = bbox.split(".") - except Exception as e: - x = 0 - y = 0 - r = width - t = height - bbox = None - log.error("{}: {} \nFormat:Crop need to be set with dots, example: " - "0.0.1920.1080, /nSetting to default".format(__name__, e)) - else: - bbox = None - - except KeyError: - log.warning( - "No resolution information found for \"{0}\".".format( - project["name"] - ) - ) + log.info("pixel_aspect: {}".format(pixel_aspect)) + if any(not x for x in [width, height, pixel_aspect]): + log.error("Missing set shot attributes in DB. \nContact your supervisor!. \n\nWidth: `{0}` \nHeight: `{1}` \nPixel Asspect: `{2}`".format( + width, height, pixel_aspect)) return + bbox = asset.get('data', {}).get('crop') + + if bbox: + try: + x, y, r, t = bbox.split(".") + except Exception as e: + bbox = None + log.error("{}: {} \nFormat:Crop need to be set with dots, example: " + "0.0.1920.1080, /nSetting to default".format(__name__, e)) + used_formats = list() for f in nuke.formats(): if project["name"] in str(f.name()): @@ -620,7 +708,7 @@ def get_hierarchical_attr(entity, attr, default=None): # dict # """ # -# node = container["_tool"] +# node = container["_node"] # tile_color = node['tile_color'].value() # if tile_color is None: # return {} diff --git a/pype/plugins/ftrack/publish/integrate_remove_components.py b/pype/plugins/ftrack/publish/integrate_remove_components.py new file mode 100644 index 0000000000..a215ee1b97 --- /dev/null +++ b/pype/plugins/ftrack/publish/integrate_remove_components.py @@ -0,0 +1,27 @@ +import pyblish.api +import os + + +class IntegrateCleanComponentData(pyblish.api.InstancePlugin): + """ + Cleaning up thumbnail an mov files after they have been integrated + """ + + order = pyblish.api.IntegratorOrder + 0.5 + label = 'Clean component data' + families = ["ftrack"] + optional = True + active = True + + def process(self, instance): + + for comp in instance.data['representations']: + self.log.debug('component {}'.format(comp)) + + if comp.get('thumbnail') or ("thumbnail" in comp.get('tags', [])): + os.remove(comp['published_path']) + self.log.info('Thumbnail image was erased') + + elif comp.get('preview') or ("preview" in comp.get('tags', [])): + os.remove(comp['published_path']) + self.log.info('Preview mov file was erased') diff --git a/pype/plugins/nuke/create/create_write b/pype/plugins/nuke/create/create_write deleted file mode 100644 index dcb132875a..0000000000 --- a/pype/plugins/nuke/create/create_write +++ /dev/null @@ -1,17 +0,0 @@ -# type: render -# if no render type node in script then first is having in name [master] for definition of main script renderer -# colorspace setting from templates -# dataflow setting from templates - -# type: mask_render -# created with shuffle gizmo for RGB separation into davinci matte -# colorspace setting from templates -# dataflow setting from templates - -# type: prerender -# backdrop with write and read -# colorspace setting from templates -# dataflow setting from templates - -# type: geo -# dataflow setting from templates diff --git a/pype/plugins/nuke/create/create_write.py b/pype/plugins/nuke/create/create_write.py index a5b0c204bd..d791fe6d1b 100644 --- a/pype/plugins/nuke/create/create_write.py +++ b/pype/plugins/nuke/create/create_write.py @@ -3,6 +3,7 @@ import avalon.api import avalon.nuke from pype.nuke.lib import create_write_node from pype import api as pype +from pypeapp import config import nuke @@ -30,6 +31,11 @@ class CreateWriteRender(avalon.nuke.Creator): def __init__(self, *args, **kwargs): super(CreateWriteRender, self).__init__(*args, **kwargs) + self.presets = config.get_presets()['plugins']["nuke"]["create"].get( + self.__class__.__name__, {} + ) + + self.name = self.data["subset"] data = OrderedDict() @@ -41,7 +47,6 @@ class CreateWriteRender(avalon.nuke.Creator): self.data = data def process(self): - self.name = self.data["subset"] family = self.family node = 'write' @@ -55,6 +60,16 @@ class CreateWriteRender(avalon.nuke.Creator): "avalon": self.data } + if self.presets.get('fpath_template'): + self.log.info("Adding template path from preset") + write_data.update( + {"fpath_template": self.presets["fpath_template"]} + ) + else: + self.log.info("Adding template path from plugin") + write_data.update({ + "fpath_template": "{work}/renders/nuke/{subset}/{subset}.{frame}.{ext}"}) + create_write_node(self.data["subset"], write_data) return @@ -74,6 +89,9 @@ class CreateWritePrerender(avalon.nuke.Creator): def __init__(self, *args, **kwargs): super(CreateWritePrerender, self).__init__(*args, **kwargs) + self.presets = config.get_presets()['plugins']["nuke"]["create"].get( + self.__class__.__name__, {} + ) data = OrderedDict() @@ -97,56 +115,16 @@ class CreateWritePrerender(avalon.nuke.Creator): "avalon": self.data } + if self.presets.get('fpath_template'): + self.log.info("Adding template path from preset") + write_data.update( + {"fpath_template": self.presets["fpath_template"]} + ) + else: + self.log.info("Adding template path from plugin") + write_data.update({ + "fpath_template": "{work}/prerenders/{subset}/{subset}.{frame}.{ext}"}) + create_write_node(self.data["subset"], write_data) return - - -""" -class CrateWriteStill(avalon.nuke.Creator): - # change this to template preset - preset = "still" - - name = "WriteStill" - label = "Create Write Still" - hosts = ["nuke"] - family = "{}_write".format(preset) - families = preset - icon = "image" - - def __init__(self, *args, **kwargs): - super(CrateWriteStill, self).__init__(*args, **kwargs) - - data = OrderedDict() - - data["family"] = self.family.split("_")[-1] - data["families"] = self.families - - {data.update({k: v}) for k, v in self.data.items() - if k not in data.keys()} - self.data = data - - def process(self): - self.name = self.data["subset"] - - node_name = self.data["subset"].replace( - "_", "_f{}_".format(nuke.frame())) - instance = nuke.toNode(self.data["subset"]) - self.data["subset"] = node_name - - family = self.family - node = 'write' - - if not instance: - write_data = { - "frame_range": [nuke.frame(), nuke.frame()], - "class": node, - "preset": self.preset, - "avalon": self.data - } - - nuke.createNode("FrameHold", "first_frame {}".format(nuke.frame())) - create_write_node(node_name, write_data) - - return -""" diff --git a/pype/plugins/nuke/inventory/select_containers.py b/pype/plugins/nuke/inventory/select_containers.py index 339e3a4992..b420f53431 100644 --- a/pype/plugins/nuke/inventory/select_containers.py +++ b/pype/plugins/nuke/inventory/select_containers.py @@ -11,7 +11,7 @@ class SelectContainers(api.InventoryAction): import avalon.nuke - nodes = [i["_tool"] for i in containers] + nodes = [i["_node"] for i in containers] with avalon.nuke.viewer_update_and_undo_stop(): # clear previous_selection diff --git a/pype/plugins/nuke/inventory/set_tool_color.py b/pype/plugins/nuke/inventory/set_tool_color.py index 725a3f3e74..7a81444c90 100644 --- a/pype/plugins/nuke/inventory/set_tool_color.py +++ b/pype/plugins/nuke/inventory/set_tool_color.py @@ -20,7 +20,7 @@ # # # Get tool color # first = containers[0] -# tool = first["_tool"] +# tool = first["_node"] # color = tool.TileColor # # if color is not None: @@ -40,7 +40,7 @@ # rgb_f_table = {"R": rgb_f[0], "G": rgb_f[1], "B": rgb_f[2]} # # # Update tool -# tool = container["_tool"] +# tool = container["_node"] # tool.TileColor = rgb_f_table # # result.append(container) diff --git a/pype/plugins/nuke/publish/collect_instances.py b/pype/plugins/nuke/publish/collect_instances.py index cca5a861ff..8d770ef0b5 100644 --- a/pype/plugins/nuke/publish/collect_instances.py +++ b/pype/plugins/nuke/publish/collect_instances.py @@ -3,7 +3,7 @@ import os import nuke import pyblish.api from avalon import io, api -from pype.nuke.lib import get_avalon_knob_data +from avalon.nuke.lib import get_avalon_knob_data @pyblish.api.log @@ -34,6 +34,7 @@ class CollectNukeInstances(pyblish.api.ContextPlugin): # get data from avalon knob avalon_knob_data = get_avalon_knob_data(node) + self.log.debug("avalon_knob_data: {}".format(avalon_knob_data)) if not avalon_knob_data: continue diff --git a/pype/templates.py b/pype/templates.py index 9fe2e8c68c..e3356e8d60 100644 --- a/pype/templates.py +++ b/pype/templates.py @@ -28,7 +28,7 @@ def get_version_from_path(file): v: version number in string ('001') """ - pattern = re.compile(r"[\._]v([0-9]*)") + pattern = re.compile(r"v([0-9]*)") try: v = pattern.findall(file)[0] return v diff --git a/setup/nuke/nuke_path/atom_server.py b/setup/nuke/nuke_path/atom_server.py new file mode 100644 index 0000000000..1742c290c1 --- /dev/null +++ b/setup/nuke/nuke_path/atom_server.py @@ -0,0 +1,54 @@ +''' + Simple socket server using threads +''' + +import socket +import sys +import threading +import StringIO +import contextlib + +import nuke + +HOST = '' +PORT = 8888 + + +@contextlib.contextmanager +def stdoutIO(stdout=None): + old = sys.stdout + if stdout is None: + stdout = StringIO.StringIO() + sys.stdout = stdout + yield stdout + sys.stdout = old + + +def _exec(data): + with stdoutIO() as s: + exec(data) + return s.getvalue() + + +def server_start(): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.bind((HOST, PORT)) + s.listen(5) + + while 1: + client, address = s.accept() + try: + data = client.recv(4096) + if data: + result = nuke.executeInMainThreadWithResult(_exec, args=(data)) + client.send(str(result)) + except SystemExit: + result = self.encode('SERVER: Shutting down...') + client.send(str(result)) + raise + finally: + client.close() + +t = threading.Thread(None, server_start) +t.setDaemon(True) +t.start() diff --git a/setup/nuke/nuke_path/menu.py b/setup/nuke/nuke_path/menu.py index 82438084aa..fd87c98246 100644 --- a/setup/nuke/nuke_path/menu.py +++ b/setup/nuke/nuke_path/menu.py @@ -1,3 +1,4 @@ +import atom_server from pype.nuke.lib import ( writes_version_sync, @@ -15,5 +16,6 @@ log = Logger().get_logger(__name__, "nuke") nuke.addOnScriptSave(onScriptLoad) nuke.addOnScriptLoad(checkInventoryVersions) nuke.addOnScriptSave(checkInventoryVersions) +nuke.addOnScriptSave(writes_version_sync) log.info('Automatic syncing of write file knob to script version')