Python appscript for Audio Hijack

After messing around with my Audio Hijack Pro setup last week, I thought it would be nice to have a command that prints out all my scheduled timers. The usual main page of Audio Hijack Pro shows the timers in the scrolling list on the left side, but doesn’t show the whole schedule at once.

I started writing an AppleScript that I could call from the command line but soon got frustrated with AppleScript’s limited text formatting functions. I decided to try Python with appscript. From the appscript home page:

Appscript is a high-level, user-friendly Apple event bridge that allows you to control scriptable Mac OS X applications using ordinary Python scripts. Appscript makes Python a serious alternative to Apple’s own AppleScript language for automating your Mac.

I’d installed appscript a while ago, and played around with a few examples, but never tried scripts of my own until this one, which I call ahtimers. It goes through the Audio Hijack Pro timers, picks out the scheduled ones (which have a check in the “On” box--see the screen shot above), and prints out a nicely formatted list of the shows, days, and times. For my current setup, running ahtimers from the command line produces this:

Alternative Sixties: ----T-- from  9:00 PM to 10:05 PM  (65 min)
 Mark Steel Lecture: -----F- from  6:00 AM to  6:40 AM  (40 min)
      Saturday Show: S------ from 12:30 AM to  3:35 AM (185 min)
  Sounds of the 60s: S------ from 10:00 AM to 12:05 PM (125 min)
  Sounds of the 70s: -----F- from  7:30 PM to  8:05 PM  (35 min)

I think the output explains itself. What I like about it--and what I was having trouble doing in AppleScript--is how the fields line up for easy reading. The timers are alphabetized by name because that’s how Audio Hijack Pro keeps them ordered. I thought about ordering them according to time, but didn’t see any advantage to it.

Here’s the source code for ahtimers:

 1:  #!/usr/bin/env python
 2:  
 3:  from appscript import *
 4:  import datetime
 5:  
 6:  # Get a list of all the sessions.
 7:  allsessions = app('Audio Hijack Pro').sessions.get()
 8:  
 9:  # Make a list with the sessions that have scheduled timers.
10:  timersessions = []
11:  for s in allsessions:
12:      for t in s.timers.get():
13:          if t.scheduled():
14:            timersessions.append(s)
15:            break # go to next session after finding a scheduled timer
16:  
17:  # Get the length of the longest name of a timersession.
18:  longest = max(len(s.name()) for s in timersessions)
19:  
20:  # Make a 7-character string with the days that the timer runs.
21:  def timerdays(t):
22:    daylist = ['-'] * 7
23:    if t.runs_Sunday():
24:      daylist[0] = 'S'
25:    if t.runs_Monday():
26:      daylist[1] = 'M'
27:    if t.runs_Tuesday():
28:      daylist[2] = 'T'
29:    if t.runs_Wednesday():
30:      daylist[3] = 'W'
31:    if t.runs_Thursday():
32:      daylist[4] = 'T'
33:    if t.runs_Friday():
34:      daylist[5] = 'F'
35:    if t.runs_Saturday():
36:      daylist[6] = 'S'
37:    return ''.join(daylist)
38:  
39:  # Print the info for all the sessions with enabled timers.
40:  for s in timersessions:
41:    for t in s.timers.get():
42:      if t.scheduled():
43:        dur = t.duration()
44:        durstr = '(%d min)' % (dur/60)
45:        st = t.start_time()
46:        et = st + datetime.timedelta(seconds = dur)
47:        dow = timerdays(t)
48:        ststr = st.strftime("%l:%M %p")
49:        etstr = et.strftime("%l:%M %p")
50:        fmtstr = "%" + str(longest) + "s: %s from %s to %s %s"
51:        print fmtstr % (s.name(), dow, ststr, etstr, durstr.rjust(9))

The longest show name, determined from the generator on line 18, is used to create the format string in line 50 which gets all the names lined up and right justified. The days of the week are formatted through the timerdays function in lines 21-37. The start and end times line up because of the %l format string in lines 48 and 49; it puts a space before single-digit hours. The durations at the end of each line are aligned by the rjust(9) method in line 51; I used a specific number for the field width because I feel pretty confident that I’ll never have a timer that records for more than 999 minutes (over 16 hours). And if I’m wrong about that, it will only screw up the alignment at the end of the line, which isn’t a big deal.

Overall, I found appscript pretty easy to work with. The get() method is a bit of a mystery to me--it was needed to get the sessions and timers lists, for example, but not needed to get a timer’s duration or start time--but I suspect there’s a good reason for it that I’ll learn as I keep using it.

The biggest problem with using appscript (or rb-appscript for Ruby) rather than AppleScript is that it isn’t included with the system. If you’re developing scripts to be used by others--especially nonprogrammers--you can’t expect them to have or install appscript. I’ve read that PyObjC is expected to be included with Leopard but haven’t heard the same about appscript. I have my fingers crossed.

Tags: