''' Auto Save script v1.3 collaboration between: Adam Kugler - http://alteredrealitystudios.com Mike Hendricks - http://www.hendricks3d.com Script creates a GUI that will allow the activation of AutoSave Single files saving is commented out, but may be changed by removing the comment in the gui There is an option for time (minutes) in between saves (multiples of 60 are best for functionality) There is also an option for the number of historical saves, default is 5. Autosaves will be saved to a newly Created AutoSave folder inside the currently active project. The curent name of the file will not change. The function will currently not run if the window is closed, so keep the window minimized while working. Closing will stop the function from running. autoSave will eat up system resources, so toggle it off for processor intensive actions. threading is not exact, so file save may be off by a few minutes. Save autoSave.py to your scripts folder. To execute, go to the script editor and type: import autoSave If you have any problems or have questions, email adam@alteredrealitystudios.com Version 1.1 Notes: - Added better functionality when changing desired time increment - Added text line for feedback on recent activity of AutoSave - Added a button that will delete all but the most recent autosave of the current project Version 1.2 Notes: - Built in a cleaner that removes files that should not be in the autoSave folder. **do not save files into the autosave folder -- they will be deleted** Version 1.2.1 Notes: - Revised cleaner to delete folders even if files exist inside, preventing mayaSwatches from creating a fatal loop. ** Keep the autoSave directory as clean as possible ** Version 1.3 Notes: - Created a button to embed autoSave into a file. Creates a script node named 'autoSave' that loads autoSave automatically when opening the embedded scene file. ''' from threading import Thread, Lock, Event import time, maya.utils import maya.OpenMaya as OpenMaya import maya.cmds as cmds import maya.mel as mel import os import math tog=0 #Threading portion (for splitting maya tasks and not locking out control of maya) def start(threads=1, interval=10, command='tm.autosave()'): ''' starts a new thread that runs command after interval seconds threads: number of threads to create, I would stick with 1 interval: number of seconds to wait before running command command: command to be run after interval seconds ''' manager = threadTime() manager.start(threads, interval, command) def stop(): ''' Stops the threads loop and ends the thread ''' manager = LoadAgent() manager.stopLoop() class threadTime: ''' Class to start the multiThreading. ''' def __init__(self): self.msg = ('localhost', '/') # default def start(self, threads=1, interval=0, command=''): for i in range(threads): #start selected thread. agent = LoadAgent(interval, command) agent.start() #print 'started thread # ' + str(i + 1) class LoadAgent(Thread): ''' Creates a new thread to process commands ''' timebreak = 0 def __init__(self, interval=1, command='', timebreak=0): Thread.__init__(self) self.interval = interval self.command = command self.finished = Event() def run(self): # creates a seperate thread so that the loop doesnt freeze the maya interface. global timebreak # reset timebreak for while loop LoadAgent.timebreak = 0 while not LoadAgent.timebreak: # lock the threading until the if statement is finished. lock = Lock() lock.acquire() if not LoadAgent.timebreak: #print('the loop is sleeping for %s seconds.\n' % self.interval) # make the loop pause for length of interval #print self.interval self.finished.wait(self.interval) # Maya commands lock can only be run from the main thread, so this command runs them in the main thread. if not LoadAgent.timebreak: #this command seemes to be evaluated even when the above lines if statement is false. maya.utils.executeInMainThreadWithResult(self.command) lock.release() def stopLoop(self): ''' This stops the loop on next eval, before it evaluates it again. ''' global timebreak if LoadAgent.timebreak == 0: LoadAgent.timebreak = 1 OpenMaya.MGlobal.displayInfo('AutoSave Turned Off\n') #File Saving Portion (Naming conventions and string manipulation to execute after X time) win="autoSaveWindow" guiW = 150 def gui(): if cmds.window(win, ex=1): cmds.deleteUI(win) cmds.window(win, title="Auto Save") cmds.columnLayout() cmds.rowColumnLayout(nc=2, w=guiW, cw=([1,120], [2,30])) cmds.text(label="Number of Saves") cmds.intField("mT", v=5) cmds.text(label="Increment (minutes)") cmds.intField("mV", v=10) cmds.setParent('..') cmds.separator(style="none", h=3) cmds.button("Autosave", label="Toggle Auto Save", c=("autoSave.toggler()"), w=guiW) cmds.button("Cleaner", label="Delete Old Auto Saves", c=("autoSave.cleaner()"), w=guiW) cmds.separator(style="single", h=15, w=150) cmds.button("Embed", label="Embed autoSave into File", c=("autoSave.embed()"), w=guiW) #remove the below comment for an incremental save #cmds.button("Timer", label="Single Save", c="autoSave.saver()", w=guiW) cmds.separator(style="none", h=3) cmds.separator(style="single", h=3, w=150) cmds.separator(style="none", h=3) cmds.text("guiUpdate", l=" Click above to activate", al="left") cmds.window(win, e=1, w=guiW) cmds.window(win, e=1, h=190) cmds.showWindow(win) #run gui gui() def embed(): try: cmds.select('autoSave') cmds.text("guiUpdate", e=1, l=("autoSave is already embeded")) except: cmds.scriptNode(n='autoSave', beforeScript="python(\"import autoSave\");\r\npython(\"reload(autoSave)\");", st=1) cmds.text("guiUpdate", e=1, l=("Embedding successful")) def toggler(): global tog timer = cmds.intField("mV", q=1, v=1) SceneName = cmds.file(q=1, sn=1, shn=1) if tog == 0: if ((SceneName)): saver() start(interval=(60*timer), command='autoSave.saver()') cmds.intField("mT", e=1, en=0) cmds.intField("mV", e=1, en=0) global tog tog = 1 else: OpenMaya.MGlobal.displayInfo("Please save your scene first") cmds.text("guiUpdate", e=1, l=" Please name your scene") else: stop() global tog tog = 0 cmds.intField("mT", e=1, en=1) cmds.intField("mV", e=1, en=1) OpenMaya.MGlobal.displayInfo("AutoSave turned off") cmds.text("guiUpdate", e=1, l=(" AutoSave off: (" + str(cmds.date(st=1)) + ")")) def cleaner(): '''Deletes all autosave files except most recent''' #get current project path, makes multiple AutoSave Folders fileType = cmds.file(q=1, type=1) SceneName = cmds.file(q=1, sn=1, shn=1) FullName = cmds.file(q=1, sn=1) SplitList=FullName.split(SceneName) #Split autosave folder if it exists to prevent recurring folder creation SplitListAuto= SplitList[0] + ('AutoSave/') SplitAuto=SplitListAuto.split('AutoSave') projPath = SplitAuto[0] savedFiles = os.listdir((projPath + 'AutoSave/')) #create autosave directory if os.path.exists((projPath + 'AutoSave/')): #print('yes') #setting a variable to get else statement to work, 'a' does nothing a=1 for files in savedFiles: if files == 'autosave01_most_recent.ma': a=1 else: os.remove((projPath + 'AutoSave/' + files)) print (files + " deleted") cmds.text("guiUpdate", e=1, l=(" Old files removed")) OpenMaya.MGlobal.displayInfo("Old files removed") else: OpenMaya.MGlobal.displayInfo('AutoSave folder does not exist') def saver(): '''This is the function that will query the path of your current project and generate autosaves in a newly created folder''' #get gui fields timeVal = cmds.intField("mT", q=1, v=1) timer = cmds.intField("mV", q=1, v=1) #get current project path, makes multiple AutoSave Folders fileType = cmds.file(q=1, type=1) SceneName = cmds.file(q=1, sn=1, shn=1) FullName = cmds.file(q=1, sn=1) SplitList=FullName.split(SceneName) #Split autosave folder if it exists to prevent recurring folder creation SplitListAuto= SplitList[0] + ('AutoSave/') SplitAuto=SplitListAuto.split('AutoSave') projPath = SplitAuto[0] #create autosave directory if os.path.exists((projPath + 'AutoSave/')): #print('yes') #setting a variable to get else statement to work, 'a' does nothing a=1 else: print 'Creating AutoSave Directory' os.mkdir(projPath + 'AutoSave/') #Get current dirctory attributes savedFiles = os.listdir((projPath + 'AutoSave/')) saveLength = len(savedFiles) xx = 0 if saveLength > 0: while xx == 0: if savedFiles[0] != 'autosave01_most_recent.ma': print ('removing ' + savedFiles[0]) try: folder = os.listdir((projPath + 'AutoSave/' + savedFiles[0])) for item in folder: os.remove((projPath + 'AutoSave/' + savedFiles[0]+'/'+item)) print ('deleting '+item) except: a=1 try: os.removedirs((projPath + 'AutoSave/' + savedFiles[0])) except: a = 1 try: os.remove((projPath + 'AutoSave/' + savedFiles[0])) except: a=1 savedFiles = os.listdir((projPath + 'AutoSave/')) else: xx=1 print 'moving on' while xx == 1: lastFile = savedFiles[-1].split('.') if ((lastFile[-1]) != ('ma')): try: folder = os.listdir((projPath + 'AutoSave/' + savedFiles[-1])) for item in folder: os.remove((projPath + 'AutoSave/' + savedFiles[-1]+'/'+item)) print ('deleting '+item) except: a=1 try: os.removedirs((projPath + 'AutoSave/' + savedFiles[-1])) except: a = 1 try: os.remove((projPath + 'AutoSave/' + savedFiles[-1])) except: a=1 savedFiles = os.listdir((projPath + 'AutoSave/')) else: xx=2 print 'moving on' saveLength = len(savedFiles) '''Delete files that are greater than number of saves field''' a = 1 while a < (saveLength): if a > (timeVal - 2): os.remove((projPath + 'AutoSave/' + savedFiles[a])) a=a+1 #New directory list attributes after cleaning desired files savedFilesB = os.listdir((projPath + 'AutoSave/')) saveLengthB = len(savedFilesB) '''renaming old files to older files loop if > 2''' SL = saveLengthB - 1 while SL > 0: #split files into peices for recognition #asd = savedFiles[SL].split('_') #dsa = asd[0].split('autosave') ComponentList = savedFiles[SL].split('_') #bbb = ComponentList[1] #spacer set for numbers below 10, add an additional elif for 100 if needed if SL < 9: spacer = ('0') else: spacer = '' minuteNamer = int(ComponentList[1]) + int(timer) #rename old files to older files os.rename((projPath + 'AutoSave/' + savedFiles[SL]), (projPath + 'AutoSave/autosave' + str(spacer) + str(SL+2) + '_' + str(minuteNamer) + '_mins_ago.ma')) SL=SL-1 '''rename 01 to 02''' if os.path.exists((projPath + 'AutoSave/autosave01_most_recent.ma')): os.rename((projPath + 'AutoSave/autosave01_most_recent.ma'), (projPath + 'AutoSave/autosave02_' + str(timer) + '_mins_ago.ma')) #Code below will be save files without the long name of minutes attached ''' while i>2: if os.path.exists((projPath + 'AutoSave/autosave' + str(i-1) + '.ma')): os.rename((projPath + 'AutoSave/autosave' + str(i-1) + '.ma'), (projPath + 'AutoSave/autosave' + str(i) + '.ma')) #print i i = i - 1 #### end loop, write initital if if os.path.exists((projPath + 'AutoSave/autosave01_most_recent.ma')): os.rename((projPath + 'AutoSave/autosave01_most_recent.ma'), (projPath + 'AutoSave/autosave02.ma')) ''' #rename file to autosave cmds.file(rn=projPath+'AutoSave/autosave01_most_recent.ma') #save and save type cmds.file( save=True, type='mayaAscii' ) #rename back to original cmds.file(rn=FullName) cmds.file(type=fileType[0]) curTime = cmds.date(t=1) #Print to command line with spaces print '' cmds.text("guiUpdate", e=1, l=(" Last save at " + curTime)) OpenMaya.MGlobal.displayInfo("Auto Saved at " + curTime)