Last active
July 6, 2019 15:07
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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