If I have an event UID, how do I script EventKit to isolate that one event, using a predicate that refers to the UID string. I wrote the following script to show that I can isolate EventKit events by dates, but have to resort to a loop to isolate EventKit events by a sharedUID.
I used Shane’s “CalendarLib EC” to gather the elements of the event itself in that loop.
The following applescript example finds an event whose UID is “34C4450E-70C0-48D5-B94C-03240284C1BD” scheduled in a calendar named “Personal Web” in period ranging from 7 days prior to 5 days hence.
The script correctly yields the following:
{event_external_ID:“34C4450E-70C0-48D5-B94C-03240284C1BD”, event_location:missing value, event_end_date:date “Sunday, June 3, 2018 at 2:00:00 PM”, event_start_date:date “Sunday, June 3, 2018 at 1:45:00 PM”, event_time_zone:“America/Los_Angeles”, event_status:“confirmed”, event_description:missing value, event_url:missing value, event_organizer:missing value, calendar_type:“cloud”, all_day:false, event_creation_date:date “Sunday, June 3, 2018 at 5:32:03 PM”, event_original_date:missing value, event_attendees:{}, event_is_recurring:false, event_summary:“Trial Event”, calendar_name:“Personal Web”}
How can I script the final repeat loop using a predicate method?
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "EventKit"
use script "CalendarLib EC"
set targetUID to "34C4450E-70C0-48D5-B94C-03240284C1BD"
set listOfCalNames to {"Personal Web"} -- list of one or more calendar names
set DaysBefore to 7
set DaysAhead to 5
set eventInformation to my getEventInfoForUID:targetUID inCalendarList:listOfCalNames fromDaysBefore:DaysBefore toDaysAhead:DaysAhead
on getEventInfoForUID:targetUID inCalendarList:listOfCalNames fromDaysBefore:DaysBefore toDaysAhead:DaysAhead
# Create event store and get access to Calendars
set theEKEventStore to current application's EKEventStore's alloc()'s init()
theEKEventStore's requestAccessToEntityType:0 completion:(missing value)
# Get event store authorization status
my authorizationStatus()
# Arrange date predicates
set {DaysBehindDate, DaysAheadDate} to my prepareDateRangeFromDaysBefore:DaysBefore toDaysAhead:DaysAhead
# Arrange calendar predicate
set calsToSearch to my getCalendarsToSearch:listOfCalNames withEKEventStore:theEKEventStore
if calsToSearch is false then return false --abort script
# Find matching events for date using predicate method
set theDatePred to theEKEventStore's predicateForEventsWithStartDate:DaysBehindDate endDate:DaysAheadDate calendars:calsToSearch
set theEvents to (theEKEventStore's eventsMatchingPredicate:theDatePred)
# Find matching event for UID using loop method
# I am unable to write an EventKit predicate method
set eventInformation to my LoopThroughEvents:theEvents ToGetEventInformationFromTargetUID:targetUID
end getEventInfoForUID:inCalendarList:fromDaysBefore:toDaysAhead:
on getCalendarsToSearch:listOfCalNames withEKEventStore:theEKEventStore
--set calendar type for EventStore Predicate
set listOfCaTypes to {0, 1, 2} -- list of one or more calendar types: : Local = 0, CalDAV/iCloud = 1, Exchange = 2, Subscription = 3, Birthday = 4
-- get calendars that store events
set theCalendars to theEKEventStore's calendarsForEntityType:0
-- filter for desired calendars
set theNSPredicate to current application's NSPredicate's predicateWithFormat_("title IN %@ AND type IN %@", listOfCalNames, listOfCaTypes)
set calsToSearch to theCalendars's filteredArrayUsingPredicate:theNSPredicate
if (count of calsToSearch) < 1 then set calsToSearch to false
calsToSearch
end getCalendarsToSearch:withEKEventStore:
on authorizationStatus()
-- check if app has access and authorization
set authorizationStatus to current application's EKEventStore's authorizationStatusForEntityType:0 -- work around enum bug
if authorizationStatus is not 3 then
display dialog "Access must be given in System Preferences" & linefeed & "-> Security & Privacy first." buttons {"OK"} default button 1
tell application "System Preferences"
activate
tell pane id "com.apple.preference.security" to reveal anchor "Privacy"
end tell
error number -128
end if
end authorizationStatus
on prepareDateRangeFromDaysBefore:DaysBefore toDaysAhead:DaysAhead
# create start date and end date for occurances
--set nowNSDate variable to represent current UTC Universal Time-Coordinated date, previously Zulu Time Zone
set nowDate to current application's NSDate's |date|
--startOfDayForDate returns the first UTC moment of a given date as a date instance, based upon the current time zone.
set todaysStartofDayDate to current application's NSCalendar's currentCalendar()'s startOfDayForDate:nowDate
--set the days that will define the date predicate range
set DaysBehindDate to todaysStartofDayDate's dateByAddingTimeInterval:(-1) * DaysBefore * days
set DaysAheadDate to todaysStartofDayDate's dateByAddingTimeInterval:DaysAhead * days
{DaysBehindDate, DaysAheadDate}
end prepareDateRangeFromDaysBefore:toDaysAhead:
on LoopThroughEvents:theEvents ToGetEventInformationFromTargetUID:targetUID
# Question: What EventKit predicate method can avoid the following loop, so that a large list can be evaluated?
repeat with anEvent in theEvents
set shareUID to (anEvent's sharedUID as string)
if targetUID is shareUID then
return (event info for event anEvent)
exit repeat
end if
end repeat
end LoopThroughEvents:ToGetEventInformationFromTargetUID: