public

A script for quickly adding reminders to the Reminders app in Mountain Lion from Launchbar and Alfred. Save this as a .scpt and drop it in ~/Library/Application\ Support/LaunchBar/Actions

  • Download Gist
New reminder from Launchbar
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
--Script for setting Reminders for LaunchBar and Alfred
--For Alfred, Applescript must NOT be set to run in Background otherwise date parsing does not work
--For LaunchBar, place the script in ~/Library/Scripts/LaunchBar
--by Michelle L. Gill, 10/07/2012
--Inspired by https://gist.github.com/3187630
--A related Alfred version 2 workflow can be found here: https://github.com/mlgill/alfred-workflow-create-reminder
 
--Changes
--02/01/2013 * Fixed an issue with setting the time when the hour is 12 and AM/PM (12-hour clock) is used
-- * Removed the ability to set seconds for the time since Reminders doesn't recognize them
--02/02/2013 * Fixed a regression in setting the date when only the hour is present
-- * Added the ability to return information from the created reminder as a string for error checking.
-- * This returned string can be sent to Growl (if installed) to post a notification. For Alfred, the
-- option to post the returned string via Growl has been commented out by default
-- since the forthcoming version of Alfred will use this script via workflows and
-- they have their own method of notification posting. If you're using alfred version 1,
-- uncomment the appropriate line below. Note that posting notifications via Mountain Lion's
-- Notification Center is not possible without incorporating additional tools (an application).
-- I **DO NOT** plan to add notification center support to this script for this reason. (However,
-- notification support can be used within the workflows in Alfred 2.
 
--Notes on valid reminders
--Order of the text must be "title #note $list @date time" but note
--List is optional if a default is set within the script
--Time must be included, but date can be omitted and is assumed to be today
--Time can be in 12- or 24-hour format, and 24-hour format is assumed if am/pm are absent
--Time can be either just the hour or colon separated (hour:minute)
--Numerical dates are listed as month/day/year and year isn't required
--Relative dates such as "Today" and "Tomorrow" can be used, as well as days of the week
--Relative dates are case instensitive and can be abbreviated, i.e. "mon" for "Monday"
--If the day of the week is entered as "Sunday" and today is Sunday, 7 days from today will be returned
--"Next" can be added to relative dates return an additional seven days from the appropriate day of the week */
 
--Examples of valid reminders:
--Buy Milk #note about milk $Personal @10/7/2012 5:00 PM
--Buy Milk #note about Milk @10/7/2012 5:00 PM
--Buy Milk $Personal @10/7/2012 5:00PM
--Buy Milk @10/7/2012 5:00 PM
--Buy Milk @10/7/12 5:00pm
--Buy Milk @10/7/12 5pm
--Buy Milk @10/7 5pm
--Buy Milk @Tomorrow 5pm
--Buy Milk @tomorrow 5pm
--Buy Milk @tom 5pm
--Buy Milk @Sunday 5pm this returns 10/14/2012 if today is Sunday, 10/7/2012
--Buy Milk @sunday 5pm this returns 10/14/2012 if today is Sunday, 10/7/2012
--Buy Milk @sun 5pm this returns 10/14/2012 if today is Sunday, 10/7/2012
--Buy Milk @Next Sunday 5pm this returns 10/21/2012 if today is Sunday, 10/7/2012
--Buy Milk @next sun 5pm this returns 10/21/2012 if today is Sunday, 10/7/2012
--Buy Milk @today 17 this assumes time is in 24-hour format (i.e. 5pm)
--Buy Milk @today 5 this also assumes time is in 24-hour format (i.e. 5am)
--Buy Milk @5pm this also assumes time is in 12-hour format
--Buy Milk @5 this also assumes time is in 24-hour format (i.e. 5am)
 
--set this to the name of the default Reminders list
property myDefaultList : "Personal"
 
-- for Alfred
on alfred_script(str)
set theResultString to my parse_reminder_string(str)
-- uncomment the next line to post a growl notification for Alfred version 1
-- post_growl_notification(theResultString)
end alfred_script
 
-- for LaunchBar
on handle_string(str)
set theResultString to my parse_reminder_string(str)
-- post growl notification if available
post_growl_notification(theResultString)
end handle_string
 
 
-- subroutines
on parse_reminder_string(str)
--separate the time string and get the value
set arrayWithDate to my theSplit(str, "@")
if arrayWithDate's length > 1 then
set theDate to my parseDate(getArrayValue(arrayWithDate, 2))
end if
--separate the Reminders list name if present
set arrayWithListName to my theSplit(getArrayValue(arrayWithDate, 1), "$")
if arrayWithListName's length > 1 then
set listName to my getArrayValue(arrayWithListName, 2) as string
else
set listName to myDefaultList
end if
--separate the note for the reminder if present
set arrayWithBody to my theSplit(getArrayValue(arrayWithListName, 1), "#")
if arrayWithBody's length > 1 then
set reminderBody to my getArrayValue(arrayWithBody, 2)
else
set reminderBody to ""
end if
set reminderName to getArrayValue(arrayWithBody, 1)
tell application "Reminders"
try
set listName to list listName
set newReminder to make new reminder with properties {name:reminderName, container:listName, body:reminderBody, remind me date:theDate}
set theReminderIDString to id of newReminder as string
set theResultString to my get_reminder_data(theReminderIDString)
on error
--set newReminder to make new reminder with properties {name:reminderName, container:listName, body:reminderBody}
set theResultString to "There was an error creating the reminder."
end try
end tell
return theResultString
end parse_reminder_string
 
on theSplit(theString, theDelim)
set oldDelimiters to AppleScript's text item delimiters
set AppleScript's text item delimiters to theDelim
set theArray to every text item of theString
set theTrimmedArray to {}
repeat with currentSplitString in theArray
if currentSplitString as string is not equal to "" then
set currentTrimmedString to trim(currentSplitString)
copy currentTrimmedString to the end of theTrimmedArray
end if
end repeat
set AppleScript's text item delimiters to oldDelimiters
return theTrimmedArray
end theSplit
 
on getArrayValue(array, location)
return item location in array
end getArrayValue
 
on parseDate(theDateStr)
-- todo: parsing pseudo-natural language date and time with applescript
-- is a pain and rife with special cases (bugs). should convert this
-- subroutine to python and use a real natural language parser.
set theDate to current date
set time of theDate to 0
-- parse the time --
-- applescript's text parsing seems very promiscuous
-- e.g. if letters end up part of the date, they are simply ignored rather than
-- producing an error. this is a lot of work to check for everything, so
-- it hasn't been implemented yet
-- first check for am/pm
set theDateStrOrig to theDateStr
set theDateStr to getArrayValue(theSplit(theDateStr, "am"), 1) as string
set theDateStr to getArrayValue(theSplit(theDateStr, "AM"), 1) as string
if theDateStrOrig is not in theDateStr then
set usesAM to true
else
set usesAM to false
end if
set theDateStrOrig to theDateStr
set theDateStr to getArrayValue(theSplit(theDateStr, "pm"), 1) as string
set theDateStr to getArrayValue(theSplit(theDateStr, "PM"), 1) as string
if theDateStrOrig is not in theDateStr then
set usesPM to true
else
set usesPM to false
end if
-- todo: should throw an error if usesPM and usesAM end up being true
-- split the string into date and time
set theDateTimeArray to theSplit(theDateStr, " ")
-- get the time, which is the last element of theDateTimeArray
set theTimeStr to getArrayValue(theDateTimeArray, -1) as string
set theTimeArray to theSplit(theTimeStr, ":")
-- get the time variables
set theHours to item 1 of theTimeArray
if theTimeArray's length > 1 then
set theMinutes to item 2 of theTimeArray
else
set theMinutes to 0
end if
-- determine how to adjust the hours for am/pm
if (theHours as integer = 12) and usesAM then
set hoursAdjust to -12
else if (theHours as integer ≠ 12) and usesPM then
set hoursAdjust to 12
else
set hoursAdjust to 0
end if
-- calculate the time
set time of theDate to (time of theDate) + (theHours + hoursAdjust) * 3600
set time of theDate to (time of theDate) + theMinutes * 60
-- now parse the date if present --
if theDateTimeArray's length > 1 then
set theDateArray to items 1 thru -2 of theDateTimeArray
set theDateArrayLen to the count of items in theDateArray
-- first see if this is a relative date involving "next"
if theDateArrayLen = 2 then
set theRelativeDateStr to getArrayValue(theDateArray, 1) as string
set theWeekdayStr to getArrayValue(theDateArray, 2) as string
if "next" is in theRelativeDateStr then
-- setting forward 8 days which prevents one week from today being returned for "next sunday" if today is sunday
set time of theDate to (time of theDate) + (8 * 24 * 3600)
end if
set theDate to getWeekday(theDate, theWeekdayStr)
else
-- look for backslashes to decide if this date is relative or numerical
set theDateArraySplit to theSplit(getArrayValue(theDateArray, 1), "/")
set theDateArraySplitLen to the count of items in theDateArraySplit
if theDateArraySplitLen = 1 then
-- relative date without "next", i.e. today, tomorrow, monday, etc.
set theRelativeDayStr to getArrayValue(theDateArraySplit, 1) as string
if "tod" is in theRelativeDayStr then
set theDate to theDate
else if "tom" is in theRelativeDayStr then
set time of theDate to (time of theDate) + (24 * 3600)
else
-- this prevents today's date from being returned if current day of week is entered
set time of theDate to (time of theDate) + (24 * 3600)
set theDate to getWeekday(theDate, theRelativeDayStr)
end if
else
-- numerical date
set month of theDate to (item 1 of theDateArraySplit) as integer
set day of theDate to (item 2 of theDateArraySplit) as integer
try
set theNewYear to (item 3 of theDateArraySplit) as integer
if theNewYear < 100 then
set theCurrentYear to (year of theDate) as integer
set theNewYear to theNewYear + ((theCurrentYear / 100) as integer) * 100
end if
set year of theDate to theNewYear
end try
end if
end if
end if
return theDate
end parseDate
 
on get_reminder_data(reminderIDString)
tell application "Reminders"
-- get the reminder reference
set theReminder to reminder id reminderIDString
-- get the reminder properties
set theRemProps to properties of theReminder
-- get the list properties
set theListProps to properties of container of theReminder
-- title, due date, note from reminder properties
set theTitle to name of theRemProps
set theDueDate to due date of theRemProps
set theNote to body of theRemProps
-- list name from list properties
set theListName to name of theListProps
end tell
-- create a string with info
set theString to "Created Reminder '" & theTitle & "' on list '" & theListName & "' due on " & theDueDate
if theNote is not "" then
set theString to theString & " with note '" & theNote & "'"
end if
set theString to theString & "."
return theString
end get_reminder_data
 
on post_growl_notification(theString)
-- crap that Growl needs before it will post a reminder
set allNotificationsList to {"Create Reminder Result"}
set enabledNotificationsList to {"Create Reminder Result"}
try
tell application "Growl"
register as application ¬
"Create Reminder" all notifications allNotificationsList ¬
default notifications enabledNotificationsList ¬
icon of application "Reminders"
notify with name ¬
"Create Reminder Result" title ¬
"Create Reminder Result" description ¬
theString application name "Create Reminder"
end tell
end try
end post_growl_notification
 
on getWeekday(theDate, theWeekdayStr)
repeat until theWeekdayStr is in ((weekday of theDate) as string)
set time of theDate to (time of theDate) + (24 * 3600)
end repeat
return theDate
end getWeekday
 
on trim(someText)
-- trimming subroutine from: http://macscripter.net/viewtopic.php?id=18519
repeat until someText does not start with " "
set someText to text 2 thru -1 of someText
end repeat
repeat until someText does not end with " "
set someText to text 1 thru -2 of someText
end repeat
return someText
end trim

This is an updated version of Jayphen's AppleScript to create Reminders using LaunchBar which has an option to include the name of the task list in Reminders. If no name is provided, then "Inbox" will be chosen. Here is the syntax:

 title of the reminder #some notes $reminder task list @29/07/2012 16:45

All the other entry restrictions (day/month/year and 24-hour time) are the same as the previous version.

Selection of the task list requires an exact match, so I had to add a subroutine to trim spaces off the end of the string. Since this is generally good practice anyway, trimming is done every time a string is split.

Updated the date parsing to handle relative days ("Today" and "Tomorrow") and days of the week. So, something like this is now possible:

 title of the reminder #some notes $reminder task list @Tomorrow 16:45

Updated to be compatible with Alfred and LaunchBar. Date is optional and can be entered as "Today", "Tomorrow", "Saturday", "Next Monday" or numerically with month/day/year where year is optional and can be two or four digit format. If no date is entered, "Today" is assumed. Time can be entered in 12- or 24-hour format and minutes and seconds are optional.

The default Reminders list is set after the comments.

Examples of valid reminders:

 Buy Milk #note about milk $Personal @10/7/2012 5:00:00 PM
 Buy Milk #note about Milk @10/7/2012 5:00:00 PM
 Buy Milk $Personal @10/7/2012 5:00:00 PM
 Buy Milk @10/7/2012 5:00:00 PM
 Buy Milk @10/7/12 5:00:00 PM
 Buy Milk @10/7/12 5:00:00 pm
 Buy Milk @10/7/12 5:00:00pm
 Buy Milk @10/7/12 5:00pm
 Buy Milk @10/7/12 5pm
 Buy Milk @10/7 5pm
 Buy Milk @Today 5pm
 Buy Milk @today 5pm
 Buy Milk @Tomorrow 5pm
 Buy Milk @tomorrow 5pm
 Buy Milk @Sunday 5pm               this returns 10/14/2012 if today is Sunday, 10/7/2012
 Buy Milk @Next Sunday 5pm        this returns 10/21/2012 if today is Sunday, 10/7/2012
 Buy Milk @next Sunday 5pm          this returns 10/21/2012 if today is Sunday, 10/7/2012
 Buy Milk @today 5am
 Buy Milk @today 17             this assumes time is in 24-hour format (i.e. 5pm)
 Buy Milk @today 5              this also assumes time is in 24-hour format (i.e. 5am)
 Buy Milk @5pm

Updated script to also support lower case and shortened relative days, i.e. "sun" for "Sunday and "tom" for "Tomorrow"

Love it! Many thanks. Helping to weed me off of using OmniFocus. (Now if only these todo's would show up side-saddle on iCal, like they used to...)

Can I put in a request for support of these relative dates:

Buy Milk @today -- sets it to 5pm today (if it's before 5pm, or else 11:59pm or some such (defaults can be hardwired as configs within script)
Buy Milk @tomorrow -- sets it to 5pm tomorrow
(etc.... allowing you to leave the time off, and have the time just be set to 5pm (say) on that particular day.)

Updated the script to (hopefully) correct issues with handling times that have 12 for the hour and use the am/pm designation (12-hour clock). Also removed the parsing for seconds in the time as Reminders.app doesn't use seconds (oops).

Fixed a regression in setting the date when only the hour is present

Added the ability to return information from the created reminder as a string for error checking. This returned string can be sent to Growl (if installed) to post a notification.

For Alfred, the option to post the returned string via Growl has been commented out by default since the forthcoming version of Alfred will use this script via workflows and they have their own method of notification posting.

Note that posting notifications via Mountain Lion's Notification Center is not possible without incorporating additional tools (an application). I DO NOT plan to add notification center support to this script for this reason. (However, notification support can still be used within the workflows in Alfred 2.)

Hi

This sounds awesome, but I have some problems getting it to work. I installed it in Alfred 2 but it won't run when I enter e.g.: Køb mælk $Personal @Tomorrow 4pm

What am I doing wrong?

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.