Scripting LittleSnapper… Slight Return

Less then a week after writing this AppleScript — which launches LittleSnapper and snaps the website currently in view in Safari — the boys at Realmac Software come out with this bookmarklet that does exactly the same thing, only with a mouse-click instead of a hot-key combination… unless you’re me.

I loath the mouse and if I can avoid ever using it I will go to great lengths to make sure my hands stay firmly atop my keyboard. Perhaps you’re the same way, so for kicks I turned Realmac Software’s bookmarklet into an executable AppleScript that I can assign a hot-key to.

What’s a bookmarklet?

First you have to understand what a bookmarklet does. A bookmarklet is nothing more then a bit of javascript (in many cases) that when clicked performs a basic task. It’s like a mini application… like an applet… in fact, it is an applet, hence the name “bookmark”-“let”. In the case of the LittleSnapper bookmarklet, clicking the bookmark (or URL) tells your browser (in javascript) to change the URL in the address bar from http://example.com to littlesnapper://snap/http://example.com. You’re just adding littlesnapper://snap/ to the front of any URL! You can actually do this yourself, provided you have LittleSnapper. Try going your favorite website, click the address field, type littlesnapper://snap/ in front of the URL and hit return… ta-da!

Make one-click easier?

So let’s go back to actually using the bookmarklet… you have to click on it and that’s no fun. It’s time to turn it into AppleScript!

The bookmarklet, if you look at it in your bookmarks folder, looks like this:

javascript:location.href='littlesnapper://snap/'+location.href;

The quick and dirty way to turn this into an executable AppleScript would be to use Safari’s built in do JavaScript method, like this:

tell application "Safari"
    do JavaScript "location.href='littlesnapper://snap/'n
    +location.href;" in document 1
end tell

But that would leave you pretty much locked into using the script with Safari when using hot-keys, while clicking the bookmarklet will work in any browser. So do JavaScript is too limiting.

Since we only need to pass in the string littlesnapper://snap/ before the URL, why not just write a method that does that:

tell application "Safari"
    set currentURL to URL of front document
    open location "littlesnapper://snap/" & currentURL
end tell

This works, but if you want to apply it to all other browsers — Opera, Camino, Firefox, etc — you have a lot of work ahead of you as you discover the various degrees of scriptability each app has. To grab the URL in some of these apps you have to jump through hoops:

  • in safari it’s URL of front document
  • for Firefox «class curl» of window 1 will sometimes work
  • Camino is URL of browser window 1 and so on…

Some apps need to use System Events to access them, others don’t. And then try and tell each one that you want to open location, again with or without System Events… it turns into argument soup very quickly.

A good rule of thumb when trying to script anything is to simplify the number of tasks you assign to any given process. In this case, for each browser I am trying to do two things; get the current URL and then open a new, modified URL.

LittleSnapper is a browser too!

Then it got me thinking — LittleSnapper uses webkit as it’s rendering engine and therefor it should share a lot of the same scripting dictionary that Safari uses. So I thought I would test something out; I attempted to open location "littlesnapper://snap... with LittleSnapper itself:

set currentURL to "http://www.google.ca"
tell application "LittleSnapper"
    open location "littlesnapper://snap/" & currentURL
end tell

Viola! Without opening a “browser”, I just snapped a web shot of Google.ca, right in LittleSnapper. This now cuts the workload of running unique scripts for each browser in half since I can now tell LittleSnapper to open the URL… once I have it.

Scripting a common thread

So now to get the URL from the browser — any browser — without making a code spaghetti like this mess:

if application "Firefox"is running then
    tell application "Firefox"
        set currentURL to «class curl» of window 1
    end tell
else if application "Safari"is running then
    tell application "Safari"
        set currentURL to URL of front document
    end tell
else if application "Opera"is running then
    tell application "Opera"
        set props to GetWindowInfo of window 1
        set currentURL to item 1 of props
    end tell
else if application "Camino"is running then
    tell application "Camino"
        set currentURL to URL of window 1
    end tell
end if

There has to be a better way… and there is. Here comes System Events to the rescue with a couple of keystroke executions like so:

tell application "System Events"
    -- highlight address field with ⌘L
    keystroke "l" using {command down}

    -- copy to clipboard with ⌘C
    keystroke "c" using {command down}
end tell

This will allow us to access any browser the same way, with global hot-keys as executed by AppleScript.

Now we just need to talk to those browsers to find out which one is in use. We can do this with an if statement, like this:

if application "Safari" is running then
    tell application "System Events"
        keystroke "l" using {command down}
        keystroke "c" using {command down}
    end tell
end if

But with four or more browsers this would be a bit much.

The full deal

So let’s make an array out of our favorite browsers, run that array through a loop, mash in our System Event keystrokes, and finish it all off with a variable passed into LittleSnapper and this is what we get:

-- let's define our array
set appArray to {"Safari", "Firefox", "Opera", "Camino"}

-- then run that array through a loop
repeat with appName in appArray
    if application appName is running then
        tell application appName to activate
        tell application "System Events"
            keystroke "l" using {command down}
            keystroke "c" using {command down}
        end tell
        delay 0.5

        -- make a variable from the clipboard
        set currentURL to the clipboard
    end if
end repeat

-- pass that variable in to LittleSnapper
tell application "LittleSnapper"
    activate
    open location "littlesnapper://snap/" & currentURL
end tell

Is this overkill to get a hot-key combo that does what a bookmarklet does in one click? Depends on who you ask I guess. I think it’s a pretty good solution in fact. Now instead of copying a bookmarklet to the toolbar of every browser I use, I have a script that I can assign a global hot-key to (via FastScripts or some such tool) and use it across any browser I set in my array.

Yes, I am that much of a geek.

Download

Get it fresh from CodeCollector.net

 

Adam Merrifield

 

Leave a Reply