Safari 5 has brought several solutions for managing lists of open tabs, from the simple (like my TabLinks extension) to full session-management capabilities (see the beautiful Sessions extension). However, I’ve found I still like using my EverSave script in many situations, primarily because it allows me to annotate, tag and sync my important sessions for later retrieval. One thing’s been bugging me, though, and that’s the inability to do a mass restore on a tab list (i.e. open them all at once).

When I decided to fix this, the first issue was that when EverSave creates the Evernote note, it lets Evernote convert the list from HTML to Rich Text. Once it’s stored in Rich Text Format (RTF), manipulating it via any shell language, including AppleScript, becomes quite difficult. It’s not impossible, but I quickly decided it wasn’t a route I wanted to wander down. Here’s what I did do…

Saving tabs to Evernote

What I ended up doing was modifying what EverSave stored, and including the actual URL in the visible text of the note. It’s not the prettiest solution, but it’s the only way that this particular system will work. I did my best to minimize the visual presence of the URL using the rudimentary markup that Evernote actually pays attention to. The final product looks like this:


The actual layout is still fully controlled by the _template property in the first line, which is the only line that’s changed from the original script. I’m posting the whole thing again, with this minor revision, for convenience. With a little bit of HTML (remember to escape your double quotes), you can modify the template to look however you like. Just keep in mind that Evernote strips 90% of markup out when it creates the note from your HTML, so stick with basic tags. See the original EverSave post for a breakdown of the script.

Be sure to continue reading after the script to see how we handle the “restore” functionality.

property _template : "<li><strong><a href="%url">&uArr;</a> %name</strong> < <small>%url</small> >"

--search and replace function for template
on snr(tofind, toreplace, TheString)
	set ditd to text item delimiters
	set text item delimiters to tofind
	set textItems to text items of TheString
	set text item delimiters to toreplace
	if (class of TheString is string) then
		set res to textItems as string
	else -- if (class of TheString is Unicode text) then
		set res to textItems as Unicode text
	end if
	set text item delimiters to ditd
	return res
end snr

set prettyDate to do shell script "date '+%A, %B %d, %Y at %l:%M %p'"
set theTitle to "Bookmarks " & prettyDate
set urlList to "<ul>"

tell application "Safari"
	set tabList to every tab of front window
	repeat with aTab in tabList
		set aLink to _template
		set aLink to my snr("%name", name of aTab, aLink)
		set aLink to my snr("%url", URL of aTab, aLink)
		set urlList to urlList & aLink & return
	end repeat
end tell
set urlList to urlList & "</ul>"

tell application "Evernote"
	set theNote to create note with html urlList title theTitle notebook "Bookmarks"
end tell

I have this script saved as “EverSave.scpt” in my ~/Library/Scripts/Applications/Safari folder (create it if you don’t have it), and launch it using FastScripts with a Command-Shift-S shortcut. Safari doesn’t have anything bound to that key-combo, and it’s easy to remember (Save As in most programs).

Restoring tabs

This solution makes a few assumptions, but the script is easily customized to handle any differences in your setup. I went with a System Service (Snow Leopard) for the restore function, primarily because it allows me to act directly on selected text in Evernote. It’s a very simple Ruby script that parses the selected text for urls, and then opens any that it finds in sequential order using your default browser. There’s a commented out line if you want to always target Safari directly when opening them, which may be useful in some situations. I use Choosy, and have a rule that just directs all of these to Safari. If you have Safari set as your default browser, and that’s where you want to open your links, this will just work as is.

To set up the service:

  1. Open Automator and select “Service” as the new file type.
  2. On the right hand side, tell it that “Service receives selected” text in (choose Other… and select Evernote).
  3. Find “Run Shell Script” in the list on the left and drag it into the area on the right.
  4. Set the Shell dropdown to /usr/bin/ruby
  5. Insert the following code, and feel free to modify
  6. Save the result as “EverRestore”
  7. Assign a shortcut key, if desired, in System Preferences > Keyboard > Keyboard Shortcuts > Services

Here’s the code for the service:

ARGF.each do |f|
    links = f.scan /< (https?://.*?) >/mi
    # The above scans specifically for the angle brackets in my template. 
    # If you remove those from the output of EverSave, be sure to update
    # the regular expression accordingly.
    if links.empty? then
        links.each {|link| %x{osascript -e 'open location "#{link[0]}"'}}
        # links.each {|link| %x{osascript -e 'tell application "Safari" to open location "#{link[0]}"'} }

The simple regular expression in line 2 does scan specifically for the angle brackets I used in the new EverSave template. That just relieves some complexity. If you want a regular expression that doesn’t require the angle brackets, try replacing line 2 with this:

links = f.scan /(https?://([^s",;]+)..{2,4}(/[^s",;!]+))/mi

Once it’s saved in Automator, it should be available when you select text in Evernote. If there are visible URLs in the selected text, running this Service will open them in tabs in Safari (or your default browser). You can selectively open certain urls by only selecting the lines that contain the ones you want to open. Non-contiguous selections will require a little text editing, of course.

Not as hard as it looks… really.

The explanation got a little long, and probably seems unnecessarily complex. The fact is, I can save a Safari browsing session with one key combo, edit, annotate and tag it (if I want to), then restore it later by highlighting and typing a new command combination. It’s actually quite convenient, and fairly bulletproof. I’d love to hear how you use it, or what you’re doing instead!