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)
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__)
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}\"." )
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)
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)
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)