Substance Designer - output node metadata get/set

This comes from the Adobe discord when I asked how to get/set metadata on the output nodes of a graph (so I could set an “exportable” kvp on it for an export tool)

The metadata on outputs is really weird, technically it’s stored at the graph level rather than on the node. If you get its output property then use that as an ID in the graph you should be able to get the metadata and then add to or query it as desired. Once you have that metadata object you should be able to metadata.setPropertyValueFromId('key', SDValueString.sNew('value') or get the value from its ID.

propertyOut = sdNodeOutput.getProperties(SDPropertyCategory.Output)[0]
metadata = sdGraph.getPropertyMetadataDictFromId(propertyOut.getId(), SDPropertyCategory.Output)

With this in mind I’ve made these simple functions that can likely be reused fairly easily :slight_smile:

import sd
from sd.api import SDValueString
from sd.api.sdproperty import SDPropertyCategory
ctx = sd.getContext()
app = ctx.getSDApplication()
uiMgr = app.getQtForPythonUIMgr()


def curr_graph():
    graph = uiMgr.getCurrentGraph()
    return graph

def get_all_metadata_from_node(sdNodeOutput):
    """Get the metadata object from a given output node

    Args:
        sdNodeOutput (SDSBSCompNode): output node to get metadata from

    Returns:
        SDMetadataDict: metadata object from node
    """        
    propertyOut = sdNodeOutput.getProperties(SDPropertyCategory.Output)[0]
    metadata = curr_graph.getPropertyMetadataDictFromId(
        propertyOut.getId(), SDPropertyCategory.Output
    )
    return metadata

def get_metadata_value_from_node(sdNodeOutput, key):
    """Try to get the metadata value from a given node and key

    Args:
        sdNodeOutput (SDSBSCompNode): output node to check for metadata on
        key (str): key of metadata object

    Returns:
        str, None: If key is found, return value else None
    """        
    metadata = get_all_metadata_from_node(sdNodeOutput)
    try:
        return metadata.getPropertyValueFromId(key).get()
    except:
        # bare except as we just want it to not error if it doesn't find anything
        # or "invalidArgument" is passed - which it shouldn't
        print(
            f"Key: {key} not found in metadata of "
            f"{sdNodeOutput.getAnnotationPropertyValueFromId('label').get()}"
        )
    return None

def set_metadata_on_node(sdNodeOutput, key, value):
    """Given a node and key/value - set it on the node's metadata object

    Args:
        sdNodeOutput (sdNode): Node to set data on
        key (str): key to store
        value (str): value (as string) to set
    """        
    metadata = get_all_metadata_from_node(sdNodeOutput)
    metadata.setPropertyValueFromId(key, SDValueString.sNew(value))

Figured it was worth sharing and having somewhere online

1 Like