Duplicating Safari browsing sessions between Macs
Hey, you’re just in time for another “stupid trick of the day” script. I have good reason for this one, and it only took me about 8 minutes to set up. It will take me longer to write about it than it’s probably worth, but it might be of use to anyone in a similar situation. Here’s the scenario:
I bought a MacBook Air recently. I have never been this happy with an Apple hardware purchase before. Not to gush, but I’ve bought and loved a lot of Macs and this one takes the cake. I’m doing more and more of my everyday work and writing on it, but I still like to sit down at the dual-monitor setup of my Mac Pro fairly regularly. When I do that, the Air becomes an auxiliary machine and I offload most of my chat and social apps to it. The annoying side of this setup is that I end up with Safari tabs piling up on both Macs, and half of them really make more sense on the other machine.
I wrote a pair of scripts that execute over SSH to pull in all of the browser tabs from the front window of Safari on the other Mac into new tabs on the one calling the script. They’re designed to run on Macs on the same network, though they’d work remotely if you could think of a reason to do it. I run it in both directions, and call it with a simple do shell script
AppleScript in ~/Library/Scripts/Applications/Safari
so it’s in my menubar when I’m browsing.
Just a few prerequisites:
- You need keyless ssh set up between the two (or more) Macs. If you want a two-way sync, you need keys in both directions. This article has everything you need.
- To keep things simple, set up a
~/.ssh/config
file on each machine you want to pull tabs to. Create the file if you don’t have one, or add this at the bottom of an existing one, modifying it for your setup:
host air
HostName computername.local
User remoteusername
Now you can just install the scripts, edit one line on each and start pulling tabs back and forth between computers.
remotetabs.rb
This goes on the machine you want to pull from. If you’re going both directions, you’ll want both scripts on both machines. Easy enough, right? Save this one as remotetabs.rb
in ~/scripts/
and run chmod a+x ~/scripts/remotetabs.rb
. Note that it doesn’t attempt to do any error reporting, it just fails silently or times out if there’s a problem. You’ll know something went wrong, you just won’t know what. It’s mysterious, enjoy it.
Because I often run Webkit, and because Webkit demands that it be addressed separately from Safari, there’s a quick check in here to see which one is running at the time.
#!/usr/bin/ruby
def app_running?(app)
not `ps ax|grep -i "#{app}.app"|grep -v grep`.empty?
end
def webkit_running?
return false if `ps ax|grep -i "Safari.app"|grep -v grep`.empty?
not `ps ax|grep -i "/Applications/Webkit.app"|grep -v grep`.empty?
end
if app_running?("Safari")
browser = webkit_running? ? "Webkit" : "Safari"
urllist = %x{osascript <<-APPLESCRIPT
tell application "#{browser}"
set _tabs to every tab of window 1
set _urls to {}
repeat with _tab in _tabs
set end of _urls to URL of _tab
end repeat
set {astid, AppleScript's text item delimiters} to {AppleScript's text item delimiters, " "}
set output to _urls as text
set AppleScript's text item delimiters to astid
return output
end tell
APPLESCRIPT }.chomp
puts urllist
end
getremotetabs.rb
This goes on the machine that’s doing the “pulling.” Save it as getremotetabs.rb
in ~/scripts/
and run chmod a+x ~/scripts/getremotetabs.rb
. You need to edit the remote_host
variable in this script on each machine to match the hostname you set up in your ~/.ssh/config
file for the ‘other’ Mac.
#!/usr/bin/ruby
# retrieves a list of urls from the front Safari window running on a remote machine
remote_host = 'air' # as set up in ~/.ssh/config with nick and keyless login
%x{ssh #{remote_host} ~/scripts/remotetabs.rb}.chomp.split(' ').each { |url|
%x{osascript -e 'tell application "Safari" to open location "#{url}"'}
}
That’s it. You can save an AppleScript with do shell script "/Users/username/scripts/getremotetabs.rb"
anywhere you want to, or just call the script from the command line. Also, stop making fun of my OSD. I mean it.