Mountain Lion Calendar - exporting calendars as .ics files

Discussion in 'Mac Programming' started by Schubi, Mar 22, 2013.

  1. macrumors newbie

    Joined:
    Mar 22, 2013
    #1
    Hello,

    I wonder if anyone can help with AppleScript and knows the latest OSX Calendar functions well.

    My goal is to backup each calendar within the Calendar application to a single directory as .ics files.

    I've been reading through this post from 2007 and tried to modify the script from xUKHCx without any success. I assume that the Calendar application has changed quite a bit over the last 5 years.

    Code:
    -- Set paths and variables ------------------------------------------------------------------------------------
    set timeStamp to do shell script "date \"+%Y%m%d\""
    set calendar_folder to POSIX path of (path to home folder from user domain)
    set sources_folder to quoted form of (calendar_folder & "Library/Calendars")
    set backup_folder to POSIX path of ("Users/ros/Backup/Calendar/")
    
    -- Find all Info.plist files ---------------------------------------------------------------------------------
    set infolist to paragraphs of (do shell script "find -f " & sources_folder & "| grep -v “/Contents” | grep Info.plist$")
    set calstartlist to {}
    set caldestlist to {}
    set calnamelist to {}
    
    -- Create a backup folder -------------------------------------------------------------------------------------
    try
    	set destfolder to backup_folder
    	set fileName to timeStamp
    	do shell script "mkdir -p " & quoted form of destfolder & "/" & quoted form of fileName
    	set destFile to destDir & "/" & fileName
    end try
    
    -- Search through above results -------------------------------------------------------------------------------
    repeat with calname in infolist
    	set calname to calname as string
    	set calname to text 1 thru -7 of calname
    
    -- Create a path to the original .ics files -------------------------------------------------------------------
    	set calstart to quoted form of (text 1 thru -5 of calname & "corestorage.ics")
    	copy calname to end of calstartlist
    	set calname to quoted form of calname
    	
    -- Read the Info.plist and grab the calendar names ------------------------------------------------------------
    	try
    		set calname to (do shell script "defaults read " & calname & " Title")
    		set caldest to quoted form of (backup_folder & calname & ".ics")
    		copy calname to end of calnamelist
    		copy caldest to end of caldestlist
    	end try
    end repeat
    
    set calexport to choose from list calnamelist with multiple selections allowed
    repeat with calname in infolist
    	set calname to calname as string
    	set calname to text 1 thru -7 of calname
    	set calstart to quoted form of (text 1 thru -5 of calname & "corestorage.ics")
    	copy calname to end of calstartlist
    	set calname to quoted form of calname
    	try
    		set calname to (do shell script "defaults read " & calname & " Title")
    		set caldest to quoted form of (backup_folder & calname & ".ics")
    		if calname is in calexport then
    			do shell script "ditto " & calstart & " " & caldest
    		end if
    	end try
    end repeat
    The end result should be as in the attached screenshot. Any help is greatly appreciated - after 2 days of searching through Google and other forums.. I'm out of skills and ideas!
     

    Attached Files:

  2. macrumors 6502a

    Joined:
    Mar 17, 2012
    Location:
    Belgium
    #2
    I couldn't find corestorage.ics on my mac or anything about exporting calendars in iCal's dictionary so I decided to go with GUI scripting. Not the best or most elegant solution but I think it does the job.

    Code:
    property savePath : ""
    set timeStamp to do shell script "date \"+%Y%m%d\""
    set backup_folder to "/Users/kryten/Backup/Calendar/"
    set macPath_Backup_folder to POSIX file backup_folder
    try
    	tell application "Finder"
    		if not (exists macPath_Backup_folder) then
    			set macBackup_folderExists to false
    			my createDirectories(backup_folder, timeStamp)
    		else
    			set savePath to backup_folder & timeStamp
    			--log savePath
    			set macBackup_folderExists to true
    		end if
    	end tell
    end try
    
    on createDirectories(theFolders, theDate)
    	set savePath to do shell script "mkdir -vp " & quoted form of theFolders & quoted form of theDate
    	--log savePath
    end createDirectories
    
    tell application "iCal"
    	activate
    	delay 2
    	set everyCalendar to every calendar
    	set countLoop to 0
    	repeat with aCalendar in everyCalendar
    		set calendarName to name of aCalendar
    		set countLoop to countLoop + 1
    		--log countLoop
    		tell application "System Events"
    			tell application process "iCal"
    				click menu item "Export…" of menu 1 of menu item "Export…" of menu 1 of menu bar item "File" of menu bar 1
    				delay 0.5
    				--keystroke aCalendar's name
    				keystroke calendarName
    				delay 0.2
    				if countLoop = 1 then
    					keystroke "g" using {command down, shift down}
    					delay 0.2
    					if macBackup_folderExists is false then
    						keystroke third paragraph of savePath
    					else
    						keystroke savePath
    					end if
    					--delay 0.5
    					keystroke return
    					--delay 0.5
    				end if
    				keystroke return
    			end tell
    		end tell
    	end repeat
    end tell
    
    Note : Make sure Enable access for assistive devices is checked in Universal Access of System Preferences. Tested on Snow Leopard with iCal 4.0.4. YMMV.
     

    Attached Files:

  3. Schubi, Mar 22, 2013
    Last edited: Mar 22, 2013

    thread starter macrumors newbie

    Joined:
    Mar 22, 2013
    #3
    Hello kryten2,

    Thanks for looking into this. The script is what I've been looking for - apart for some small problems.

    1) It does not create a new backup folder ('YYYYMMDD').

    2) The script runs through the actions very quickly and stumbles upon an event creating a calendar backup called Employmentnment.ics instead of Employment.ics

    3) All backup files have the same file size. Clicking a manual 'File -> Export -> Export...' in Calendar however saves the calendars with their correct file size.

    4) The Calendar menu has slightly changed in Calendar 6.0 (1648) so I made the following adjustments to 'click menu item'. Here's the whole script:
    Code:
    property savePath : ""
    set timeStamp to do shell script "date \"+%Y%m%d\""
    set backup_folder to "/Users/ros/Backup/Calendar/"
    set macPath_Backup_folder to POSIX file backup_folder
    try
    	tell application "Finder"
    		if not (exists macPath_Backup_folder) then
    			set macBackup_folderExists to false
    			my createDirectories(backup_folder, timeStamp)
    		else
    			set savePath to backup_folder & timeStamp
    			--log savePath
    			set macBackup_folderExists to true
    		end if
    	end tell
    end try
    
    on createDirectories(theFolders, theDate)
    	set savePath to do shell script "mkdir -vp " & quoted form of theFolders & quoted form of theDate
    	--log savePath
    end createDirectories
    
    tell application "Calendar"
    	activate
    	delay 2
    	set everyCalendar to every calendar
    	set countLoop to 0
    	repeat with aCalendar in everyCalendar
    		set calendarName to name of aCalendar
    		set countLoop to countLoop + 1
    		--log countLoop
    		tell application "System Events"
    			tell application process "Calendar"
    				click menu item "Export…" of menu 1 of menu item "Export" of menu 1 of menu bar item "File" of menu bar 1
    				delay 0.5
    				--keystroke aCalendar's name
    				keystroke calendarName
    				delay 0.2
    				if countLoop = 1 then
    					keystroke "g" using {command down, shift down}
    					delay 0.2
    					if macBackup_folderExists is false then
    						keystroke third paragraph of savePath
    					else
    						keystroke savePath
    					end if
    					--delay 0.5
    					keystroke return
    					--delay 0.5
    				end if
    				keystroke return
    			end tell
    		end tell
    	end repeat
    end tell

    I've created a screencast that shows what the script does (31MB, .mov): http://195.30.252.25/files/dmp/ScreencastCalendar.mov
     
  4. macrumors 6502a

    Joined:
    Mar 17, 2012
    Location:
    Belgium
    #4
    About 5 minutes after posting my reply and thinking about it a little bit harder I knew this script was no good.

    1) Make a new script with everything except the tell application iCal block and look at the replies and events in Applescript Editor why it fails to create a new backup folder. Uncomment the log statements for more feedback.

    2) Yeah it runs fast on your system. Increase the delays.

    3) Here's the real problem. The script loops through every calendar but doesn't really export the right calendars. Mainly because iCal doesn't understand( on Leopard and Snow Leopard anyway) the selection keyword.
    I'll look into UI browser to select them with GUI scripting. Unfortunately I'm not on Mountain Lion so I can't really test anything.

    I'll see if I can make some time to get ML running on my hack to come up with a satisfying solution to your problem. There's on thing you can do. Can you look into the following path if you see a corestorage.ics file?

    /Users/ros/Library/Application Support/iCal/Sources/2B835489-C867-4DBB-9AFC-5986AA3F58F4.calendar/

    The id part is just an example and should be different on your mac. If it's there and also the info.plist file the first script uses it should be possible to make the first script you posted work after you change the sources_folder to the right path eg /Users/ros/Library/Application Support/iCal
     
  5. thread starter macrumors newbie

    Joined:
    Mar 22, 2013
    #5
    Thanks for the effort you are putting into helping me!

    Make a new script with everything except the tell application iCal block and look at the replies and events in Applescript Editor why it fails to create a new backup folder. Uncomment the log statements for more feedback.

    Modified script running with logging activated:
    Code:
    property savePath : ""
    set timeStamp to do shell script "date \"+%Y%m%d\""
    set backup_folder to "/Users/ros/Backup/Calendar/"
    set macPath_Backup_folder to POSIX file backup_folder
    try
    	tell application "Finder"
    		if not (exists macPath_Backup_folder) then
    			set macBackup_folderExists to false
    			my createDirectories(backup_folder, timeStamp)
    		else
    			set savePath to backup_folder & timeStamp
    			log savePath
    			set macBackup_folderExists to true
    		end if
    	end tell
    end try
    
    on createDirectories(theFolders, theDate)
    	set savePath to do shell script "mkdir -vp " & quoted form of theFolders & quoted form of theDate
    	log savePath
    end createDirectories
    From the Events/Replies section in AppleScript Editor (although the folder '20130324' does NOT exist in /Users/ros/Backup/Calendar/):
    Code:
    tell current application
    	do shell script "date \"+%Y%m%d\""
    		--> "20130324"
    end tell
    tell application "Finder"
    	exists file "Main:Users:ros:Backup:Calendar:"
    		--> true
    	(*/Users/ros/Backup/Calendar/20130324*)
    end tell
    Result:
    true


    Can you look into the following path if you see a corestorage.ics file?

    I could not find any 'corestorage.ics' file at all on my system:
    Code:
    [localhost]$ sudo find / -type f -name corestorage.ics
    Password:
    [localhost]$  
    But I found where all the calendars are stored. I sync my calendars to an OwnCloud server so the path is 'caldav' related. Comments in brackets () right to the file listing:

    Calendar Root Directory
    Code:
    [COLOR="DarkRed"]/Users/ros/Library/Calendars/[/COLOR]
    drwxr-xr-x  22 ros  staff      748 Mar 18 22:38 8E83A3AD-8EEF-4428-8203-2A4C67565E30.caldav		(All my personal calendars)
    drwxr-xr-x   5 ros  staff      170 Oct  6 17:01 5DD3C270-985B-4C7A-AE57-399DB46CDDE6.calendar		(The 'Birthdays' calendar)
    
    drwxr-xr-x   5 ros  staff      170 Oct  6 17:14 750D9A10-25FD-4CB7-9FA9-0464084CDBF5.caldav		(NotificationCollection)
    drwxr-xr-x   4 ros  staff      136 Oct  6 15:54 C60C3148-EB8F-4929-B59E-9B0B8C6EF0EB.calendar		(Event Reminders)
    -rw-r--r--@  1 ros  staff  7356416 Mar 24 12:25 Calendar Cache						(Binary File)
    drwxr-xr-x  39 ros  staff     1326 Mar 24 12:02 Calendar Sync Changes					(Temp files)	
    -rw-r--r--   1 ros  staff      182 Oct  6 17:14 Email Cache.plist					(Empty file)
    drwxr-xr-x   2 ros  staff       68 Oct  6 16:16 Incoming						(Empty folder)
    Calendar Directory for all my personal calendars
    Code:
    [COLOR="DarkRed"]/Users/ros/Library/Calendars/8E83A3AD-8EEF-4428-8203-2A4C67565E30.caldav/[/COLOR]
    drwxr-xr-x    4 ros  staff   136 Mar 18 22:38 04950D7E-2BFA-4239-A349-24A573513B9E.calendar		(Education)
    drwxr-xr-x    4 ros  staff   136 Mar 18 22:38 3CAF1ED2-BE78-4A46-BC4D-E6C2BDD05B49.calendar		(Health)
    drwxr-xr-x    4 ros  staff   136 Mar 18 22:38 3F438A8D-EDDB-4FC0-861D-E5B2550A6D55.calendar		(Rest)
    drwxr-xr-x    4 ros  staff   136 Mar 18 22:38 4605849B-95A7-47B0-AEF3-39D6D04B7071.calendar		(Food)
    drwxr-xr-x    4 ros  staff   136 Mar 18 22:38 7CE2B1AD-C7E1-4DC8-86B6-62382364F678.calendar		(Location)	
    drwxr-xr-x    4 ros  staff   136 Mar 18 22:38 86C2E0A3-46E2-4576-8D40-0027E409F593.calendar		(Holidays)
    drwxr-xr-x    4 ros  staff   136 Mar 18 22:38 94764D88-4D2E-4EF8-AE2D-042D805D847D.calendar		(Socialising)
    drwxr-xr-x    4 ros  staff   136 Mar 18 22:38 9C483337-B54C-4656-9AD4-D209418EDA33.calendar		(Employment)
    drwxr-xr-x    4 ros  staff   136 Mar 18 22:38 BEE64618-8AD9-4213-994C-A2EDA573082D.calendar		(Entertainment)
    drwxr-xr-x    4 ros  staff   136 Mar 18 22:38 CCF565CD-053B-479F-BE8D-EAC00681EA05.calendar		(Transport)
    drwxr-xr-x    4 ros  staff   136 Mar 18 22:38 D8B8EEC6-7963-4B9C-B759-97EA3EBD313C.calendar		(ToDo)
    drwxr-xr-x    4 ros  staff   136 Mar 18 22:38 DE09DCB3-11E5-481B-9825-8CC00EEDAD2B.calendar		(Hygiene)
    drwxr-xr-x    4 ros  staff   136 Mar 18 22:38 E4FD5C67-3BE5-4C0A-841F-E7AD244386B0.calendar		(Sports)
    drwxr-xr-x    4 ros  staff   136 Mar 18 22:38 FE588D5A-A7A0-49B6-AA7A-1926468641ED.calendar		(Relationship)
    
    drwxr-xr-x  121 ros  staff  4114 Mar 23 18:43 Attachments						(Empty folder)	
    drwxr-xr-x    2 ros  staff    68 Feb 13 10:37 Inbox							(Empty folder)
    -rw-r--r--@   1 ros  staff  1953 Mar 24 12:10 Info.plist						(CalDav setup details)
    drwxr-xr-x    4 ros  staff   136 Oct  8 17:09 LocalDefaultAlarms					(Alarm related details)
    drwxr-xr-x    2 ros  staff    68 Oct  6 17:14 NotificationCollection					(Empty folder)
    drwxr-xr-x    4 ros  staff   136 Oct  6 17:02 ServerDefaultAlarms					(Alarm related details)
    Example Calendar Details for Calendar 'Education'
    Code:
    [COLOR="DarkRed"]/Users/ros/Library/Calendars/8E83A3AD-8EEF-4428-8203-2A4C67565E30.caldav/04950D7E-2BFA-4239-A349-24A573513B9E.calendar/[/COLOR] 
    	drwxr-xr-x  91 ros  staff  3094 Mar 19 23:05 Events
    	-rw-r--r--   1 ros  staff  1169 Mar 24 11:45 Info.plist
    Example Info.plist for Calendar 'Education' (snipped details)
    Code:
    [COLOR="DarkRed"]/Users/ros/Library/Calendars/8E83A3AD-8EEF-4428-8203-2A4C67565E30.caldav/04950D7E-2BFA-4239-A349-24A573513B9E.calendar/Info.plist[/COLOR] 
    		...
            <key>Key</key>
            <string>04950D7E-2BFA-4239-A349-24A573513B9E</string>
    		...
            <key>Title</key>
            <string>Education</string>
    		...
    Calendar Events for Calendar 'Education' (just a short selection of hundred of .ics files):
    Code:
    [COLOR="DarkRed"]/Users/ros/Library/Calendars/8E83A3AD-8EEF-4428-8203-2A4C67565E30.caldav/04950D7E-2BFA-4239-A349-24A573513B9E.calendar/Events/[/COLOR]
    -rw-r--r--   1 ros  staff  1041 Mar 18 22:38 042597A8-26B1-4DAF-8B40-56314C666062.ics
    -rw-r--r--   1 ros  staff  1041 Mar 18 22:38 0A69923B-2EEF-4D6A-A187-5CFB94C30026.ics
    -rw-r--r--   1 ros  staff  1085 Mar 18 22:38 0F476A80-364D-456C-BE31-A894334A4A31.ics
    -rw-r--r--   1 ros  staff  1039 Mar 18 22:38 158904AF-C32B-4814-B006-DC704D0465BD.ics
    -rw-r--r--   1 ros  staff  1041 Mar 18 22:38 18A199AE-92DC-453F-935A-8B162711854A.ics
    ...
     
  6. macrumors 6502a

    Joined:
    Mar 17, 2012
    Location:
    Belgium
    #6
    Sorry it's been a while. Can you try this :

    Code:
    -- Selecting calendars in iCal and export using GUI scripting
    -- Change the backup_folder path!
    -- Don't click anywhere else when the srcipt is running!
    
    set timeStamp to do shell script "date \"+%Y%m%d\""
    set backup_folder to "/Users/kryten/Backup/Calendar/"
    do shell script "mkdir -p " & quoted form of backup_folder & quoted form of timeStamp
    set savePath to backup_folder & timeStamp
    
    -- Begin script
    tell application "Calendar"
    	launch
    	activate
    	delay 1
    	set calNames to name of every calendar
    end tell
    
    tell application "System Events"
    	tell process "Calendar"
    		
    		-- Left-hand menu of iCal, containing named calendars	
    		set myOutline to outline 1 of scroll area 1 of splitter group 1 of splitter group 1 of splitter group 1 of window "Calendar"
    		set allRows to rows of myOutline
    		
    		-- List of named calendars
    		set calNameVals to value of text field of every row in myOutline
    		
    		-- For all named calendars, check whether it's the same name as one of calNames
    		-- If so, export that calendar.
    		
    		set countLoop to 0
    		repeat with i from 2 to (count calNameVals)
    			set countLoop to countLoop + 1
    			set calName to item 1 of item i of calNameVals
    			repeat with myName in calNames
    				if (myName as string = calName as string) then
    					tell row i of myOutline
    						select
    						delay 1
    					end tell
    					click menu item "Export…" of menu 1 of menu item "Export" of menu 1 of menu bar item "File" of menu bar 1
    					delay 2
    					if countLoop = 1 then
    						keystroke "g" using {command down, shift down}
    						delay 1
    						keystroke savePath
    						delay 1
    						click button "Go" of sheet 1 of sheet 1 of window 1
    					end if
    					click button "Export" of sheet 1 of window 1
    				end if
    			end repeat
    		end repeat
    	end tell
    end tell
    
     

    Attached Files:

  7. thread starter macrumors newbie

    Joined:
    Mar 22, 2013
    #7
    Like a clock-work! Thank you very much!

    I'm pretty sure this will be helpful to a lot of other people as well - pity that such a basic function isn't implemented in Mountain Lion!
     
  8. macrumors newbie

    Joined:
    Dec 30, 2008
    #8
    This is great. Thanks!

    I'd been previously saving my local (non-iCloud) calendars using an Applescript using a Calendar Archive, so scripting was relatively easy. Your method should also work for iCloud-based calendar backups, since these calendars aren't included in Calendar Archives.

    However, I have struck a problem trying to implement your script if the Calendar application is actively updating subscribed calendars. In this situation, the window isn't called "Calendar. It's called "Calendar — Updating…".

    How would I modify the script to select either window, bearing in mind that the name may change midway through the script execution?

    Thanks.
     
  9. Schubi, Nov 1, 2013
    Last edited: Nov 8, 2014

    thread starter macrumors newbie

    Joined:
    Mar 22, 2013
    #9
    Attaching the Mountain Lion script. Please rename .txt to .scpt in order to run it from the Script Editor.app. Don't forget to enable access for assistive devices and applications.

    If you are looking for a script that runs under 10.9, please check the following thread: Mavericks Calendar - exporting calendars as .ics files
     

    Attached Files:

Share This Page