7
$\begingroup$

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
$\endgroup$
2
  • 1
    $\begingroup$ I don't think you can do this without altering the source code and building your own version. $\endgroup$
    – sambler
    Feb 11, 2014 at 8:59
  • $\begingroup$ Make a request as it is a thing that bothers me a bit, too $\endgroup$ Feb 11, 2014 at 20:22

5 Answers 5

10
$\begingroup$

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.
$\endgroup$
4
  • $\begingroup$ Thanks for take the time to do this, is it ok if i spread the code to other people that might be interested? $\endgroup$ Feb 13, 2014 at 9:50
  • 2
    $\begingroup$ You're welcome, I'm glad you like it.Yes, definitely! Feel free to spread it around. $\endgroup$
    – Jonathan
    Feb 13, 2014 at 17:25
  • $\begingroup$ Even though this is 4 years old, it's still very useful. $\endgroup$
    – Leander
    Jun 5, 2018 at 9:35
  • 1
    $\begingroup$ No longer works in versions 2.8 and beyond. Is it possible to get this updated for 2.9? $\endgroup$ Jan 2, 2021 at 1:49
2
$\begingroup$

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.
$\endgroup$
1
$\begingroup$

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



#This document is licensed according to GNU Global Public License v3.
$\endgroup$
1
  • $\begingroup$ this is very beautiful. thanks (it worked on blender 3.4.1 on Windows 10) $\endgroup$
    – Fede Berg
    Sep 21, 2023 at 19:17
0
$\begingroup$

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.

$\endgroup$
0
$\begingroup$

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 = {"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.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
@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.
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .