Reanimating Chat Logs with AppleScript
The audience at Seven on Seven watched a projection of David Kravitz’s screen as he chatted with Frances Stark in the Messages app for Mac (known as iChat up until 2012). This was their performance Opening the Kimono, a highlight of the conference. Later we kicked ourselves for not capturing David’s screen during the performance. Our documentation consists of this video and an .ichat log file–which David kindly provided. This post is about playing back Opening the Kimono from the log in real-time using AppleScript. For context about the piece, see this article on Rhizome.
What does one get when opening a chat log in Messages? Pretty pastel chat bubbles. But this format is not so easy to parse1. To wrangle the log file, I used the beautifully-named software Logorrhea. Logorrhea exports iChat logs as text files.2 The first line looks like:
SevenOnSevenFrancesStarkDavidKravitz davidkravitz 05/03/2014 16:57:43 hi frances!
The above looks oddly like TSV (Tab-Separated Values). By changing the extension to .tsv, spreadsheet programs will happily open it, yielding something like:
A | B | C | D | E |
---|---|---|---|---|
SevenOnSevenFrancesStarkDavidKravitz | davidkravitz | 05/03/2014 | 16:57:43 | hi frances! |
SevenOnSevenFrancesStarkDavidKravitz | francesstark | 05/03/2014 | 16:57:49 | well hello David! |
… | … | … | … | … |
I’m no spreadsheet wizard, so to find the time elapsed between messages I use Python’s datetime module.
>>> import datetime
>>>
>>> message_time = '16:57:43'
>>> next_message_time = '16:57:49'
>>>
>>> delta = datetime.datetime.strptime(next_message_time, '%H:%M:%S') - datetime.datetime.strptime(message_time, '%H:%M:%S')
>>> print delta.seconds
6
>>>
But what I really want is to convert the log data into a native AppleScript data type–I don’t want to parse anything in AppleScript, ever. Python’s built-in CSV module can parse TSV as well, and with some clever string formatting, one can convert the rows of data into an AppleScript list of lists, which can later be plopped into an AppleScript source file. Here is code to do this:
import csv
import datetime
DELIM = '\t'
PATH = '/Users/scott/Desktop/iChat Export.tsv'
row_buffer = []
output = []
with open(PATH, 'rU') as tsvfile:
tsvreader = csv.reader(tsvfile, delimiter=DELIM)
# load rows in buffer so we can look ahead
row_buffer = [row for row in tsvreader]
for idx, row in enumerate(row_buffer):
try:
next_row = row_buffer[idx + 1]
delta = (datetime.datetime.strptime(next_row[3], '%H:%M:%S')\
- datetime.datetime.strptime(row[3], '%H:%M:%S')).seconds
except IndexError:
delta = 0
output.append('{{"{}",{},"{}"}}'.format(row[1].split('@')[0], delta, row[4].rstrip('\n')))
print '{' + ', '.join(output) + '}'
A subset of the output from the above:
{{"davidkravitz", 6, "hi frances!"}, {"francesstark", 8, "well hello David!"}, {"davidkravitz", 30, "how’s it going?"}, {"francesstark", 9, "I’m feeling more than a little excited about much of what we discussed yesterday"}, {"davidkravitz", 17, "yeah me too"}, {"davidkravitz", 4, "we should start by telling the audience a bit about the start of this whole thing"}, {"davidkravitz", 15, "namely"}, {"davidkravitz", 6, "i had a friend who suggested that we do performance art"}, {"davidkravitz", 6, "well, what he called performance art"}, {"francesstark", 52, "hahahhaha"}}
AppleScript allows OS level automation for programs that implement the interface for it (most do, which makes it very useful).3 To fake the conversation, two chat clients (iChat and Adium) are automated to talk to each other. In the following code sample, pretend I’ve already assigned all the output from the above into a variable called theBigList.
repeat with i from 1 to count of theBigList
set theLine to items of item i of theBigList
set theSender to item 1 of theLine
set theDelay to item 2 of theLine
set theMessage to item 3 of theLine
if (theSender = "davidkravitz") then
tell application "iChat"
set theBuddy to buddy "protonpopsicle" of service "AIM"
send theMessage to theBuddy
end tell
end if
if (theSender = "francesstark") then
tell application "Adium"
send the active chat message theMessage
end tell
end if
delay theDelay
end repeat
After all that work, we (Rhizome) ended up manually recreating the performance with human actors. Why? With the automated method, one cannot see messages being typed into the message box before they are sent. Even though it is possible to simulate this typing with AppleScript, the rhythm of the typing, the puases for comprehension and other subtleties of the performance are not present in the log file. Any further attempt would be a mini Turing Test, where a bot must be programmed to type in such a way as to fool us into believing it is David Kravitz. However, I was able to re-use much of this code to create a script for the human actors which included timing cues.
Footnotes
-
It could be done using AppleScript to scrape data off of the native Mac UI. ↩
-
If one has access to the computer on which the chat occured, there is a sqlite3 database of messages at ~/Library/Messages/chat.db. Also Adium is capable of converting .ichat logs to XML format. ↩
-
A most incredible thing about AppleScript are the “scripting dictionaries”. From Script Editor, go to File > Open Dictionary to view a list of scriptable applications on one’s computer. From here view complete documentation for the scripting interface of each application. ↩