Esempio n. 1
0
    def load(self, context, name=None, namespace=None, data=None):
        # Import template.
        temp_dir = tempfile.mkdtemp()
        zip_file = api.get_representation_path(context["representation"])
        template_path = os.path.join(temp_dir, "temp.tpl")
        with zipfile.ZipFile(zip_file, "r") as zip_ref:
            zip_ref.extractall(template_path)

        sig = harmony.signature("paste")
        func = """function %s(args)
        {
            var template_path = args[0];
            var drag_object = copyPaste.pasteTemplateIntoGroup(
                template_path, "Top", 1
            );
        }
        %s
        """ % (sig, sig)

        harmony.send({"function": func, "args": [template_path]})

        shutil.rmtree(temp_dir)

        subset_name = context["subset"]["name"]

        return harmony.containerise(subset_name, namespace, subset_name,
                                    context, self.__class__.__name__)

        def update(self, container, representation):
            pass

        def remove(self, container):
            pass
Esempio n. 2
0
def set_scene_settings(settings):
    func = """function func(args)
    {
        if (args[0]["fps"])
        {
            scene.setFrameRate(args[0]["fps"]);
        }
        if (args[0]["frameStart"] && args[0]["frameEnd"])
        {
            var duration = args[0]["frameEnd"] - args[0]["frameStart"] + 1

            if (frame.numberOf() < duration)
            {
                frame.insert(
                    duration, duration - frame.numberOf()
                );
            }

            scene.setStartFrame(1);
            scene.setStopFrame(duration);
        }
        if (args[0]["resolutionWidth"] && args[0]["resolutionHeight"])
        {
            scene.setDefaultResolution(
                args[0]["resolutionWidth"], args[0]["resolutionHeight"], 41.112
            )
        }
    }
    func
    """
    harmony.send({"function": func, "args": [settings]})
Esempio n. 3
0
    def process(self, context):
        nodes = harmony.send({
            "function": "node.subNodes",
            "args": ["Top"]
        })["result"]

        for node in nodes:
            data = harmony.read(node)

            # Skip non-tagged nodes.
            if not data:
                continue

            # Skip containers.
            if "container" in data["id"]:
                continue

            instance = context.create_instance(node.split("/")[-1])
            instance.append(node)
            instance.data.update(data)
            instance.data["publish"] = harmony.send({
                "function": "node.getEnable",
                "args": [node]
            })["result"]
            instance.data["families"] = self.families_mapping[data["family"]]

            # Produce diagnostic message for any graphical
            # user interface interested in visualising it.
            self.log.info("Found: \"{0}\": \n{1}".format(
                instance.data["name"], json.dumps(instance.data, indent=4)))
Esempio n. 4
0
 def _set_red(self, node):
     """Set node color to red `rgba(255, 0, 0, 255)`."""
     harmony.send(
         {
             "function": "PypeHarmony.setColor",
             "args": [node, [255, 0, 0, 255]]
         })
Esempio n. 5
0
 def _set_green(self, node):
     """Set node color to green `rgba(0, 255, 0, 255)`."""
     harmony.send(
         {
             "function": "PypeHarmony.setColor",
             "args": [node, [0, 255, 0, 255]]
         })
Esempio n. 6
0
 def setup_node(self, node):
     """Set render node."""
     self_name = self.__class__.__name__
     path = "render/{0}/{0}.".format(node.split("/")[-1])
     harmony.send({
         "function": f"PypeHarmony.Creators.{self_name}.create",
         "args": [node, path]
     })
Esempio n. 7
0
    def remove(self, container):
        """Remove container.

        Args:
            container (dict): container definition.

        """
        node = harmony.find_node_by_name(container["name"], "GROUP")
        harmony.send({"function": "PypeHarmony.deleteNode", "args": [node]})
Esempio n. 8
0
 def remove(self, container):
     node = container.pop("node")
     func = """function deleteNode(_node)
     {
         node.deleteNode(_node, true, true);
     }
     deleteNode
     """
     harmony.send({"function": func, "args": [node]})
Esempio n. 9
0
def on_pyblish_instance_toggled(instance, old_value, new_value):
    """Toggle node enabling on instance toggles."""
    func = """function func(args)
    {
        node.setEnable(args[0], args[1])
    }
    func
    """
    harmony.send({"function": func, "args": [instance[0], new_value]})
Esempio n. 10
0
    def remove(self, container):
        """Remove loaded container.

        Args:
            container (dict): Container data.

        """
        node = container.get("nodes").pop()
        harmony.send({"function": "PypeHarmony.deleteNode", "args": [node]})
        harmony.imprint(node, {}, remove=True)
Esempio n. 11
0
    def remove(self, container):
        node = harmony.find_node_by_name(container["name"], "READ")

        func = """function deleteNode(_node)
        {
            node.deleteNode(_node, true, true);
        }
        deleteNode
        """
        harmony.send({"function": func, "args": [node]})
Esempio n. 12
0
 def setup_node(self, node):
     """Set render node."""
     path = "render/{0}/{0}.".format(node.split("/")[-1])
     harmony.send({
         "function": f"PypeHarmony.Creators.CreateRender.create",
         "args": [node, path]
     })
     harmony.send({
         "function": f"PypeHarmony.color",
         "args": [[0.9, 0.75, 0.3, 1.0]]
     })
Esempio n. 13
0
    def load(self, context, name=None, namespace=None, data=None):
        wav_file = api.get_representation_path(context["representation"])
        harmony.send({
            "function": func,
            "args": [context["subset"]["name"], wav_file]
        })

        subset_name = context["subset"]["name"]

        return harmony.containerise(subset_name, namespace, subset_name,
                                    context, self.__class__.__name__)
Esempio n. 14
0
 def setup_node(self, node):
     func = """function func(args)
     {
         node.setTextAttr(args[0], "DRAWING_TYPE", 1, "PNG4");
         node.setTextAttr(args[0], "DRAWING_NAME", 1, args[1]);
         node.setTextAttr(args[0], "MOVIE_PATH", 1, args[1]);
     }
     func
     """
     path = "{0}/{0}".format(node.split("/")[-1])
     harmony.send({"function": func, "args": [node, path]})
Esempio n. 15
0
    def remove(self, container):
        for node in container.get("nodes"):

            func = """function deleteNode(_node)
            {
                node.deleteNode(_node, true, true);
            }
            deleteNode
            """
            harmony.send({"function": func, "args": [node]})
            harmony.imprint(container['name'], {}, remove=True)
Esempio n. 16
0
    def process(self, context):
        """Plugin entry point."""
        result = harmony.send({
            f"function": "PypeHarmony.getSceneSettings",
            "args": []
        })["result"]

        context.data["applicationPath"] = result[0]
        context.data["scenePath"] = os.path.join(result[1],
                                                 result[2] + ".xstage")
        context.data["frameRate"] = result[3]
        context.data["frameStartHandle"] = result[4]
        context.data["frameEndHandle"] = result[5]
        context.data["audioPath"] = result[6]
        context.data["resolutionWidth"] = result[7]
        context.data["resolutionHeight"] = result[8]
        context.data["FOV"] = result[9]

        # harmony always starts from 1. frame
        # 1001 - 10010 >> 1 - 10
        # frameStart, frameEnd already collected by global plugin
        offset = context.data["frameStart"] - 1
        frame_start = context.data["frameStart"] - offset
        frames_count = context.data["frameEnd"] - \
            context.data["frameStart"] + 1

        # increase by handleStart - real frame range
        # frameStart != frameStartHandle with handle presence
        context.data["frameStart"] = int(frame_start) + \
            context.data["handleStart"]
        context.data["frameEnd"] = int(frames_count) + \
            context.data["frameStart"] - 1

        all_nodes = harmony.send({
            "function": "node.subNodes",
            "args": ["Top"]
        })["result"]

        context.data["allNodes"] = all_nodes

        # collect all write nodes to be able disable them in Deadline
        all_write_nodes = harmony.send({
            "function": "node.getNodes",
            "args": ["WRITE"]
        })["result"]

        context.data["all_write_nodes"] = all_write_nodes

        result = harmony.send({
            f"function": "PypeHarmony.getVersion",
            "args": []
        })["result"]
        context.data["harmonyVersion"] = "{}.{}".format(result[0], result[1])
Esempio n. 17
0
def check_inventory():
    if not lib.any_outdated():
        return

    host = avalon.api.registered_host()
    outdated_containers = []
    for container in host.ls():
        representation = container['representation']
        representation_doc = io.find_one(
            {
                "_id": io.ObjectId(representation),
                "type": "representation"
            },
            projection={"parent": True}
        )
        if representation_doc and not lib.is_latest(representation_doc):
            outdated_containers.append(container)

    # Colour nodes.
    func = """function func(args){
        for( var i =0; i <= args[0].length - 1; ++i)
        {
            var red_color = new ColorRGBA(255, 0, 0, 255);
            node.setColor(args[0][i], red_color);
        }
    }
    func
    """
    outdated_nodes = []
    for container in outdated_containers:
        if container["loader"] == "ImageSequenceLoader":
            outdated_nodes.append(
                harmony.find_node_by_name(container["name"], "READ")
            )
    harmony.send({"function": func, "args": [outdated_nodes]})

    # Warn about outdated containers.
    print("Starting new QApplication..")
    app = Qt.QtWidgets.QApplication(sys.argv)

    message_box = Qt.QtWidgets.QMessageBox()
    message_box.setIcon(Qt.QtWidgets.QMessageBox.Warning)
    msg = "There are outdated containers in the scene."
    message_box.setText(msg)
    message_box.exec_()

    # Garbage collect QApplication.
    del app
Esempio n. 18
0
    def process(self, context):
        func = """function func()
        {
            var palette_list = PaletteObjectManager.getScenePaletteList();

            var palettes = {};
            for(var i=0; i < palette_list.numPalettes; ++i)
            {
                var palette = palette_list.getPaletteByIndex(i);
                palettes[palette.getName()] = palette.id;
            }

            return palettes;
        }
        func
        """
        palettes = harmony.send({"function": func})["result"]

        for name, id in palettes.items():
            instance = context.create_instance(name)
            instance.data.update({
                "id": id,
                "family": "harmony.palette",
                "asset": os.environ["AVALON_ASSET"],
                "subset": "palette" + name
            })
            self.log.info(
                "Created instance:\n" + json.dumps(
                    instance.data, sort_keys=True, indent=4
                )
            )
Esempio n. 19
0
    def process(self, context):
        """Inject the current working file."""
        self_name = self.__class__.__name__

        current_file = harmony.send(
            {"function": f"PypeHarmony.Publish.{self_name}.collect"})["result"]
        context.data["currentFile"] = os.path.normpath(current_file)
Esempio n. 20
0
    def process(self, context):
        """Collector entry point."""
        self_name = self.__class__.__name__
        palettes = harmony.send({
            "function":
            f"PypeHarmony.Publish.{self_name}.getPalettes",
        })["result"]

        # skip collecting if not in allowed task
        if self.allowed_tasks:
            task_name = context.data["anatomyData"]["task"].lower()
            if (not any([
                    re.search(pattern, task_name)
                    for pattern in self.allowed_tasks
            ])):
                return

        for name, id in palettes.items():
            instance = context.create_instance(name)
            instance.data.update({
                "id": id,
                "family": "harmony.palette",
                'families': [],
                "asset": os.environ["AVALON_ASSET"],
                "subset": "{}{}".format("palette", name)
            })
            self.log.info("Created instance:\n" +
                          json.dumps(instance.data, sort_keys=True, indent=4))
Esempio n. 21
0
    def load(self, context, name=None, namespace=None, data=None):
        """Plugin entry point.

        Args:
            context (:class:`pyblish.api.Context`): Context.
            name (str, optional): Container name.
            namespace (str, optional): Container namespace.
            data (dict, optional): Additional data passed into loader.

        """
        # Load template.
        self_name = self.__class__.__name__
        temp_dir = tempfile.mkdtemp()
        zip_file = api.get_representation_path(context["representation"])
        template_path = os.path.join(temp_dir, "temp.tpl")
        with zipfile.ZipFile(zip_file, "r") as zip_ref:
            zip_ref.extractall(template_path)

        group_id = "{}".format(uuid.uuid4())

        container_group = harmony.send({
            "function":
            f"PypeHarmony.Loaders.{self_name}.loadContainer",
            "args": [
                template_path, context["asset"]["name"],
                context["subset"]["name"], group_id
            ]
        })["result"]

        # Cleanup the temp directory
        shutil.rmtree(temp_dir)

        # We must validate the group_node
        return harmony.containerise(name, namespace, container_group, context,
                                    self_name)
Esempio n. 22
0
    def load(self, context, name=None, namespace=None, data=None):

        collections, remainder = clique.assemble(
            os.listdir(os.path.dirname(self.fname)))
        files = []
        if collections:
            for f in list(collections[0]):
                files.append(
                    os.path.join(os.path.dirname(self.fname),
                                 f).replace("\\", "/"))
        else:
            files.append(
                os.path.join(os.path.dirname(self.fname),
                             remainder[0]).replace("\\", "/"))

        name = context["subset"]["name"]
        name += "_{}".format(uuid.uuid4())
        read_node = harmony.send({
            "function": copy_files + import_files,
            "args": ["Top", files, name, 1]
        })["result"]

        return harmony.containerise(name,
                                    namespace,
                                    read_node,
                                    context,
                                    self.__class__.__name__,
                                    nodes=[read_node])
Esempio n. 23
0
    def get_dependencies(self, node: str, dependencies: list = None) -> list:
        """Get node dependencies.

        This will return recursive dependency list of given node.

        Args:
            node (str): Path to the node.
            dependencies (list, optional): existing dependency list.

        Returns:
            list: List of dependent nodes.

        """
        current_dependencies = harmony.send({
            "function": "PypeHarmony.getDependencies",
            "args": node
        })["result"]

        for dependency in current_dependencies:
            if not dependency:
                continue

            if dependency in dependencies:
                continue

            dependencies.append(dependency)

            self.get_dependencies(dependency, dependencies)
Esempio n. 24
0
def export_template(backdrops, nodes, filepath):
    func = """function func(args)
    {

        var temp_node = node.add("Top", "temp_note", "NOTE", 0, 0, 0);
        var template_group = node.createGroup(temp_node, "temp_group");
        node.deleteNode( template_group + "/temp_note" );

        selection.clearSelection();
        for (var f = 0; f < args[1].length; f++)
        {
            selection.addNodeToSelection(args[1][f]);
        }

        Action.perform("copy()", "Node View");

        selection.clearSelection();
        selection.addNodeToSelection(template_group);
        Action.perform("onActionEnterGroup()", "Node View");
        Action.perform("paste()", "Node View");

        // Recreate backdrops in group.
        for (var i = 0 ; i < args[0].length; i++)
        {
            MessageLog.trace(args[0][i]);
            Backdrop.addBackdrop(template_group, args[0][i]);
        };

        Action.perform( "selectAll()", "Node View" );
        copyPaste.createTemplateFromSelection(args[2], args[3]);

        // Unfocus the group in Node view, delete all nodes and backdrops
        // created during the process.
        Action.perform("onActionUpToParent()", "Node View");
        node.deleteNode(template_group, true, true);
    }
    func
    """
    harmony.send({
        "function": func,
        "args": [
            backdrops,
            nodes,
            os.path.basename(filepath),
            os.path.dirname(filepath)
        ]
    })
Esempio n. 25
0
    def process(self, instance):
        """Plugin entry point."""
        self_name = self.__class__.__name__
        result = harmony.send({
            "function": f"PypeHarmony.Publish.{self_name}.getPalette",
            "args": instance.data["id"]
        })["result"]

        if not isinstance(result, list):
            self.log.error(f"Invalid reply: {result}")
            raise AssertionError("Invalid reply from server.")
        palette_name = result[0]
        palette_file = result[1]
        self.log.info(f"Got palette named {palette_name} "
                      f"and file {palette_file}.")

        tmp_thumb_path = os.path.join(
            os.path.dirname(palette_file),
            os.path.basename(palette_file).split(".plt")[0] + "_swatches.png")
        self.log.info(f"Temporary thumbnail path {tmp_thumb_path}")

        palette_version = str(instance.data.get("version")).zfill(3)

        self.log.info(f"Palette version {palette_version}")

        if not instance.data.get("representations"):
            instance.data["representations"] = []

        try:
            thumbnail_path = self.create_palette_thumbnail(
                palette_name, palette_version, palette_file, tmp_thumb_path)
        except OSError as e:
            # FIXME: this happens on Mac where PIL cannot access fonts
            # for some reason.
            self.log.warning("Thumbnail generation failed")
            self.log.warning(e)
        except ValueError:
            self.log.error("Unsupported palette type for thumbnail.")

        else:
            thumbnail = {
                "name": "thumbnail",
                "ext": "png",
                "files": os.path.basename(thumbnail_path),
                "stagingDir": os.path.dirname(thumbnail_path),
                "tags": ["thumbnail"]
            }

            instance.data["representations"].append(thumbnail)

        representation = {
            "name": "plt",
            "ext": "plt",
            "files": os.path.basename(palette_file),
            "stagingDir": os.path.dirname(palette_file)
        }

        instance.data["representations"].append(representation)
