I just realized today, quite belatedly, that you can control GeekTool on your Mac with AppleScript. I just wanted to play around with it a bit, so I threw together a countdown timer. This could be done much more elegantly, I’m sure; I just wanted to see what I could pull off quickly.

The script takes an argument ending in an integer (interpreted as minutes), or a colon-separated hour/minutes argument. The last argument is always the time from now. For example Pick up the kids 1:30 would set a timer for an hour and 30 minutes from now. Feed the fish 10 would set a timer to go off in 10 minutes.

The script calculates the target time and then runs a loop every second to update a GeekTool shell geeklet with the countdown timer. Yes, you could probably do this more efficiently by making use of the Geeklet’s interval property, but… meh, I don’t have an excuse. I kind of thought of that after writing the script. It’s Sunday, lay off.

If you want to play with it, you need to have GeekTool installed and running. Create a Shell Geeklet by dragging the shell icon to your desktop from the GeekTool window. In the properties for the geeklet, name it “GeekTimer” and leave the timeout and refresh values at zero. Size it so that it’s the full width of your screen, set the paragraph justification to centered, pick a font/color and make it as large as you want.

Now, save the AppleScript below as a file called geektooltimer somewhere on your drive. Wherever you put it, you’ll need to adjust any commands that call it to match your own path.

The AppleScript

#!/usr/bin/osascript

on padNum(_num)
	if _num < 10 then set _num to "0" & _num
	return _num
end padNum

on run argv
	set message to item 1 of argv
	
	tell application "GeekTool Helper" to set command of shell geeklet named "GeekTimer" to "echo"
	
	set {astid, AppleScript's text item delimiters} to {AppleScript's text item delimiters, " "}
	set _task to text items 1 thru ((count of text items of message) - 1) of message as string
	set _min to last item of text items of message
	if (offset of ":" in _min) > 0 then
		set AppleScript's text item delimiters to ":"
		set _min to (item 1 of text items of _min) * 60 + (item 2 of text items of _min)
	end if
	set AppleScript's text item delimiters to astid
	
	set _date to current date
	set _target to (_date + (_min * 60))
	repeat
		set timeLeft to (_target - (current date))
		set minLeft to round timeLeft / 60 rounding down
		if minLeft > 60 then
			set minLeft to (round minLeft / 60 rounding down) & ":" & padNum(minLeft mod 60)
		else
			set minLeft to padNum(minLeft)
		end if
		set secLeft to padNum(timeLeft mod 60)
		tell application "GeekTool Helper"
			set command of shell geeklet named "GeekTimer" to "echo \"" & _task & " in " & minLeft & ":" & secLeft & "\""
			
			if (current date)  _target then
				do shell script "/usr/bin/afplay /System/Library/Sounds/Glass.aiff"
				set command of shell geeklet named "GeekTimer" to "echo \"Time to " & _task & "\""
				return "Time to " & _task
			end if
		end tell
		delay 1
	end repeat
end run

Note that the hashbang at the beginning will let you make it executable and call it without osascript, but I used osascript in the methods below just to be safe.

When the timer is up, it will use afplay to ring a bell and set the final text of the Geeklet to your reminder title. I’m pretty sure afplay is included in a standard install, but if you run into issues just remove that line or substitute your own alert method.

As a Bash function

I’m mostly calling this script from the command line. I added a function to ~/.bash_profile that looks like this:

## GeekTool Timer
# `gtt Pick up the kids 1:30` sets a timer for 1 hour and 30 minutes
# `gtt Feed the fish 10` will set a timer for 10 minutes
# Running `gtt` with no arguments will clear the running timer and exit
gtt() {
	# if a timer is running, kill it
	pid=$(ps ax | grep -E "osascript .*/geektooltimer" | grep -v grep | awk '{print $1}')
	[[ $pid ]] && kill $pid
	# Clear any existing text
	/usr/bin/osascript -e 'tell application "GeekTool Helper" to set command of shell geeklet named "GeekTimer" to "echo"'
	# if there are arguments, run the script with them. 
	if [[ $# -gt 0 ]]; then
		/usr/bin/osascript ~/scripts/geektooltimer "$*" 2>&1 &
	fi
}

Drop that into your ~/.bash_profile and run source ~/.bash_profile. Now, in combination with the previous AppleScript, you have a gtt command for setting timers on your desktop from Terminal. Be sure to modify the path in the last command (the one that calls geektooltimer) to match the location of the AppleScript you created.

The function first checks to see if a timer is already running, and if so, kills it. Then it clears any text currently in the “GeekTimer” Geeklet, and then runs the AppleScript and passes all command line arguments as one quoted string. The geektoolreminder script handles parsing out the last number and turns the preceding text into the reminder title. Running just gtt without any arguments will clear the current timer.

There’s not a lot of error checking involved, so incorrect parameters will throw errors on the command line. Feel free to spiff it up.

As a Launchbar (or Alfred or whatever) action

You can also call the script from Launchbar by creating an action like:

on handle_string(message)
	do shell script "/Users/ttscoff/scripts/geektooltimer '" & message & "' &"
end handle_string

Name the action “GeekTool Reminder” (save it in ~/Library/Application Support/Launchbar/Actions/GeekTool Reminder.scpt). You’ll call it up by popping up Launchbar and typing “GTR” or similar, then pressing space. Enter the text of the reminder and end it with a minute or hour:minute designation. Minor catch: execute it with Option-Return to run it in the background, otherwise Launchbar will freeze until the timer is up.

In Alfred you can probably make a straight shell script that runs in the background automatically, so it would be more in line with the Bash function above than with the Launchbar AppleScript method.


What I’m hoping is that this example will get a ball rolling, and someone will see a little bit more exciting potential in it than I came up with on a lazy Sunday. Got a cool AppleScript (or even an idea) for GeekTool? I’d love to hear about it!