7

Blender is by default config to save backup file from previous saves like .blender1, .blender2 and this is a good thing in case you mess up. What i want is to config blender to place this specific files in a subdirectory. Right now they show up in the list of blender files and make the list really long if you have a few scenes. Is it possible to config blender to do this?

Illustration of the structure.

.blender_folder
..Backup
...file1.blender1
...file1.blender2
...file2.blender1
...file2.blender2
..file1.blender
..file2.blender
Dragon Creature
  • 173
  • 1
  • 5

5 Answers5

10

I took a little time writing an addon for Blender, which will move the backup save files to a sub directory every time you save. You may change it however you want it to work.

I hope it works for you guys. :)

Simply save the code below into a file called something .py, I called mine "blender_move_backup_save_files_to_a_sub_directory.py".

Then import the file by clicking: File > User Preferences > Addons > Install From File... > Finally select the file and activate the addon.

bl_info = {
    "version": (1, 3),
    "blender": (2, 68, 0),
    "name": "Move Backup Save Files To A Sub Directory",
    "author": "Jonathan Stroem",
    "description": """Move the backup save files to a sub-directory instead of the Blender-file's current directory. A new folder called "backup.blend" will be created and all save-files will be moved there instead of the default folder.""" ,
    "category": "System",
    "location": """The backup folder will be named "backup.blend". Under 'File > User Preferences > File > Save Versions', you can change how many backups that'll be used.""",
    }

#IMPORTS
import bpy, os
import shutil
from bpy.app.handlers import persistent

import time
from stat import *

#When enabling the addon.
def register():
    bpy.app.handlers.save_post.append(move_handler)

#When disabling the addon.
def unregister():
    bpy.app.handlers.save_post.remove(move_handler)

#So that Blender recognize it as an addon.
if __name__ == "__main__":
    register()

@persistent
def move_handler(dummy):

    #fullpath = Full path to the data file.
    #directory = Directory the data file is in.
    #name = Name of file, without extension.
    #extension = Extension of files.
    #backup_amount = Max amount of backups to store.
    #backup_directory = The name of the backup directory. (Where the files should be moved.) So change this if you want to change where the backups are saved.

    file = {"fullpath":bpy.data.filepath, \
            "directory":os.path.dirname(bpy.data.filepath), \
            "name":bpy.path.display_name_from_filepath(bpy.data.filepath), \
            "extension":".blend", \
            "backup_amount":bpy.context.user_preferences.filepaths.save_version, \
            "backup_directory":"backup.blend" \
            }

    #Create backup directory if it doesn't exist.
    if file["backup_directory"] not in os.listdir(file["directory"]) :
        os.chdir(file["directory"])
        os.mkdir(file["backup_directory"])

    #Get current save files from the backup directory.
    currentFiles = []
    for f in [ f for f in os.listdir(file["directory"] + "\\" + file["backup_directory"]) for c in range(1, int(file["backup_amount"]) + 1) if f == file["name"] + file["extension"] + str(c) if os.path.isfile(os.path.join(file["directory"] + "\\" + file["backup_directory"], f)) ] :
        currentFiles.append(f)

    #All this is moving the correct file.
    if len(currentFiles) < 1 : #If no files, then no need to check.
        if os.path.isfile(file["fullpath"] + "1") :
            shutil.move(file["fullpath"] + "1", file["directory"] + "\\" + file["backup_directory"] + "\\" + file["name"] + ".blend1")
    else : #If the max backup amount has been reached, then check for the oldest file and overwrite that one.
        if file["backup_amount"] <= len(currentFiles) :
            replaceFile = {"modified_date":None, \
                           "fullname":""}
            for f in currentFiles :
                stats = os.stat(file["directory"] + "\\" + file["backup_directory"] + "\\" + f) #Get attributes from a file.
                if replaceFile["fullname"] == "" : #This will happen only the first time.
                    replaceFile["fullname"] = f
                    replaceFile["modified_date"] = time.asctime(time.localtime(stats[ST_MTIME]))
                else : # Is the previous file older or newer? If it's older, then you'd want to overwrite that one instead. Go through all backup-files.
                    temp_modified = time.asctime(time.localtime(stats[ST_MTIME]))
                    if replaceFile["modified_date"] > temp_modified :
                        replaceFile["fullname"] = f
                        replaceFile["modified_date"] = temp_modified

            #When the loop is finished, the oldest file has been found, and will be overwritten.
            shutil.move(file["fullpath"] + "1", file["directory"] + "\\" + file["backup_directory"] + "\\" + replaceFile["fullname"])
        else : #If the max backup amount hasn't been reached, and the folder isn't empty.
            #Then check for the next number, and then just move the file over with the correct number.
            replaceFile = "" #Location.
            for f in currentFiles :
                for c in range(1, int(file["backup_amount"]) + 1) :
                    if not os.path.isfile(file["directory"] + "\\" + file["backup_directory"] + "\\" + file["name"] + file["extension"] + str(c)) :
                        shutil.move(file["fullpath"] + "1", file["directory"] + "\\" + file["backup_directory"] + "\\" + file["name"] + file["extension"] + str(c))
                        replaceFile = f
                        break
                if replaceFile != "" : #File to replace has been found, break out.
                    break


#This document is licensed according to GNU Global Public License v3.
Jonathan
  • 216
  • 1
  • 3
2

First of all, thank you Jonathan for writing this script. I'm much happier with this arrangement of backup files!

It didn't work out of the box on my Mac because the some of the OS paths were constructed with hard-coded Windows backslashes, so I went in and changed them to be platform independent.

I hope this is helpful to someone. Since I hadn't seen any later versions of this script, I went ahead and advanced the version #.

bl_info = {
    "version": (1, 4),
    "blender": (2, 68, 0),
    "name": "Move Backup Save Files To A Sub Directory",
    "author": "Jonathan Stroem",
    "description": """Move the backup save files to a sub-directory instead of the Blender-file's current directory. A new folder called "backup.blend" will be created and all save-files will be moved there instead of the default folder.""" ,
    "category": "System",
    "location": """The backup folder will be named "backup.blend". Under 'File > User Preferences > File > Save Versions', you can change how many backups that'll be used.""",
    }

#IMPORTS
import bpy, os
import shutil
from bpy.app.handlers import persistent

import time
from stat import *

#When enabling the addon.
def register():
    bpy.app.handlers.save_post.append(move_handler)

#When disabling the addon.
def unregister():
    bpy.app.handlers.save_post.remove(move_handler)

#So that Blender recognize it as an addon.
if __name__ == "__main__":
    register()

@persistent
def move_handler(dummy):

    #fullpath = Full path to the data file.
    #directory = Directory the data file is in.
    #name = Name of file, without extension.
    #extension = Extension of files.
    #backup_amount = Max amount of backups to store.
    #backup_directory = The name of the backup directory. (Where the files should be moved.) So change this if you want to change where the backups are saved.

    file = {"fullpath":bpy.data.filepath, \
            "directory":os.path.dirname(bpy.data.filepath), \
            "name":bpy.path.display_name_from_filepath(bpy.data.filepath), \
            "extension":".blend", \
            "backup_amount":bpy.context.user_preferences.filepaths.save_version, \
            "backup_directory":"backup.blend" \
            }

    #Create backup directory if it doesn't exist.
    if file["backup_directory"] not in os.listdir(file["directory"]) :
        os.chdir(file["directory"])
        os.mkdir(file["backup_directory"])

    #Get current save files from the backup directory.
    currentFiles = []
    for f in [ f for f in os.listdir(os.path.join(file["directory"], file["backup_directory"])) for c in range(1, int(file["backup_amount"]) + 1) if f == file["name"] + file["extension"] + str(c) if os.path.isfile(os.path.join(file["directory"], file["backup_directory"], f)) ] :
        currentFiles.append(f)

    #All this is moving the correct file.
    if len(currentFiles) < 1 : #If no files, then no need to check.
        if os.path.isfile(file["fullpath"] + "1") :
            shutil.move(file["fullpath"] + "1", os.path.join(file["directory"], file["backup_directory"], file["name"] + ".blend1"))
    else : #If the max backup amount has been reached, then check for the oldest file and overwrite that one.
        if file["backup_amount"] <= len(currentFiles) :
            replaceFile = {"modified_date":None, \
                           "fullname":""}
            for f in currentFiles :
                stats = os.stat(os.path.join(file["directory"], file["backup_directory"], f)) #Get attributes from a file.
                if replaceFile["fullname"] == "" : #This will happen only the first time.
                    replaceFile["fullname"] = f
                    replaceFile["modified_date"] = time.asctime(time.localtime(stats[ST_MTIME]))
                else : # Is the previous file older or newer? If it's older, then you'd want to overwrite that one instead. Go through all backup-files.
                    temp_modified = time.asctime(time.localtime(stats[ST_MTIME]))
                    if replaceFile["modified_date"] > temp_modified :
                        replaceFile["fullname"] = f
                        replaceFile["modified_date"] = temp_modified

            #When the loop is finished, the oldest file has been found, and will be overwritten.
            shutil.move(file["fullpath"] + "1", os.path.join(file["directory"], file["backup_directory"], replaceFile["fullname"]))
        else : #If the max backup amount hasn't been reached, and the folder isn't empty.
            #Then check for the next number, and then just move the file over with the correct number.
            replaceFile = "" #Location.
            for f in currentFiles :
                for c in range(1, int(file["backup_amount"]) + 1) :
                    if not os.path.isfile(os.path.join(file["directory"], file["backup_directory"], file["name"] + file["extension"] + str(c))) :
                        shutil.move(file["fullpath"] + "1", os.path.join(file["directory"], file["backup_directory"], file["name"] + file["extension"] + str(c)))
                        replaceFile = f
                        break
                if replaceFile != "" : #File to replace has been found, break out.
                    break


#This document is licensed according to GNU Global Public License v3.
Paul Mohr
  • 21
  • 1
1

with this change that work for me on Linux.

bl_info = {
    "version": (1, 3, 1),
    "blender": (3, 0, 0),
    "name": "Move Backup Save Files To A Sub Directory",
    "author": "Jonathan Stroem",
    "description": """Move the backup save files to a sub-directory instead of the Blender-file's current directory. A new folder called "backup.blend" will be created and all save-files will be moved there instead of the default folder.""" ,
    "category": "System",
    "location": """The backup folder will be named "backup.blend". Under 'File > User Preferences > File > Save Versions', you can change how many backups that'll be used.""",
    }

import bpy, os import shutil from bpy.app.handlers import persistent

import time from stat import *

def register(): bpy.app.handlers.save_post.append(move_handler)

def unregister(): bpy.app.handlers.save_post.remove(move_handler)

if name == "main": register()

@persistent def move_handler(dummy):

file = {&quot;fullpath&quot;:bpy.data.filepath, \
        &quot;directory&quot;:os.path.dirname(bpy.data.filepath), \
        &quot;name&quot;:bpy.path.display_name_from_filepath(bpy.data.filepath), \
        &quot;extension&quot;:&quot;.blend&quot;, \
        &quot;backup_amount&quot;:bpy.context.preferences.filepaths.save_version, \
        &quot;backup_directory&quot;:&quot;backup&quot; \
        }
if file[&quot;backup_directory&quot;] not in os.listdir(file[&quot;directory&quot;]) :
    os.chdir(file[&quot;directory&quot;])
    os.mkdir(file[&quot;backup_directory&quot;])
currentFiles = []
for f in [ f for f in os.listdir(os.path.dirname(bpy.data.filepath) + &quot;/&quot; + &quot;backup&quot;) ] :
    for c in range(1, int(bpy.context.preferences.filepaths.save_version) + 1) :
        if f == bpy.path.display_name_from_filepath(bpy.data.filepath) + &quot;.blend&quot; + str(c) :
            if os.path.isfile(os.path.join(os.path.dirname(bpy.data.filepath) + &quot;/&quot; + &quot;backup&quot;, f)) :
                currentFiles.append(f)
if len(currentFiles) &lt; 1 :
    if os.path.isfile(file[&quot;fullpath&quot;] + &quot;1&quot;) :
        shutil.move(file[&quot;fullpath&quot;] + &quot;1&quot;, file[&quot;directory&quot;] + &quot;/&quot; + file[&quot;backup_directory&quot;] + &quot;/&quot; + file[&quot;name&quot;] + &quot;.blend1&quot;)
else :
    if file[&quot;backup_amount&quot;] &lt;= len(currentFiles) :
        replaceFile = {&quot;modified_date&quot;:None, \
                       &quot;fullname&quot;:&quot;&quot;}
        for f in currentFiles :
            stats = os.stat(file[&quot;directory&quot;] + &quot;/&quot; + file[&quot;backup_directory&quot;] + &quot;/&quot; + f)
            if replaceFile[&quot;fullname&quot;] == &quot;&quot; :
                replaceFile[&quot;fullname&quot;] = f
                replaceFile[&quot;modified_date&quot;] = time.asctime(time.localtime(stats.st_mtime))
            else :
                temp_modified = time.asctime(time.localtime(stats.st_mtime))
                if replaceFile[&quot;modified_date&quot;] &gt; temp_modified :
                    replaceFile[&quot;fullname&quot;] = f
                    replaceFile[&quot;modified_date&quot;] = temp_modified
        shutil.move(file[&quot;fullpath&quot;] + &quot;1&quot;, file[&quot;directory&quot;] + &quot;/&quot; + file[&quot;backup_directory&quot;] + &quot;/&quot; + replaceFile[&quot;fullname&quot;])
    else :
        replaceFile = &quot;&quot;
        for f in currentFiles :
            for c in range(1, int(file[&quot;backup_amount&quot;]) + 1) :
                if not os.path.isfile(file[&quot;directory&quot;] + &quot;/&quot; + file[&quot;backup_directory&quot;] + &quot;/&quot; + file[&quot;name&quot;] + file[&quot;extension&quot;] + str(c)) :
                    shutil.move(file[&quot;fullpath&quot;] + &quot;1&quot;, file[&quot;directory&quot;] + &quot;/&quot; + file[&quot;backup_directory&quot;] + &quot;/&quot; + file[&quot;name&quot;] + file[&quot;extension&quot;] + str(c))
                    replaceFile = f
                    break
            if replaceFile != &quot;&quot; :
                break



#This document is licensed according to GNU Global Public License v3.

twigho
  • 11
  • 1
0

Cheers to Jonathan and Paul for leading the way. Anthony Araques of Adventures in 3d modified their Add-on to work with Blender 4.x!

bl_info = {
    "version": (1, 5),
    "blender": (4, 0, 0),
    "name": "Move old Save Files To A Sub Directory",
    "author": "Jonathan Stroem, Paul Mohr, Anthony Aragues",
    "description": """Move the backup save files to a sub-directory instead of the Blender-file's current directory. A new folder called "backup.blend" will be created and all save-files will be moved there instead of the default folder.""" ,
    "category": "System",
    "location": """The backup folder will be named "backup.blend". Under 'File > User Preferences > File > Save Versions', you can change how many backups that'll be used.""",
    }

#IMPORTS import bpy, os import shutil from bpy.app.handlers import persistent

import time from stat import *

@persistent def move_handler(dummy): print('save_post handler:', bpy.data.filepath, dummy)

#fullpath = Full path to the data file.
#directory = Directory the data file is in.
#name = Name of file, without extension.
#extension = Extension of files.
#backup_amount = Max amount of backups to store.
#backup_directory = The name of the backup directory. (Where the files should be moved.) So change this if you want to change where the backups are saved.

file = {&quot;fullpath&quot;:bpy.data.filepath, \
        &quot;directory&quot;:os.path.dirname(bpy.data.filepath), \
        &quot;name&quot;:bpy.path.display_name_from_filepath(bpy.data.filepath), \
        &quot;extension&quot;:&quot;.blend&quot;, \
        &quot;backup_amount&quot;:bpy.context.preferences.filepaths.save_version, \
        &quot;backup_directory&quot;:&quot;backup.blend&quot; \
        }

#Create backup directory if it doesn't exist.
if file[&quot;backup_directory&quot;] not in os.listdir(file[&quot;directory&quot;]) :
    os.chdir(file[&quot;directory&quot;])
    os.mkdir(file[&quot;backup_directory&quot;])

#Get current save files from the backup directory.
currentFiles = []
for f in [ f for f in os.listdir(os.path.join(file[&quot;directory&quot;], file[&quot;backup_directory&quot;])) for c in range(1, int(file[&quot;backup_amount&quot;]) + 1) if f == file[&quot;name&quot;] + file[&quot;extension&quot;] + str(c) if os.path.isfile(os.path.join(file[&quot;directory&quot;], file[&quot;backup_directory&quot;], f)) ] :
    currentFiles.append(f)

#All this is moving the correct file.
if len(currentFiles) &lt; 1 : #If no files, then no need to check.
    if os.path.isfile(file[&quot;fullpath&quot;] + &quot;1&quot;) :
        shutil.move(file[&quot;fullpath&quot;] + &quot;1&quot;, os.path.join(file[&quot;directory&quot;], file[&quot;backup_directory&quot;], file[&quot;name&quot;] + &quot;.blend1&quot;))
else : #If the max backup amount has been reached, then check for the oldest file and overwrite that one.
    if file[&quot;backup_amount&quot;] &lt;= len(currentFiles) :
        replaceFile = {&quot;modified_date&quot;:None, \
                       &quot;fullname&quot;:&quot;&quot;}
        for f in currentFiles :
            stats = os.stat(os.path.join(file[&quot;directory&quot;], file[&quot;backup_directory&quot;], f)) #Get attributes from a file.
            if replaceFile[&quot;fullname&quot;] == &quot;&quot; : #This will happen only the first time.
                replaceFile[&quot;fullname&quot;] = f
                replaceFile[&quot;modified_date&quot;] = time.asctime(time.localtime(stats[ST_MTIME]))
            else : # Is the previous file older or newer? If it's older, then you'd want to overwrite that one instead. Go through all backup-files.
                temp_modified = time.asctime(time.localtime(stats[ST_MTIME]))
                if replaceFile[&quot;modified_date&quot;] &gt; temp_modified :
                    replaceFile[&quot;fullname&quot;] = f
                    replaceFile[&quot;modified_date&quot;] = temp_modified

        #When the loop is finished, the oldest file has been found, and will be overwritten.
        shutil.move(file[&quot;fullpath&quot;] + &quot;1&quot;, os.path.join(file[&quot;directory&quot;], file[&quot;backup_directory&quot;], replaceFile[&quot;fullname&quot;]))
    else : #If the max backup amount hasn't been reached, and the folder isn't empty.
        #Then check for the next number, and then just move the file over with the correct number.
        replaceFile = &quot;&quot; #Location.
        for f in currentFiles :
            for c in range(1, int(file[&quot;backup_amount&quot;]) + 1) :
                if not os.path.isfile(os.path.join(file[&quot;directory&quot;], file[&quot;backup_directory&quot;], file[&quot;name&quot;] + file[&quot;extension&quot;] + str(c))) :
                    shutil.move(file[&quot;fullpath&quot;] + &quot;1&quot;, os.path.join(file[&quot;directory&quot;], file[&quot;backup_directory&quot;], file[&quot;name&quot;] + file[&quot;extension&quot;] + str(c)))
                    replaceFile = f
                    break
            if replaceFile != &quot;&quot; : #File to replace has been found, break out.
                break

@persistent def test_handler(dummy): print('save_pre handler:', bpy.data.filepath, dummy)

#When enabling the addon. def register(): bpy.app.handlers.save_post.append(move_handler)

#When disabling the addon. def unregister(): bpy.app.handlers.save_post.remove(move_handler)

#So that Blender recognize it as an addon. if name == "main": register()

#This document is licensed according to GNU Global Public License v3.

0

In Blender the file selector window have a filter for excluding BLEND1/BLEND2/... files. It's located inbetween the show BLEND files and show image files (a grey icon with the Blender logo). enter image description here

Don't forget to activate the filter altogether by clicking on the funnel icon to the left of all the possible filters.

In Windows 7 you can right click and select group by type, and then click on the arrows next to "BLEND1 file", "BLEND2 file" et.c. in order to collapse these. This helps to remove clutter when browsing the files in Windows Explorer. Windows remembers your selection.

And consider using software for version control like GIT (http://git-scm.com/). Then you do not need the BLEND1/BLEND2/... files at all! And have greater flexibility experimenting.

GOlaf
  • 31
  • 4