Scripting Safari

I am new to Mac programming.  I have downloaded Xcode and MacRuby and have some familiarity with Objective-C and common Unix tools.  I had thought that I might stick to MacRuby for any immediate projects so that I could get the “feel” of the system quickly.

I was not sure what I wanted to tackle as a first project.  I wrote a traditional “Hello, world!” application and ran it.


#!/usr/local/bin/macruby

puts "Hello, world!"
puts "Testing."

I opted to edit the code in vi.  I soon found that vi on the Mac is actually vim.  Cool!

I searched through a few sites and found an interesting Ars Technica article on using the Scripting Bridge via MacRuby to eliminate the need to use AppleScript to control other applications:

http://arstechnica.com/apple/2011/09/tutorial-os-x-automation-with-macruby-and-the-scripting-bridge/

One of the scripts in the article lists the names of the sites in all of the tabs for a running instance of Safari.  I thought it would be nice to try to write a script that would invoke Safari and open various tabs for a handful of sites that I visit regularly.  I’d like to have tabs open for Google, Twitter,YCombinator / HackerNews, and GMail.

I soon found that in order to familiarize myself with the scriptable objects in Safari, I’d have to use the AppleScript Editor.  I invoked the editor, and opened the dictionary entry for Safari:

Unfortunately, the object reference seems to be geared toward AppleScript.  I couldn’t figure out how to invoke the chain of expressions in MacRuby to do what the AppleScript I had ended up finding on the web could accomplish.  I tried to simply call the Safari.application object’s open() method with a URL:


#!/usr/local/bin/macruby

framework "ScriptingBridge"

safari=SBApplication.applicationWithBundleIdentifier("com.apple.Safari")
safari.open "http://www.google.com"

Arrrgh! Safari then tried to open a file on the filesystem itself with the argument that I had specified, prefixed with the “file://” protocol:

I experimented with the Do JavaScript directive in AppleScript to see if I could use a window.open() call from JavaScript to open new tabs.  When I couldn’t exactly figure out the syntax for that in MacRuby, I wondered, “What if I just open a local HTML file that has a JS payload that can open these tabs?”

I created this HTML file:

<html><head /><body>
<script type="text/javascript">
   var sites=[
      "https://mail.google.com",
      "https://twitter.com",
      "http://news.ycombinator.com"
    ] ;
   function openMore() {
      var i;
      for(i in sites) {
         window.open(sites[i]);
      }
   }
</script>
Loading...please wait.
</body></html>

After a lot of experimentation, I found that I just wasn’t going to figure out enough about how to properly script Safari in MacRuby at this juncture.  So, my pet project changed slightly into something different.  I decided to use a simple Bash script as a wrapper for a small AppleScript script.

After a quick Google search, I found that Bash supports arrays.  Good.  I wanted to be able to specify a list of URL’s at the top of the script.  I would then add code to iterate through the list and open each URL in a tab of its own.

As luck would have it, I couldn’t get any of the array samples that I found to work.  Why? I suspect that the default Bash implementation on OS/X (Lion) is a bit old:


$ bash --version

GNU bash, version 3.2.48(1)-release (x86_64-apple-darwin11)
Copyright (C) 2007 Free Software Foundation, Inc.

Hmmm.  Copyright 2007.  Okay, maybe it was a lofty goal to expect to be able to use a list of strings from the stock version of Bash.  I wrote a function called saf() that will pass a URL to an AppleScript file.

mysafari.sh


#!/bin/bash
function saf {
 osascript $HOME/Progs/mysafari.scpt $1
}

open -a safari "http://www.google.com"

saf https://mail.google.com
saf https://twitter.com
saf http://news.ycombinator.com

I first invoke Safari via the open command and direct it to Google.  This gives me a running instance for use within the AppleScript code:

mysafari.scpt


on run argv
   tell front window of application "Safari"
      set newTab to make new tab
      set the URL of newTab to item 1 of argv
      set the current tab to newTab
   end tell
end run

Now, I can invoke the script from a terminal prompt by typing


./mysafari.sh

…which yields my desired Safari session:

I also toyed with the idea of specifying the entire script in the osascript command-line and I toyed with the idea of compiling the AppleScript code.

I think that I may still revisit this subject later, perhaps using MacRuby to put a decent UI on top of the script so that I can edit the URL list more easily.

( Please see comments for a contributed MacRuby solution…)

Advertisements

About Jim Lawless

I've been programming computers for about 36 years ... 30 of that professionally. I've been a teacher, I've worked as a consultant, and have written articles here and there for publications like Dr. Dobbs Journal, The C/C++ Users Journal, Nuts and Volts, and others.
This entry was posted in Technology and tagged , , , , . Bookmark the permalink.

2 Responses to Scripting Safari

  1. Mateus says:

    hi Jim, you can solve it with MacRuby like this:

    #!/usr/bin/env macruby -wKU
    framework “ScriptingBridge”

    safari = SBApplication.applicationWithBundleIdentifier(“com.apple.Safari”)
    new_window = SafariDocument.alloc.init # create a new window
    safari.windows < site}) # create a new tab
    safari.windows.first.tabs << new_tab # add the tab to the window
    end

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s