Skip to content

Instantly share code, notes, and snippets.

@teared
Last active July 6, 2019 15:07
Show Gist options
  • Save teared/189cd2c500a9e7adadb1 to your computer and use it in GitHub Desktop.
Save teared/189cd2c500a9e7adadb1 to your computer and use it in GitHub Desktop.
System addon bringing to Blender a Houdini-like saving system. Every save a versioned copy of the current scene moved into the backup folder in the current scene directory.
# System addon bringing to Blender a Houdini-like saving system. Every save a
# versioned copy of the current scene moved into the backup folder in the
# current scene directory.
#
# Install from Blender User Preferences → Add-ons via the Install from File
# button, then tick the checkbox near the Backup and Save add-on. Searching by
# name is useful here. After that, the Backup and Save operation can be found in
# space bar menu. Navigate to Blender User Preferences → File and set Save
# Versions to 0. It disables .blend1 files creation on each save which is a
# backup system itself. No need to use it anymore. Remove the Ctrl S shortcut
# binded to the "Save Blender File" operation.
bl_info = {
"name": "Backup and Save",
"description": "Copy current Blender file to the ./backup folder and save.",
"version": (1, 0),
"blender": (2, 74, 0),
"category": "System"
}
import os
import re
import shutil
import bpy
class BackupAndSave(bpy.types.Operator):
"""Copy current Blender file to the ./backup folder and save"""
bl_idname = "wm.backup_and_save"
bl_label = "Backup and Save"
def execute(self, context):
src_path = bpy.data.filepath
# If file not exist, perform a normal save.
if not os.path.exists(src_path):
bpy.ops.wm.save_mainfile('INVOKE_DEFAULT')
return {'CANCELLED'}
# Otherwise, create proper backup path.
src_file = os.path.basename(src_path)
src_name, _ = os.path.splitext(src_file)
src_dir = os.path.dirname(src_path)
bak_dir = os.path.join(src_dir, "backup")
# Compute bak number.
if os.path.exists(bak_dir):
# Find maximum bak number from existing backups.
num = 0
for f in os.listdir(bak_dir):
if not f.startswith(src_name + "_bak"):
continue
match = re.search(r".*_bak([0-9]+)\.blend", f)
if not match:
continue
match_num = int(match.group(1))
num = max(num, match_num)
bak_num = num + 1
else:
os.mkdir(bak_dir)
bak_num = 1
bak_file = "{}_bak{}.blend".format(src_name, bak_num)
bak_path = os.path.join(bak_dir, bak_file)
# Backup file and save.
shutil.copy2(src_path, bak_path)
bpy.ops.wm.save_mainfile()
return {'FINISHED'}
# store keymaps here to access after registration
addon_keymaps = []
def register():
bpy.utils.register_class(BackupAndSave)
# handle the keymap
wm = bpy.context.window_manager
km = wm.keyconfigs.addon.keymaps.new(name='Window', space_type='EMPTY')
kmi = km.keymap_items.new(BackupAndSave.bl_idname, 'S', 'PRESS', ctrl=True)
addon_keymaps.append(km)
def unregister():
bpy.utils.unregister_class(BackupAndSave)
# handle the keymap
wm = bpy.context.window_manager
for km in addon_keymaps:
wm.keyconfigs.addon.keymaps.remove(km)
addon_keymaps.clear()
if __name__ == "__main__":
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment