Skip to content

Instantly share code, notes, and snippets.

@robertguetzkow
Last active August 26, 2024 19:49
Show Gist options
  • Save robertguetzkow/8dacd4b565538d657b72efcaf0afe07e to your computer and use it in GitHub Desktop.
Save robertguetzkow/8dacd4b565538d657b72efcaf0afe07e to your computer and use it in GitHub Desktop.
Blender add-on for automatic unique output path generation based on the current timestamp
bl_info = {
"name": "Auto-Filepath",
"author": "Robert Guetzkow",
"version": (1, 0, 2),
"blender": (2, 80, 0),
"location": "Output Properties > Auto-filepath",
"description": "Automatically sets a unique filepath for each frame based on the current timestamp.",
"warning": "",
"wiki_url": "",
"category": "Render"}
import bpy
import datetime
from pathlib import Path
from bpy.app.handlers import persistent
@persistent
def update_filepath(self):
if not bpy.context.scene.auto_filepath_settings.use_auto_filepath:
return
now = datetime.datetime.now()
path = Path(bpy.context.scene.auto_filepath_settings.directory)
base_path = path / now.strftime('%Y-%m-%d_%H_%M_%S_%f')
bpy.context.scene.render.filepath = str(base_path / "####")
bpy.context.scene.render.use_file_extension = True
bpy.context.scene.render.use_overwrite = False
if bpy.context.scene.use_nodes:
for node in bpy.context.scene.node_tree.nodes:
if node.type == "OUTPUT_FILE":
node.base_path = str(base_path / node.name)
def set_directory(self, value):
path = Path(value)
if path.is_dir():
self["directory"] = value
def get_directory(self):
return self.get("directory", bpy.context.scene.auto_filepath_settings.bl_rna.properties["directory"].default)
class AutoFilepathSettings(bpy.types.PropertyGroup):
use_auto_filepath: bpy.props.BoolProperty(name="Automatic filepath generation.",
description="Enable/disable automatic filepath generation. When enabled, "
"this will overwrite the output path and the base path of "
"all File Output nodes.",
default=False)
directory: bpy.props.StringProperty(name="Directory",
description="Directory where files shall be stored.",
default="/",
maxlen=4096,
subtype="DIR_PATH",
set=set_directory,
get=get_directory)
class AUTOFILEPATH_PT_panel(bpy.types.Panel):
bl_label = "Auto-Filepath"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "output"
bl_options = {"DEFAULT_CLOSED"}
def draw_header(self, context):
self.layout.prop(context.scene.auto_filepath_settings, "use_auto_filepath", text="")
def draw(self, context):
layout = self.layout
layout.prop(context.scene.auto_filepath_settings, "directory")
classes = (AutoFilepathSettings, AUTOFILEPATH_PT_panel)
def register():
for cls in classes:
bpy.utils.register_class(cls)
bpy.types.Scene.auto_filepath_settings = bpy.props.PointerProperty(type=AutoFilepathSettings)
if update_filepath not in bpy.app.handlers.render_pre:
bpy.app.handlers.render_pre.append(update_filepath)
def unregister():
for cls in classes:
bpy.utils.unregister_class(cls)
del bpy.types.Scene.auto_filepath_settings
if update_filepath in bpy.app.handlers.render_pre:
bpy.app.handlers.render_pre.remove(update_filepath)
if __name__ == "__main__":
register()
@QuietNoise
Copy link

QuietNoise commented Dec 17, 2023

Here is my take on this. Rather than generating new folder for each image I just save images with timestamps in filename.
https://gist.github.com/QuietNoise/c56c5f4bf1e42238928bf2cef481cde0

@robertguetzkow
Copy link
Author

@QuietNoise I think I originally wrote this for animations, hence the separate folder. Thanks for leaving a link to the adapted version, might be useful for someone looking at the old question on Stack Exchange.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment