Home

You’re Doing That Wrong is a journal of various successes and failures by Dan Sturm.

iSight Scripting Redux

I was looking through some old photos on my iPhone the other day, reminiscing. Unfortunately, there weren’t a lot of photos from the period of time I was scrolling through. My craving for personal nostalgia was not fully satisfied. Luckily, I remembered another place I might find a few more memories to peruse: my iSight Capture folder in my Dropbox archive.

To spare you the headache of reading that meandering, ill-framed, eight-year-old blog post, here’s the gist of what I built back in 2012.

I set up a bash script and launchd task that used a CLI tool I found called isightcapture to take a photo through my MacBook Pro’s iSight camera every 2 hours, and put them in a Dropbox folder.

I had some grand idea that this would help me locate my laptop if it were ever stolen; giving me photographic clues to its location. Which was incredibly stupid.

But, in setting up this little script, I inadvertently created a sort of photo diary for myself. These incredibly unremarkable images gave me a consistent snapshot of my day-to-day life that, as the months and years passed, became an incredible record of one of the more interesting (to me) periods of my life.

The photos themselves are terrible quality. They’re 640x480 resolution. They’re dark, grainy, and usually framed badly. In some cases, you can barely even see me. But I can see me.

I can see the frustration and immaturity on my face in 2012 — my last year at Intel — before I left to pursue…something I hadn’t worked out yet.

I can see myself doing everything in my power to suppress a sea of self-doubt when I found myself working in the Sandwich Video office for a few weeks in 2013. I was absolutely exhausted driving back and forth between Phoenix and Los Angeles probably a dozen times over the course of a few months. But I was (and still am) so grateful for everything I learned from that experience.

I can see the unexpected enthusiasm on my face as I taught two semesters of post-production finishing and vfx at the film school at Scottsdale Community College; taking over for a professor who had moved away.

There are the backstage photos of those sales and marketing conferences I worked. The ones where we basically didn’t sleep for three days, shooting and editing around the clock.

I see my temporary office setup in the family room of my dad’s house where I lived for a month after moving back to Phoenix from San Jose. Behind me in the photos are the dozens of moving boxes my now-wife and I couldn’t unpack until we found a new place to live. (I really didn’t plan that career/life transition well at all.)

I can see a whole lot in those crappy, automated webcam photos.

May 26, 2016

I don’t remember why, but in May of 2016, my script broke. This is the last photo it took.

I figured I’d find a way to fix it, at some point. Eventually, though, I just gave up and moved the folder of images into my unsynced Dropbox archive folder.

But, looking through those old photos gave me the motivation to give it another shot.

ImageSnap

In the years since my script broke, isightcapture has been abandoned. I found a thread in a forum somewhere mentioning ImageSnap as a potential replacement, and it turned out to be perfect for my needs.

First of all, it’s able to capture the full resolution of my 2020 iMac’s new 1920x1080 FaceTime camera. Still, each photo is only about 250 KB.

Second, it’s much faster than isightcapture. Both apps, when taking a photo, activated the camera’s green “active” light (as they should). But with isightcapture, I was occasionally able to notice the green light in my peripheral vision, look at the camera, and pose for the photo. So far, no matter how quick my reaction time, each photo taken by ImageSnap has been captured before my eyes were able to dart up to the camera. Which is exactly what I want.

I’m genuinely surprised just how fast it is. Especially because the command I’m using to take the photo includes a one second delay to let the camera “warm up”. The hardware (apparently) needs that to avoid occasionally taking an underexposed image.

Here’s the single-line shell script that takes the photo:

/usr/local/bin/imagesnap -d "FaceTime HD Camera (Built-in)" -q -w 1 /Users/dansturm/Dropbox/Photos/iSight_Capture/$(date +"%F—%H-%M-%S").jpg

Automator?

I’m running this script by way of an Automator “Application” because, thanks to macOS Catalina, things that access the camera of my Mac need to throw a macOS system permissions dialogue box so I can grant them explicit access to the hardware. Currently [1], running the command directly inside Keyboard Maestro does not cause the system to prompt for camera permissions, so the command fails.

Not to worry, though. We’ll use Keyboard Maestro to launch the Automator application at the interval of our choosing because it has great trigger options.

Having the app take a photo every two hours was never ideal. A full third of the images are just black because they were taken in the dead of night. And another third were of my empty office chair. Not terribly interesting.

So, this time around, I set the macro to trigger at 10am, 1pm, and 4pm. Three times I can almost guarantee I’ll be sitting at my desk, in front of the camera. And the Keyboard Maestro trigger is flexible enough that, if I decide later to expand the window of time or frequency of images, it’s an easy adjustment.

It’s a little strange how excited I was to get this thing working again. My life is far less unpredictable than it was eight years ago, and it’s likely that I’ll just end up with hundreds of photos that looks exactly the same, featuring nothing of any real interest.

But, you know, that’s exactly what I thought the first time I set it up.


  1. Thanks to Dr. Drang and Peter N Lewis for helping me diagnose this issue. And it sounds like Peter is working on a fix.  ↩

Experiments in iSight Scripting

A week or two ago, a conversation with my girlfriend reminded me of this old video from the Defcon 18 Conference, in which a hacker by the name of Zoz recounts the tale of how he located and recovered his recently-stolen computer by way of some fancy Internet skills. In addition to being a great reminder about data safety and security, it’s a pretty damn funny story.

Re-watching the video reminded me I’ve always wanted to experiment with scripting the iSight camera on my MacBook Pro. Not necessarily for the purpose of having photo evidence in the event of a theft, but more as a fun exercise in scripting and automation. Maybe I’m easily entertained (rhetorical), but I found the process and results throughly enjoyable.

Command Line Tools

The first thing I needed was a command line interface to the iSight camera. Despite my best Googling efforts, I wasn’t able to find any native OS tools to fire the camera (I’m still not sure if there is one). But lucky for me, nearly every search I did pointed me to a free, no-longer-supported-but-still-functional CLI tool called iSightCapture. Installation is as simple as tossing it into /usr/local/bin.

Regarding syntax, here’s the pertinent information from the iSightCapture readme file:

isightcapture [-v] [-d] [-n frame-no] [-w width] [-h height] [-t jpg|png|tiff|bmp] output-filename

Options
-v output version information and exit
-d enable debugging messages. Off by default
-n capture nth-frame
-w output file pixel width. Defaults to 640 pixels.
-h output file pixel height. Defaults to 480 pixels.
-t output format - one of jpg, png, tiff or bmp. Defaults to JPEG.

Examples
$ ./isightcapture image.jpg
will output a 640x480 image in JPEG format

$ ./isightcapture -w 320 -h 240 -t png image.png
will output a scaled 320x240 image in PNG format

Triggering

I wanted the ability to remotely trigger the iSight camera from my phone, and have it run for a predefined interval of time. To do this, I’d use a watch folder and a trigger file, uploaded from my phone, to initiate the script. This would theoretically be the method I’d use to “gather photographic evidence” in the event my laptop is stolen.

As usual, to set this up, I turned to my trusty friend Dropbox. To keep things tidy, I needed a couple of folders. The directory structure looks like this:

  • iSight_backup
    • scripts
    • trigger

The photos taken by the script will be placed in the top level directory, iSight_backup. The script itself would be placed in the scripts folder, and the trigger folder remains empty, awaiting a text file to be uploaded via Dropbox on my phone.

The Script

Here’s the script, called isbackup_t.bash, and saved into my iSight_backup/scripts/ folder:

#!/bin/bash  

#   path to iSightCapture CLI tool  
APPP="/usr/local/bin/isightcapture"  

#   path to Dropbox folder to receive photos  
FPATH="/Path/To/Dropbox/iSight_backup/" 

#   path to trigger file  
TPATH="/Path/To/Dropbox/iSight_backup/trigger/"  

#   select photo filetype; jpg, png, tiff, or bmp  
XTN=".jpg"  

#   number of photos to take  
PNUM="24"  

#   interval between photos (seconds)  
PINT="300"  

for i in `seq 1 $PNUM`;  
    do
        DTS=$(date -u +"%F--%H-%M-%S")  
        $APPP "$FPATH$DTS$XTN"  
        sleep $PINT  
    done  

rm $TPATH*  

The Details

Each photo gets a date and time stamp added to the file name for easy sorting. Since the FPATH destination is set to a folder within my Dropbox, and each file is a 640x480 jpeg, approximately 25kb in size, I can see the resulting photos on my phone just seconds after their taken.

By setting PNUM to 24, and PINT to 300, the script will take a photo every 5 minutes, for the next 2 hours, then stop until I upload another trigger file. However, since the script itself lives in Dropbox, I can change the interval or duration variables from my iOS text editor at any time.

Tying The Room Together

All that’s left to complete our little project is to create a launchd task to keep an eye on our trigger folder, and fire up the script if anything lands inside. Since creating, modifying, or using launchd tasks via any method other than a GUI is currently beyond me, I turned to Lingon.

Here’s the resulting launchd task:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>isbackup triggered</string>
    <key>ProgramArguments</key>
    <array>
        <string>bash</string>
        <string>/Path/To/Dropbox/iSight_backup/scripts/isbackup_t.bash</string>
    </array>
    <key>QueueDirectories</key>
    <array>
        <string>/Path/To/Dropbox/iSight_backup/trigger</string>
    </array>
</dict>
</plist>

And just like that, we’ve got a setup that will monitor our trigger folder, fire up our script when it sees anything inside, and save each file to our Dropbox.

Extra Credit

During my research for this project, I found a number of people using iSightCapture for things other than a makeshift security tool. Some, for example, used it to take a self portrait at login every day and auto-upload it to an online photo diary.

I thought that was a fun idea, so I wrote a second, shorter version of my script to automatically take a shot every 2 hours without the need for a trigger. For my version, however, I was most definitely not interested in auto-uploading the photos.

The script:

#!/bin/bash

APPP="/usr/local/bin/isightcapture"
FPATH="/Path/To/Dropbox/iSight_backup/"
DTS=$(date -u +"%F--%H-%M-%S")
XTN=".jpg"

$APPP "$FPATH$DTS$XTN"

And the launchd task:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Disabled</key>
    <false/>
    <key>KeepAlive</key>
    <false/>
    <key>Label</key>
    <string>IS Secuirty</string>
    <key>ProgramArguments</key>
    <array>
        <string>bash</string>
        <string>/Path/To/Dropbox/iSight_backup/scripts/isbackup.bash</string>
    </array>
    <key>QueueDirectories</key>
    <array/>
    <key>RunAtLoad</key>
    <true/>
    <key>StartInterval</key>
    <integer>7200</integer>
</dict>
</plist>

Since I typically use a multiple monitor setup when working, I almost never see the green light come on when the script runs and when I check the photo directory, usually the beginning of the next day, I’m treated to at least a couple hilarious images. Like these, for example:

Hi Merlin!

I may be asleep in this photo. I can't tell.

No, that's not my poster. My girlfriend got to decorate that side of the room.

Yes, It makes Skype calls awkward. Then again, so does that hair.

Cleanup

Despite the photos being almost inconsequentially small in file size, I really don’t need to be keeping a long-running historical record of my disheveled appearance. To keep things from getting unwieldy, I created a Hazel rule that deletes files older than 2 weeks. I see no reason I’d need to keep them any longer than that.

Why?

I don’t know if it’s because this little project was so different from my day to day work, or I thought it would be a genuinely useful security tool, or I’m a narcissist that loves seeing pictures of himself (again, rhetorical), but I had a blast playing around with this little project.

As with nearly everything on this blog, I learned some things, failed a few times, and came out the other side with a fun little script I can demo to people, making it absolutely certain they’ll never ask me anything about computers again.