Skip to content

Instantly share code, notes, and snippets.

@hepcat72
Forked from mlgill/New reminder from Launchbar
Last active September 23, 2016 16:41
Show Gist options
  • Save hepcat72/c34c2b96eba23a1aa424757d066aa07d to your computer and use it in GitHub Desktop.
Save hepcat72/c34c2b96eba23a1aa424757d066aa07d to your computer and use it in GitHub Desktop.
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
--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.
--09/23/2016 * Prevented an endless loop when no day of the week is provided in the input string by checking for sun, mon, tue, etc.
--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 if ("sun" is in theRelativeDayStr or "mon" is in theRelativeDayStr or "tue" is in theRelativeDayStr or "wed" is in theRelativeDayStr or "thu" is in theRelativeDayStr or "fri" is in theRelativeDayStr or "sat" is in theRelativeDayStr) then
-- 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment