Can you create a Metadata or Text node from a batch python script?

I’m trying to figure out a way to take a clip and automatically create the slate info as an overlay node (either a text node or a Metadata node) from it but I can’t figure out from the API if there is a way to create such a node. Anybody know?

Hey Elad!

It’s definitely possible. But not all through the API. The way I’ve done it in the past is to save out a metadata node setup to use as a template of what info you want in the slate and the positioning of it. Then using python create a copy of that template setup and insert whatever custom shot data you need into that template setup, then through the API load it into your metadata node. A similar process could be done with the text node. Although using the metadata node would probably be easier.

Mike

1 Like

Thanks Mike! I figured that might need to be the way to go about it. Although I can’t even figure out which call would load the data into the node.

I guess the other end of the question is, is there a way to grab all the pertinent information from a clip? like the length, etc, or other information from the batch as well like the batch iteration etc? I’m having a hard time figuring all that out from the API documentation.

Yea… the API doc’s are a struggle sometimes for sure.

To create a metadata node and load a setup you can do this:

metadata_node = flame.batch.create_node(‘burn-in metadata’)
metadata_node.load_node_setup(path_to_metadata_setup)

To get the batch duration:

flame.batch.duration

To get the batch iteration:

flame.batch.current_iteration.name

1 Like

You the best Mike!

me again… apologies… I’ve collected out all the data I need but how do I access the files for the metadata node on the filesystem to revise the data? Any chance you’re willing to send me what you did as an example?

Sure. The script is a couple years old and written for python 2.7. I would probably do a couple things differently if I was writing it now.

If you’re using Flame 2022 or newer just adding some parenthesis around the print statements should get it working.

What the script did was allow you to set off a render by right clicking in batch but while also updating the slate info in the metadata node(metadata node would have to be named ‘slate info’ for the right-click menu to appear). I would have a template metadata node setup in the default flame project burnmetadata node folder that the script would look for… this could be changed to be wherever though. The template would have everything setup with the way you want to have the slate look. Except in the fields where the things like the date, duration, version would go, I would put tokens that get replaced by the script. In this case %Version% and %Date%. So you could have a Custom Text layer with a line like this in the node:

Date: %Date%

and it would get changed to:

Date: 06/13/22

The replace_tokens function is where the tokens the script looks for can be added/changed. After it looks for all the tokens, it writes out a temp file that then gets loaded back into the ‘slate_info’ metadata node.

Hope it helps.

burnmetadata_template.burnmetadata_node.zip (1.2 KB)

def update_burnin_node():
    import datetime
    import flame
    import os

    def project_path():
        import re

        flame_prj_name = flame.project.current_project.project_name
        print 'flame_prj_name:', flame_prj_name

        with open('/opt/Autodesk/project/project.db', 'r') as project_db:
            for line in project_db:
                if ':' + flame_prj_name + '=' in line:
                    save_path = re.search('SetupDir="(.*)",Partition', line)
                    save_path = save_path.group(1)

        print 'save path:', save_path

        return save_path

    def edit_template():

        def replace_tokens():
            import re

            token_dict = {}

            token_dict['%Version%'] = batch_iteration
            token_dict['%Date%'] = date

            # Replace tokens in menu template

            for key, value in token_dict.items():
                for line in template_lines:
                    if key in line:
                        line_index = template_lines.index(line)
                        new_line = re.sub(key, value, line)
                        template_lines[line_index] = new_line

        # Read template

        burn_in_setup = open(template_path, 'r')
        template_lines = burn_in_setup.read().splitlines()

        # Replace tokens in template

        replace_tokens()

        # Write out temp node

        out_file = open(temp_burn_in_file, 'w')
        for line in template_lines:
            print >>out_file, line
        out_file.close()

    def load_burn_in_node():

        burn_in_node.load_node_setup(temp_burn_in_file)

    # Get current project path

    template_path = '%s/burnmetadata/flame/slate_info.burnmetadata_node' % project_path()
    print 'template_path:', template_path

    temp_burn_in_file = '/opt/Autodesk/shared/python/update_slate/temp.burnmetadata_node'

    batch_iteration = str(flame.batch.current_iteration.name)[1:-1]
    print 'batch_iteration:', batch_iteration

    now = datetime.datetime.now()
    date = now.strftime('%m/%d/%y')
    print 'date: ', date

    for node in flame.batch.nodes:
        if node.name == 'slate_info':
            burn_in_node = node

            edit_template()

            load_burn_in_node()

    os.remove(temp_burn_in_file)

def update_slate(selection):

    update_burnin_node()

    print '\n>>> slate updated <<<\n'

def update_slate_render(selection):
    import flame

    update_burnin_node()

    flame.batch.render()

    print '\n>>> slate updated <<<\n'

def update_slate_burn(selection):
    import flame

    update_burnin_node()

    flame.batch.render(render_option='Burn')

    print '\n>>> slate updated <<<\n'

def scope_slate_info(selection):
    import flame

    for n in flame.batch.nodes:
        if n.name == 'slate_info':
            return True
    return False

def get_batch_custom_ui_actions():

    return [
        {
            'name': 'Slate...',
            'actions': [
                {
                    'name': 'Update Slate',
                    'isVisible': scope_slate_info,
                    'execute': update_slate,
                    'minimumVersion': '2020'
                },
                {
                    'name': 'Update Slate and Render',
                    'isVisible': scope_slate_info,
                    'execute': update_slate_render,
                    'minimumVersion': '2020'
                },
                {
                    'name': 'Update Slate and Burn',
                    'isVisible': scope_slate_info,
                    'execute': update_slate_burn,
                    'minimumVersion': '2020'
                }
            ]
        }
    ]

