Blender 4.1 addon to add time to rendered file names

I’m trying to make an addon for Blender 4.1 that adds current seconds to rendered file name. We need it for our workflow when rendering overnight, to check later which frames had the biggest gap between seconds. We’ve tried other solutions and settled for this one.

Addon works perfectly in the main output filepath, in the Output Properties.

  1. I specify output path - “//@second@_”
  2. When I hit render, addon stores the original filepath “//@second@_”
  3. Addon replaces @second@ with the current second
  4. Blender render out an image with a file name “41_0001.png”
  5. Addon restores the original filepath “//@second@_”

The problem is when I need to render other passes (alpha) in the Compositor’s File Output node.

  1. I specify output path - “//@second@”
  2. When I hit render, I can see in Blender UI that the addon replaces @second@ with the current second
  3. Blender creates a folder named “@second@”
  4. Addon restores the original filepath “//@second@”

For the actual pass (alpha) files:

  1. In the Compositor’s sidebar in the File Subpath I specify output path - “//@second@alpha
  2. When I hit render, I can see in Blender UI that the addon replaces @second@ with the current second
  3. In the folder named “@second@” Blender creates a file named “@second@_alpha_0001.png”
  4. Addon restores the original filepath “//@second@alpha

What I need the structure to look like:

Either:

folder named “41” with files “41_0001.png”, “43_0002.png”, “45_0003.png”

Or:

folder named “41” with file “41_0001.png”

folder named “43” with file “43_0002.png”

folder named “45” with file “45_0003.png”

Can someone help me please?

My code here:

import bpy
from bpy.app.handlers import persistent
from datetime import datetime

# Store the original file paths
original_file_paths = {
    "render_file_path": "",
    "node_base_paths": {},
    "file_slot_paths": {}
}

@persistent
def replace_seconds(scene):
    global original_file_paths
    # Store the original render file path with @second@
    original_file_paths["render_file_path"] = scene.render.filepath

# Get the project name from the .blend file name
    project_name = bpy.path.basename(bpy.data.filepath).rpartition('.')[0]

    # Get the current date and time
    from datetime import datetime
    now = datetime.now()

    # Replace @second@ in the render file path
    scene.render.filepath = scene.render.filepath.replace("@second@", str(now.second).zfill(2))

    # Replace @second@ for Compositor File Output nodes
    for node in scene.node_tree.nodes:
        if node.type == 'OUTPUT_FILE':
            # Store the original node base path
            original_file_paths["node_base_paths"][node.name] = node.base_path
            # Replace @second@ in the node base path
            node.base_path = node.base_path.replace("@second@", str(now.second).zfill(2))
            for file_slot in node.file_slots:
                # Store the original file slot path with the modified path as the key
                original_file_paths["file_slot_paths"][file_slot.path.replace("@second@", str(now.second).zfill(2))] = file_slot.path
                # Replace @second@ in the file slot path
                file_slot.path = file_slot.path.replace("@second@", str(now.second).zfill(2))

@persistent
def restore_seconds(scene):
    global original_file_paths
    # Restore the original render file path with @second@
    scene.render.filepath = original_file_paths["render_file_path"]

# Restore the original node base paths with @second@
    for node in bpy.context.scene.node_tree.nodes:
        if node.type == 'OUTPUT_FILE':
            node.base_path = original_file_paths["node_base_paths"].get(node.name, "")
            # Restore the original file slot paths with @second@
            for file_slot in node.file_slots:
                # Use the modified path to get the original path
                file_slot.path = original_file_paths["file_slot_paths"].get(file_slot.path, "")

def register():
    # Make sure to clear any existing handlers to avoid duplicates
    bpy.app.handlers.render_pre.clear()
    bpy.app.handlers.render_post.clear()

    # Register the handlers to trigger before and after each frame
    bpy.app.handlers.render_pre.append(replace_seconds)
    bpy.app.handlers.render_post.append(restore_seconds)

def unregister():
    bpy.app.handlers.render_pre.remove(replace_seconds)
    bpy.app.handlers.render_post.remove(restore_seconds)

if __name__ == "__main__":
    register()

1 Like

May i ask why need an addon for this andl not simply compare the file date-time-stamps ?

I mean: you surely do read the "file-names" with added seconds, extract the number from the string, convert it to numbers and then compare the differences between them afterwards…
…so why not compare two "file dates" and get the time difference directly within your analyzing app?

There are more processes following that, it’s just one part of the workflow. That’s why we need to find a solution to this problem :slight_smile: