import bpy import re def clean_name(name): if re.match(r'(.*)\.\d{3}$', name): return name[:-4] return name def is_node_groups_duplicate(node_groups): node_group_types = sorted([n.type for n in node_groups[0].nodes]) return all( sorted([n.type for n in ng.nodes]) == node_group_types for ng in node_groups[1:]) def remap_node_group_duplicates(nodes=None, force=False): if nodes is None: nodes = list(bpy.data.node_groups) nodes = [n for n in nodes if not n.library] failed = [] merged = [] # Group by name groups = {} for node in nodes: groups.setdefault(clean_name(node.name), []).append(node) for node in bpy.data.node_groups: name = clean_name(node.name) if name in groups and node not in groups[name]: groups[name].append(node) print("\nMerge Duplicate NodeGroup...") for node_groups in groups.values(): if len(node_groups) == 1: continue if not force: node_groups.sort(key=lambda x : x.name, reverse=True) print(node_groups) for node_group in node_groups[1:]: is_duplicate = is_node_groups_duplicate((node_group, node_groups[0])) if not is_duplicate and not force: failed.append((node_group.name, node_groups[0].name)) print(f'Cannot merge Nodegroup {node_group.name} with {node_groups[0].name} they are different') continue merged.append((node_group.name, node_groups[0].name)) print(f'Merge Nodegroup {node_group.name} into {node_groups[0].name}') node_group.user_remap(node_groups[0]) bpy.data.node_groups.remove(node_group) node_groups.remove(node_group) # Rename groups if it has no duplicate left for node_groups in groups.values(): if len(node_groups) == 1 and not node_groups[0].library: node_groups[0].name = clean_name(node_groups[0].name) return merged, failed