Esempio n. 26
0
    def process(self, context):
        """Plugin entry point.

        Args:
            context (:class:`pyblish.api.Context`): Context data.

        """
        nodes = harmony.send({
            "function": "node.subNodes",
            "args": ["Top"]
        })["result"]

        for node in nodes:
            data = harmony.read(node)

            # Skip non-tagged nodes.
            if not data:
                continue

            # Skip containers.
            if "container" in data["id"]:
                continue

            # skip render farm family as it is collected separately
            if data["family"] == "renderFarm":
                continue

            instance = context.create_instance(node.split("/")[-1])
            instance.data.update(data)
            instance.data["setMembers"] = [node]
            instance.data["publish"] = harmony.send({
                "function": "node.getEnable",
                "args": [node]
            })["result"]
            instance.data["families"] = self.families_mapping[data["family"]]

            # If set in plugin, pair the scene Version in ftrack with
            # thumbnails and review media.
            if (self.pair_media and instance.data["family"] == "scene"):
                context.data["scene_instance"] = instance

            # Produce diagnostic message for any graphical
            # user interface interested in visualising it.
            self.log.info("Found: \"{0}\": \n{1}".format(
                instance.data["name"], json.dumps(instance.data, indent=4)))
Esempio n. 27
0
    def update(self, container, representation):
        node = container.pop("node")

        collections, remainder = clique.assemble(
            os.listdir(
                os.path.dirname(api.get_representation_path(representation))))
        files = []
        for f in list(collections[0]):
            files.append(
                os.path.join(os.path.dirname(self.fname),
                             f).replace("\\", "/"))

        harmony.send({
            "function": copy_files + replace_files,
            "args": [files, node, 1]
        })

        harmony.imprint(node, {"representation": str(representation["_id"])})
Esempio n. 28
0
    def update(self, container, representation):
        """Update loaded containers.

        Args:
            container (dict): Container data.
            representation (dict): Representation data.

        """
        node_name = container["name"]
        node = harmony.find_node_by_name(node_name, "GROUP")
        self_name = self.__class__.__name__

        update_and_replace = False
        if pype.lib.is_latest(representation):
            self._set_green(node)
        else:
            self._set_red(node)

        update_and_replace = harmony.send(
            {
                "function": f"PypeHarmony.Loaders.{self_name}."
                            "askForColumnsUpdate",
                "args": []
            }
        )["result"]

        if update_and_replace:
            # FIXME: This won't work, need to implement it.
            harmony.send(
                {
                    "function": f"PypeHarmony.Loaders.{self_name}."
                                "replaceNode",
                    "args": []
                }
            )
        else:
            self.load(
                container["context"], container["name"],
                None, container["data"])

        harmony.imprint(
            node, {"representation": str(representation["_id"])}
        )
Esempio n. 29
0
    def load_palette(self, representation):
        subset_name = representation["context"]["subset"]
        name = subset_name.replace("palette", "")

        # Overwrite palette on disk.
        scene_path = harmony.send({"function":
                                   "scene.currentProjectPath"})["result"]
        src = api.get_representation_path(representation)
        dst = os.path.join(scene_path, "palette-library",
                           "{}.plt".format(name))
        shutil.copy(src, dst)

        harmony.save_scene()

        msg = "Updated {}.".format(subset_name)
        msg += " You need to reload the scene to see the changes."

        harmony.send({"function": "PypeHarmony.message", "args": msg})
        return name
Esempio n. 30
0
def export_template(backdrops, nodes, filepath):
    func = """function func(args)
    {
        // Add an extra node just so a new group can be created.
        var temp_node = node.add("Top", "temp_note", "NOTE", 0, 0, 0);
        var template_group = node.createGroup(temp_node, "temp_group");
        node.deleteNode( template_group + "/temp_note" );

        // This will make Node View to focus on the new group.
        selection.clearSelection();
        selection.addNodeToSelection(template_group);
        Action.perform("onActionEnterGroup()", "Node View");

        // Recreate backdrops in group.
        for (var i = 0 ; i < args[0].length; i++)
        {
            Backdrop.addBackdrop(template_group, args[0][i]);
        };

        // Copy-paste the selected nodes into the new group.
        var drag_object = copyPaste.copy(args[1], 1, frame.numberOf, "");
        copyPaste.pasteNewNodes(drag_object, template_group, "");

        // Select all nodes within group and export as template.
        Action.perform( "selectAll()", "Node View" );
        copyPaste.createTemplateFromSelection(args[2], args[3]);

        // Unfocus the group in Node view, delete all nodes and backdrops
        // created during the process.
        Action.perform("onActionUpToParent()", "Node View");
        node.deleteNode(template_group, true, true);
    }
    func
    """
    harmony.send({
        "function":
        func,
        "args": [
            backdrops, nodes,
            os.path.basename(filepath),
            os.path.dirname(filepath)
        ]
    })