Automatically back up every "n" minutes.

Edit: Post updated to use launcd rather than cron, and with an updated script.

Hi, for very good reasons (The backups can be a really annoying interruption) Scrivener doesn’t have a “backup every n minutes” option, but as I want to see if could live with the limitations I’ve come up with a way to implement such a feature for those that don’t mind getting their hands dirty:

I’ve written an AppleScript that will run the “File / Backup Up / Backup Now” menu item, and then I’ve scheduled this using Lingon (Am app store bought GUI front end for the OSX system launcd). The script is scheduled to run every minute, but checks the time so it only runs “on the hour”

Yes, there’s the expected interruption when the backup runs, but I’ve got the script telling me aloud it’s about to backup (May change this to a growl notification) which gives me a bit of notice. My backups take about one sip of tea, so no big deal.

Currently the script only runs when Scrivener is open, and only when my mac is active (Has been idle for less than 3630 seconds). This way it gives me a backup every hour, but only when I’m working. If I stop working, the backups will run once more, then stop until I’m back.

Script is here if anyone is interested: … n_1_0.scpt

If anyone wants to know more, ping me.

Note! I’m using this and it’s working fine for me. But this has been kludged together without input from anyone at L&L. I don’t believe it will (or can) do any harm, but the usual “Don’t come running back to me” warnings apply, especially if you run wild with lingon and start deleting your needed startup items!

Update: Note, due to Scrivener greying out the Back Up / Back Up Now menu option in full screen. These backups will not run when in full screen mode. (Although I’d love to find a work around)

What about something like this psuedo-code:

	-- Menu click: "View/Exit Full Screen"
	set wasFull to true
on error
	set wasFull to false
end try

-- Menu click: "File/Back Up/Back Up Now"

if wasFull is true then
	-- Menu click: "View/Enter Full Screen"
end if

So long as you’re actually on a tea break, it shouldn’t matter if the screen flickers a bit.

Thanks for the tip and it really looked promising… but it was never going to work as when Scrivener is in full screen mode the menu is hidden and won’t respond to scripted GUI commands. (It works okay if you leave the mouse at the top activating the menu.)

But… it got me thinking. If the menu doesn’t have the options I need and doesn’t work anyway, then why not just use a keyboard command?

So the script has been simplified and changed to do a command-s, which saves and therefore runs my backup. Works perfectly in any mode.

[code]-- Jen Yates Backup Scrivener Script
property idleTest : 3630 – Seconds for idle test

– Start of idle check
set idleTime to idle_time()
set old_delims to AppleScript’s text item delimiters
set AppleScript’s text item delimiters to “.”
set idleTime to ((first text item of idleTime as string) as integer)
set AppleScript’s text item delimiters to old_delims
set idleTest to (idleTest as integer)

– Only run if on the half hour
if getMinutes() as string = “30” then

if idleTime is greater than idleTest then
	-- System is too idle, so don't backup
	-- Mac still in use (Or within n seconds of active where n is set above).
	-- So okay to backup now
	-- But only if Scrivener is running!
	if appIsRunning("Scrivener") then
		say "Backing up"
		delay 1
		tell application "Scrivener" to activate
		tell application "System Events" to keystroke "s" using {command down}
		--End of app running check
	end if
	-- End of idle check	
end if

--End of time check	

end if

– Routine to get the minutes component of the current time
on getMinutes()
– Get the “hour”
set timeStr to time string of (current date)

set Pos to offset of ":" in timeStr
set theHour to characters 1 thru (Pos - 1) of timeStr as string
set timeStr to characters (Pos + 1) through end of timeStr as string

-- Get the "minute"
set Pos to offset of ":" in timeStr
set theMin to characters 1 thru (Pos - 1) of timeStr as string
set timeStr to characters (Pos + 1) through end of timeStr as string

return theMin

end getMinutes

– Routine to check if an app is running
on appIsRunning(appName)
tell application “System Events”
set isRunning to ((application processes whose (name is equal to appName)) count)
end tell
if isRunning is greater than 0 then
return true
return false
end if
end appIsRunning

– Routine to check idle time
on idle_time()
– this is the crucial line that I don’t claim credit for
set idleTime to (do shell script “ioreg -c IOHIDSystem | perl -ane 'if (/Idle/) {$idle=(pop @F)/1000000000; print $idle,”";last}’")
return idleTime
end idle_time