Thanks so much Mike! I just needed an example to follow :blush:.



Image removed by sender.

|

MikeV patron of Logik
June 14

|

  • | - |

Sure. The script is a couple years old and written for python 2.7. I would probably do a couple things differently if I was writing it now.

If you’re using Flame 2022 or newer just adding some parenthesis around the print statements should get it working.

What the script did was allow you to set off a render by right clicking in batch but while also updating the slate info in the metadata node(metadata node would have to be named ‘slate info’ for the right-click menu to appear). I would have a template metadata node setup in the default flame project burnmetadata node folder that the script would look for… this could be changed to be wherever though. The template would have everything setup with the way you want to have the slate look. Except in the fields where the things like the date, duration, version would go, I would put tokens that get replaced by the script. In this case %Version% and %Date%. So you could have a Custom Text layer with a line like this in the node:

Date: %Date%

and it would get changed to:

The replace_tokens function is where the tokens the script looks for can be added/changed. After it looks for all the tokens, it writes out a temp file that then gets loaded back into the ‘slate_info’ metadata node.

Hope it helps.

burnmetadata_template.burnmetadata_node.zip (1.2 KB)

def update_burnin_node():

    import datetime

    import flame

    import os



    def project_path():

        import re



        flame_prj_name = flame.project.current_project.project_name

        print 'flame_prj_name:', flame_prj_name



        with open('/opt/Autodesk/project/project.db', 'r') as project_db:

            for line in project_db:

                if ':' + flame_prj_name + '=' in line:

                    save_path = re.search('SetupDir="(.*)",Partition', line)

                    save_path = save_path.group(1)



        print 'save path:', save_path



        return save_path



    def edit_template():



        def replace_tokens():

            import re



            token_dict = {}



            token_dict['%Version%'] = batch_iteration

            token_dict['%Date%'] = date



            # Replace tokens in menu template



            for key, value in token_dict.items():

                for line in template_lines:

                    if key in line:

                        line_index = template_lines.index(line)

                        new_line = re.sub(key, value, line)

                        template_lines[line_index] = new_line



        # Read template



        burn_in_setup = open(template_path, 'r')

        template_lines = burn_in_setup.read().splitlines()



        # Replace tokens in template



        replace_tokens()



        # Write out temp node



        out_file = open(temp_burn_in_file, 'w')

        for line in template_lines:

            print >>out_file, line

        out_file.close()



    def load_burn_in_node():



        burn_in_node.load_node_setup(temp_burn_in_file)



    # Get current project path



    template_path = '%s/burnmetadata/flame/slate_info.burnmetadata_node' % project_path()

    print 'template_path:', template_path



    temp_burn_in_file = '/opt/Autodesk/shared/python/update_slate/temp.burnmetadata_node'



    batch_iteration = str(flame.batch.current_iteration.name)[1:-1]

    print 'batch_iteration:', batch_iteration



    now = datetime.datetime.now()

    date = now.strftime('%m/%d/%y')

    print 'date: ', date



    for node in flame.batch.nodes:

        if node.name == 'slate_info':

            burn_in_node = node



            edit_template()



            load_burn_in_node()



    os.remove(temp_burn_in_file)



def update_slate(selection):



    update_burnin_node()



    print '\n>>> slate updated <<<\n'



def update_slate_render(selection):

    import flame



    update_burnin_node()



    flame.batch.render()



    print '\n>>> slate updated <<<\n'



def update_slate_burn(selection):

    import flame



    update_burnin_node()



    flame.batch.render(render_option='Burn')



    print '\n>>> slate updated <<<\n'



def scope_slate_info(selection):

    import flame



    for n in flame.batch.nodes:

        if n.name == 'slate_info':

            return True

    return False



def get_batch_custom_ui_actions():



    return [

        {

            'name': 'Slate...',

            'actions': [

                {

                    'name': 'Update Slate',

                    'isVisible': scope_slate_info,

                    'execute': update_slate,

                    'minimumVersion': '2020'

                },

                {

                    'name': 'Update Slate and Render',

                    'isVisible': scope_slate_info,

                    'execute': update_slate_render,

                    'minimumVersion': '2020'

                },

                {

                    'name': 'Update Slate and Burn',

                    'isVisible': scope_slate_info,

                    'execute': update_slate_burn,

                    'minimumVersion': '2020'

                }

            ]

        }

    ]



1 Like

That worked perfectly! I was able to revise it to make it work and it taught me some stuff!
Another follow up question - is there a direct way to get the current batch iteration number or do I need to get the iteration list and grab the last one and get that one’s iteration number? do you know?
Tell me to fuck off any time I get annoying with these question btw…

Glad to hear it helped out. Doing something like this might get you what you’re looking for as far as the batch iterations on your currently open batch:

print(flame.batch.current_iteration.name)
print(flame.batch.batch_iterations[-1].name)

current_iteration and batch_iterations can also be applied to any batch group selection.

The funny thing about that is that it gives the full name and I can even get the formatting text from token_name but it doesn’t seem like there is a way to just get the iteration number other than as its place in the iterations list. Not hard to do but seems to me a little odd that it isn’t an exposed value.

You could get the iteration number in an indirect way via the WriteFile node attributes.

def get_current_iteration_number():
    import flame
    dummy_node = flame.batch.create_node("Write File")
    dummy_node.version_mode = "Follow Iteration"
    number = dummy_node.version_number.get_value()
    flame.delete(dummy_node)
    return number
2 Likes