Search code examples
applescript

How can I get the list of calendars (with UID) using applescript?


I am trying to get the UIDs of calendars (MacOS calendar app) so I can push events to specific calendars (I have multiple calendars with the same name).

I've tried this code

tell application "Calendar"
    set calendarList to {}
    repeat with aCalendar in calendars
        set end of calendarList to {uid of aCalendar, name of aCalendar}
    end repeat
    return calendarList
end tell

It errors out unless I remove uid of aCalendar.


Solution

  • As far as I know, the uid property of calendars in the Calendars.app has not been available for scripting for a long time. Until Apple fixes the bug, I use the following script, which is based on parsing error message in a 2-level try block.

    First I try to get the uid in the normal way. This usually doesn't work, and I force the calendar-to-text coercion to throw the error and get the error message. From this error message it is easy to parse the uid, which is done.

    on identifyCalendars()
        set ATID to AppleScript's text item delimiters
        set AppleScript's text item delimiters to {"Can’t make «class wres» id \"", "\" of application \"Calendar\" into type text."}
        tell application "Calendar"
            set calendarList to {}
            repeat with aCalendar in calendars
                try
                    set end of calendarList to {uid of aCalendar, name of aCalendar}
                on error number -10000 -- error "AppleEvent handler failed"
                    try
                        aCalendar as text
                    on error errorMessage
                        set theID to text item 2 of errorMessage
                        set end of calendarList to {theID, name of aCalendar}
                    end try
                end try
            end repeat
        end tell
        set AppleScript's text item delimiters to ATID
        return calendarList
    end identifyCalendars
    
    identifyCalendars()
    

    It was a plain (vanilla) AppleScript solution.

    For those who prefer plain AppleScript over the alternative solution, I note that the AsObjC solution (already suggested by another user) is faster (after bootstrapping), by about 10 times. Also in the AsObjC solution, it is easy to get the desired result in the form of the record {name:uid, name:uid,..}.

    use AppleScript version "2.4"
    use framework "EventKit"
    use scripting additions
    
    on identifyCalendars()
        set eventStore to current application's EKEventStore's alloc()'s init()
        set allCalendars to eventStore's calendarsForEntityType:(current application's EKEntityTypeEvent)
        set calendarNames to allCalendars's valueForKey:"title"
        set calendarUIDs to allCalendars's valueForKey:"calendarIdentifier"
        return (current application's NSDictionary's dictionaryWithObjects:calendarUIDs forKeys:calendarNames) as record
    end identifyCalendars
    
    identifyCalendars()