예제 #1
0
    def _remove_layers(self, layer_names=None, layer_ids=None, layers=None):
        if not layer_names and not layer_ids:
            self.log.warning("Got empty layer names list.")
            return

        if layers is None:
            layers = lib.layers_data()

        available_ids = set(layer["layer_id"] for layer in layers)

        if layer_ids is None:
            # Backwards compatibility (layer ids were stored instead of names)
            layer_names_are_ids = True
            for layer_name in layer_names:
                if (not isinstance(layer_name, int)
                        and not layer_name.isnumeric()):
                    layer_names_are_ids = False
                    break

            if layer_names_are_ids:
                layer_ids = layer_names

        layer_ids_to_remove = []
        if layer_ids is not None:
            for layer_id in layer_ids:
                if layer_id in available_ids:
                    layer_ids_to_remove.append(layer_id)

        else:
            layers_by_name = collections.defaultdict(list)
            for layer in layers:
                layers_by_name[layer["name"]].append(layer)

            for layer_name in layer_names:
                layers = layers_by_name[layer_name]
                if len(layers) == 1:
                    layer_ids_to_remove.append(layers[0]["layer_id"])

        if not layer_ids_to_remove:
            self.log.warning("No layers to delete.")
            return

        george_script_lines = []
        for layer_id in layer_ids_to_remove:
            line = "tv_layerkill {}".format(layer_id)
            george_script_lines.append(line)
        george_script = "\n".join(george_script_lines)
        lib.execute_george_through_file(george_script)
예제 #2
0
    def load(self, context, name, namespace, options):
        stretch = options.get("stretch", self.defaults["stretch"])
        timestretch = options.get("timestretch", self.defaults["timestretch"])
        preload = options.get("preload", self.defaults["preload"])

        load_options = []
        if stretch:
            load_options.append("\"STRETCH\"")
        if timestretch:
            load_options.append("\"TIMESTRETCH\"")
        if preload:
            load_options.append("\"PRELOAD\"")

        load_options_str = ""
        for load_option in load_options:
            load_options_str += (load_option + " ")

        # Prepare layer name
        asset_name = context["asset"]["name"]
        subset_name = context["subset"]["name"]
        layer_name = self.get_unique_layer_name(asset_name, subset_name)

        # Fill import script with filename and layer name
        # - filename mus not contain backwards slashes
        george_script = self.import_script.format(
            self.fname.replace("\\", "/"), layer_name, load_options_str)

        lib.execute_george_through_file(george_script)

        loaded_layer = None
        layers = lib.layers_data()
        for layer in layers:
            if layer["name"] == layer_name:
                loaded_layer = layer
                break

        if loaded_layer is None:
            raise AssertionError(
                "Loading probably failed during execution of george script.")

        layer_names = [loaded_layer["name"]]
        namespace = namespace or layer_name
        return pipeline.containerise(name=name,
                                     namespace=namespace,
                                     members=layer_names,
                                     context=context,
                                     loader=self.__class__.__name__)
예제 #3
0
    def process(self):
        self.log.debug("Query data from workfile.")
        instances = pipeline.list_instances()
        layers_data = lib.layers_data()

        self.log.debug("Checking for selection groups.")
        # Collect group ids from selection
        group_ids = set()
        for layer in layers_data:
            if layer["selected"]:
                group_ids.add(layer["group_id"])

        # Raise if there is no selection
        if not group_ids:
            raise AssertionError("Nothing is selected.")

        # This creator should run only on one group
        if len(group_ids) > 1:
            raise AssertionError("More than one group is in selection.")

        group_id = tuple(group_ids)[0]
        # If group id is `0` it is `default` group which is invalid
        if group_id == 0:
            raise AssertionError(
                "Selection is not in group. Can't mark selection as Beauty."
            )

        self.log.debug(f"Selected group id is \"{group_id}\".")
        self.data["group_id"] = group_id

        family = self.data["family"]
        # Extract entered name
        name = self.data["subset"][len(family):]
        self.log.info(f"Extracted name from subset name \"{name}\".")
        self.data["name"] = name

        # Change subset name by template
        subset_name = self.subset_template.format(**{
            "family": self.family,
            "name": name
        })
        self.log.info(f"New subset name \"{subset_name}\".")
        self.data["subset"] = subset_name

        # Check for instances of same group
        existing_instance = None
        existing_instance_idx = None
        # Check if subset name is not already taken
        same_subset_instance = None
        same_subset_instance_idx = None
        for idx, instance in enumerate(instances):
            if instance["family"] == family:
                if instance["group_id"] == group_id:
                    existing_instance = instance
                    existing_instance_idx = idx
                elif instance["subset"] == subset_name:
                    same_subset_instance = instance
                    same_subset_instance_idx = idx

            if (
                same_subset_instance_idx is not None
                and existing_instance_idx is not None
            ):
                break

        if same_subset_instance_idx is not None:
            if self._ask_user_subset_override(same_subset_instance):
                instances.pop(same_subset_instance_idx)
            else:
                return

        if existing_instance is not None:
            self.log.info(
                f"Beauty instance for group id {group_id} already exists"
                ", overriding"
            )
            instances[existing_instance_idx] = self.data
        else:
            instances.append(self.data)

        self.write_instances(instances)

        if not self.rename_group:
            self.log.info("Group rename function is turned off. Skipping")
            return

        self.log.debug("Querying groups data from workfile.")
        groups_data = lib.groups_data()

        self.log.debug("Changing name of the group.")
        selected_group = None
        for group_data in groups_data:
            if group_data["group_id"] == group_id:
                selected_group = group_data

        # Rename TVPaint group (keep color same)
        # - groups can't contain spaces
        new_group_name = name.replace(" ", "_")
        rename_script = self.rename_script_template.format(
            clip_id=selected_group["clip_id"],
            group_id=selected_group["group_id"],
            r=selected_group["red"],
            g=selected_group["green"],
            b=selected_group["blue"],
            name=new_group_name
        )
        lib.execute_george_through_file(rename_script)

        self.log.info(
            f"Name of group with index {group_id}"
            f" was changed to \"{new_group_name}\"."
        )
예제 #4
0
    def process(self):
        self.log.debug("Query data from workfile.")
        instances = pipeline.list_instances()
        layers_data = lib.layers_data()

        self.log.debug("Checking selection.")
        # Get all selected layers and their group ids
        group_ids = set()
        selected_layers = []
        for layer in layers_data:
            if layer["selected"]:
                selected_layers.append(layer)
                group_ids.add(layer["group_id"])

        # Raise if nothing is selected
        if not selected_layers:
            raise AssertionError("Nothing is selected.")

        # Raise if layers from multiple groups are selected
        if len(group_ids) != 1:
            raise AssertionError("More than one group is in selection.")

        group_id = tuple(group_ids)[0]
        self.log.debug(f"Selected group id is \"{group_id}\".")

        # Find beauty instance for selected layers
        beauty_instance = None
        for instance in instances:
            if (instance["family"] == "renderLayer"
                    and instance["group_id"] == group_id):
                beauty_instance = instance
                break

        # Beauty is required for this creator so raise if was not found
        if beauty_instance is None:
            raise AssertionError("Beauty pass does not exist yet.")

        render_layer = beauty_instance["name"]

        # Extract entered name
        family = self.data["family"]
        name = self.data["subset"]
        # Is this right way how to get name?
        name = name[len(family):]
        self.log.info(f"Extracted name from subset name \"{name}\".")

        self.data["group_id"] = group_id
        self.data["pass"] = name
        self.data["render_layer"] = render_layer

        # Collect selected layer ids to be stored into instance
        layer_names = [layer["name"] for layer in selected_layers]
        self.data["layer_names"] = layer_names

        # Replace `beauty` in beauty's subset name with entered name
        subset_name = self.subset_template.format(**{
            "family": family,
            "render_layer": render_layer,
            "pass": name
        })
        self.data["subset"] = subset_name
        self.log.info(f"New subset name is \"{subset_name}\".")

        # Check if same instance already exists
        existing_instance = None
        existing_instance_idx = None
        for idx, instance in enumerate(instances):
            if (instance["family"] == family
                    and instance["group_id"] == group_id
                    and instance["pass"] == name):
                existing_instance = instance
                existing_instance_idx = idx
                break

        if existing_instance is not None:
            self.log.info(f"Render pass instance for group id {group_id}"
                          f" and name \"{name}\" already exists, overriding.")
            instances[existing_instance_idx] = self.data
        else:
            instances.append(self.data)

        self.write_instances(instances)
예제 #5
0
    def process(self, context):
        current_project_id = lib.execute_george("tv_projectcurrentid")
        lib.execute_george("tv_projectselect {}".format(current_project_id))

        # Collect and store current context to have reference
        current_context = {
            "project": avalon.api.Session["AVALON_PROJECT"],
            "asset": avalon.api.Session["AVALON_ASSET"],
            "task": avalon.api.Session["AVALON_TASK"]
        }
        context.data["previous_context"] = current_context
        self.log.debug("Current context is: {}".format(current_context))

        # Collect context from workfile metadata
        self.log.info("Collecting workfile context")
        workfile_context = pipeline.get_current_workfile_context()
        if workfile_context:
            # Change current context with context from workfile
            key_map = (("AVALON_ASSET", "asset"), ("AVALON_TASK", "task"))
            for env_key, key in key_map:
                avalon.api.Session[env_key] = workfile_context[key]
                os.environ[env_key] = workfile_context[key]
        else:
            # Handle older workfiles or workfiles without metadata
            self.log.warning(
                "Workfile does not contain information about context."
                " Using current Session context.")
            workfile_context = current_context.copy()

        context.data["workfile_context"] = workfile_context
        self.log.info("Context changed to: {}".format(workfile_context))

        # Collect instances
        self.log.info("Collecting instance data from workfile")
        instance_data = pipeline.list_instances()
        context.data["workfileInstances"] = instance_data
        self.log.debug("Instance data:\"{}".format(
            json.dumps(instance_data, indent=4)))

        # Collect information about layers
        self.log.info("Collecting layers data from workfile")
        layers_data = lib.layers_data()
        layers_by_name = {}
        for layer in layers_data:
            layer_name = layer["name"]
            if layer_name not in layers_by_name:
                layers_by_name[layer_name] = []
            layers_by_name[layer_name].append(layer)
        context.data["layersData"] = layers_data
        context.data["layersByName"] = layers_by_name

        self.log.debug("Layers data:\"{}".format(
            json.dumps(layers_data, indent=4)))

        # Collect information about groups
        self.log.info("Collecting groups data from workfile")
        group_data = lib.groups_data()
        context.data["groupsData"] = group_data
        self.log.debug("Group data:\"{}".format(
            json.dumps(group_data, indent=4)))

        self.log.info("Collecting scene data from workfile")
        workfile_info_parts = lib.execute_george("tv_projectinfo").split(" ")

        # Project frame start - not used
        workfile_info_parts.pop(-1)
        field_order = workfile_info_parts.pop(-1)
        frame_rate = float(workfile_info_parts.pop(-1))
        pixel_apsect = float(workfile_info_parts.pop(-1))
        height = int(workfile_info_parts.pop(-1))
        width = int(workfile_info_parts.pop(-1))
        workfile_path = " ".join(workfile_info_parts).replace("\"", "")

        frame_start, frame_end = self.collect_clip_frames()
        scene_data = {
            "currentFile": workfile_path,
            "sceneWidth": width,
            "sceneHeight": height,
            "pixelAspect": pixel_apsect,
            "frameStart": frame_start,
            "frameEnd": frame_end,
            "fps": frame_rate,
            "fieldOrder": field_order
        }
        self.log.debug("Scene data: {}".format(json.dumps(scene_data,
                                                          indent=4)))
        context.data.update(scene_data)
예제 #6
0
    def update(self, container, representation):
        """Replace container with different version.

        New layers are loaded as first step. Then is tried to change data in
        new layers with data from old layers. When that is done old layers are
        removed.
        """
        # Create new containers first
        context = get_representation_context(representation)

        # Get layer ids from previous container
        old_layer_names = self.get_members_from_container(container)

        # Backwards compatibility (layer ids were stored instead of names)
        old_layers_are_ids = True
        for name in old_layer_names:
            if isinstance(name, int) or name.isnumeric():
                continue
            old_layers_are_ids = False
            break

        old_layers = []
        layers = lib.layers_data()
        previous_layer_ids = set(layer["layer_id"] for layer in layers)
        if old_layers_are_ids:
            for layer in layers:
                if layer["layer_id"] in old_layer_names:
                    old_layers.append(layer)
        else:
            layers_by_name = collections.defaultdict(list)
            for layer in layers:
                layers_by_name[layer["name"]].append(layer)

            for layer_name in old_layer_names:
                layers = layers_by_name[layer_name]
                if len(layers) == 1:
                    old_layers.append(layers[0])

        # Prepare few data
        new_start_position = None
        new_group_id = None
        layer_ids_to_remove = set()
        for layer in old_layers:
            layer_ids_to_remove.add(layer["layer_id"])
            position = layer["position"]
            group_id = layer["group_id"]
            if new_start_position is None:
                new_start_position = position
            elif new_start_position > position:
                new_start_position = position

            if new_group_id is None:
                new_group_id = group_id
            elif new_group_id < 0:
                continue
            elif new_group_id != group_id:
                new_group_id = -1

        # Remove old container
        self._remove_container(container)
        # Remove old layers
        self._remove_layers(layer_ids=layer_ids_to_remove)

        # Change `fname` to new representation
        self.fname = self.filepath_from_context(context)

        name = container["name"]
        namespace = container["namespace"]
        new_container = self.load(context, name, namespace, {})
        new_layer_names = self.get_members_from_container(new_container)

        layers = lib.layers_data()

        new_layers = []
        for layer in layers:
            if layer["layer_id"] in previous_layer_ids:
                continue
            if layer["name"] in new_layer_names:
                new_layers.append(layer)

        george_script_lines = []
        # Group new layers to same group as previous container layers had
        # - all old layers must be under same group
        if new_group_id is not None and new_group_id > 0:
            for layer in new_layers:
                line = "tv_layercolor \"set\" {} {}".format(
                    layer["layer_id"], new_group_id)
                george_script_lines.append(line)

        # Rename new layer to have same name
        # - only if both old and new have one layer
        if len(old_layers) == 1 and len(new_layers) == 1:
            layer_name = old_layers[0]["name"]
            george_script_lines.append("tv_layerrename {} \"{}\"".format(
                new_layers[0]["layer_id"], layer_name))

        # Change position of new layer
        # - this must be done before remove old layers
        if len(new_layers) == 1 and new_start_position is not None:
            new_layer = new_layers[0]
            george_script_lines.extend([
                "tv_layerset {}".format(new_layer["layer_id"]),
                "tv_layermove {}".format(new_start_position)
            ])

        # Execute george scripts if there are any
        if george_script_lines:
            george_script = "\n".join(george_script_lines)
            lib.execute_george_through_file(george_script)