top of page

DUPLICATE NODES

  • jnietomonco
  • Feb 7, 2023
  • 1 min read

This simple code copies and pastes your selection while maintaining the input connection of the highest-positioned node. I have this code set to the hotkey shift+d.


ree

Expand Duplicate Nodes

import nuke
import nukescripts

#####################################################################


# We create a list of all the selected nodes. We will use it to
# check what function will run depending on single or
# multiple selection.
def selectedNamesList():
    selected = nuke.selectedNodes()
    # We use a global variable to call it from other functions.
    global selNames
    selNames = []
    for i in selected:
        nodeName = i['name'].value()
        selNames.append(nodeName)
        selNames = sorted(selNames)


#####################################################################


# This function will run if there is just one node selected.
def duplicateNodeSimple():
    global selNames
    # Deselect all nodes.
    for node in nuke.allNodes():
        node['selected'].setValue(False)

    # We go through all the nodes of the global variable selNames.
    # We select each and save their X and Y positions.
    n = nuke.toNode(selNames[0])
    n['selected'].setValue(True)
    xpos = n.xpos()
    ypos = n.ypos()

    # We create an empty list and populate it with the node's
    # dependencies names (nodes connected to its inputs).
    dependenciesList = []
    for node in nuke.selectedNode().dependencies():
        depName = node.name()
        dependenciesList.append(depName)

    # We check the number of the highest input connected and use
    # it to populate an empty list with 1 (if the input in that
    # position is connected) and 0 (if it is not connected).
    # For example, if a Merge has A connected, but not B or mask,
    # the list would be [0,1].
    maxInputConnected = nuke.selectedNode().inputs()
    connectedList = []
    for i in range(maxInputConnected):
        connResult = 1 if nuke.selectedNode().input(i) else 0
        connectedList.append(connResult)
    # We also save the number of dependencies found
    depNumber = len(connectedList)

    # We copy the node, deselect it, paste the new one and
    # set its position apart from the original one.
    nuke.nodeCopy(nukescripts.cut_paste_file())
    n['selected'].setValue(False)
    nuke.nodePaste(nukescripts.cut_paste_file())
    nuke.selectedNode().setXYpos((xpos+90),(ypos+10))

    # We create two different counters: one for the number of
    # dependencies and another one for the number of
    # connections. A node can have two dependencies and three
    # connections, for example a Merge with B and Mask connected,
    # but not A, will have two dependencies (or one if B and Mask
    # are connected to the same node) and three connections (A
    # counts as a connection even if it is not connected).
    depCounter = 0
    connCounter = 0
    while connCounter <= (depNumber-1):
        # Using connectedList we created before, we connect
        # inputs to the correct node (if it is 1).
        if connectedList[connCounter] == 1:
            nuke.selectedNode().setInput(connCounter, nuke.toNode(str(dependenciesList[depCounter])))
            depCounter = depCounter + 1
            connCounter = connCounter + 1
        # Or leave them disconnected (if it is 0).
        elif connectedList[depCounter] == 0:
            connCounter = connCounter + 1
   
  # We could deselect the new node if we want to, but I preferred to
  # let it selected just in case you want to do more copies from it. 
  # for node in nuke.allNodes():
  #     node['selected'].setValue(False)

   # Delete stored variables.
   # del n
   # del xpos
   # del ypos
   # del selNames


#####################################################################


# This function will run if there is more than one node selected.
def duplicateNodeMulti():
    global selNames

    # We create an empty list and populate it with each node's
    # dependencies names (nodes connected to its inputs).    
    dependenciesList = []
    for node in selNames:
        nodeName = nuke.toNode(node)
        nodeName['selected'].setValue(True)
        for i in nodeName.dependencies():
            depName = i.name()
            dependenciesList.append(depName)
        nodeName['selected'].setValue(False)

    # Because we don't know if there will be any dependencies or not,
    # we will create an exception for IndexError just in case there
    # are no dependencies.
    try:
        # This variable will compare the list of selected nodes and
        # the list of the dependencies of each of those selected
        # nodes. The name present in dependenciesList that is not
        # present in selNames is the node we will need to connect
        # our duplicated node to.
        topConnNode = [item for item in dependenciesList if item not in selNames][0]

        # We check now all the nodes connected to the node we found in
        # previous list comparison.
        topNodeOutputList = []
        for node in nuke.toNode(topConnNode).dependent():
            topNodeOutputName = node.name()
            topNodeOutputList.append(topNodeOutputName)

        # And compared the new created list with the list of selected
        # nodes to find what is the first node to duplicate.    
        topToDuplicate = [item for item in topNodeOutputList if item in selNames][0]

        # Now that we have the first node located, we check its
        # dependencies and creat a list with all of them.
        nuke.toNode(topToDuplicate)['selected'].setValue(True)        
        nodeToDuplicateDepList = []
        for node in nuke.selectedNode().dependencies():
            depName = node.name()
            nodeToDuplicateDepList.append(depName)

        # If the list we just created has more than one element, it
        # means the node has more than 1 input connected.
        if len(nodeToDuplicateDepList) > 1:
            # We create a list of 1 (if the input is connected) and
            # 0 (if the input is not connected).
            maxInputConnected = nuke.selectedNode().inputs()
            connectedList = []
            for i in range(maxInputConnected):
                connResult = 1 if nuke.selectedNode().input(i) else 0
                connectedList.append(connResult)
            depNumber = len(connectedList)

            # We copy, deselect the first node, and paste the new one.
            nuke.nodeCopy(nukescripts.cut_paste_file())
            nuke.selectedNode()['selected'].setValue(False)
            nuke.nodePaste(nukescripts.cut_paste_file())

            # We create two different counters: one for the number of
            # dependencies and one for the number of connections.
            depCounter = 0
            connCounter = 0
            while connCounter <= (depNumber-1):
                # Using connectedList we created before, we connect
                # inputs to the correct node (if it is 1).
                if connectedList[connCounter] == 1:
                    nuke.selectedNode().setInput(connCounter, nuke.toNode(str(nodeToDuplicateDepList[depCounter])))
                    depCounter = depCounter + 1
                    connCounter = connCounter + 1
                # Or leave them disconnected (if the input is 0).
                elif connectedList[depCounter] == 0:
                    connCounter = connCounter + 1

            # We deselect the node we just pasted.
            topDuplicated = nuke.selectedNode().name()
            nuke.toNode(topDuplicated)['selected'].setValue(False)

            # We select all the nodes in our selNodes list, except
            # the one we already duplicated.
            for node in selNames:
                nodeName = nuke.toNode(node)
                if not nodeName['name'].getValue() == topToDuplicate:
                    nodeName['selected'].setValue(True)
            # We copy the selected nodes and deselect them.
            nuke.nodeCopy(nukescripts.cut_paste_file())
            for node in nuke.selectedNodes():
                node['selected'].setValue(False)
            # We select the node we already duplicated.
            nuke.toNode(topDuplicated)['selected'].setValue(True)
            # And paste the other nodes under it.
            nuke.nodePaste(nukescripts.cut_paste_file())
            nuke.toNode(topDuplicated)['selected'].setValue(True)

        # If the list we created before (nodeToDuplicateDepList) has
        # one element, it means the node has one input connected.
        else:
            # We copy, deselect, paste the new node and connect it.
            nuke.nodeCopy(nukescripts.cut_paste_file())
            nuke.toNode(topToDuplicate)['selected'].setValue(False)
            nuke.nodePaste(nukescripts.cut_paste_file())
            nuke.selectedNode().setInput(0, nuke.toNode(topConnNode))

            # We deselect the node we just pasted.
            topDuplicated = nuke.selectedNode().name()
            nuke.toNode(topDuplicated)['selected'].setValue(False)

            # We select all the nodes in our selNodes list, except
            # the one we already duplicated.
            for node in selNames:
                nodeName = nuke.toNode(node)
                if not nodeName['name'].getValue() == topToDuplicate:
                    nodeName['selected'].setValue(True)
            # We copy the selected nodes and deselect them.
            nuke.nodeCopy(nukescripts.cut_paste_file())
            for node in nuke.selectedNodes():
                node['selected'].setValue(False)
            # We select the node we already duplicated.
            nuke.toNode(topDuplicated)['selected'].setValue(True)
            # And paste the other nodes under it.
            nuke.nodePaste(nukescripts.cut_paste_file())
            nuke.toNode(topDuplicated)['selected'].setValue(True)

    # If there the selection is not connected to anything, we will
    # have an IndexError. In that case:
    except IndexError:
        # We select every node of our original selection.
        for node in selNames:
            nodeName = nuke.toNode(node)
            nodeName['selected'].setValue(True)
        # Copy and deselect the original nodes.
        nuke.nodeCopy(nukescripts.cut_paste_file())
        for node in nuke.selectedNodes():
           node['selected'].setValue(False)
        # And paste the new ones.
        nuke.nodePaste(nukescripts.cut_paste_file())


#####################################################################


# We use this function to know how many nodes we selected, and apply
# one function or another depending on this number.
def duplicateNodeCheck():
    selectedNamesList()
    global selNames
    if len(selNames) < 1:
        nuke.message('Please, select one or more nodes to duplicate.')
    elif len(selNames) > 1:
        duplicateNodeMulti()
    else:
        duplicateNodeSimple()

Javier Nieto Moncó © 2025

  • linkedin
  • vimeo
  • generic-social-link
bottom of page