Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

pudge (1)

pudge
  (email not shown publicly)
http://pudge.net/
AOL IM: Crimethnk (Add Buddy, Send Message)

I run this joint, see?

Journal of pudge (1)

Thursday May 17, 2007
10:35 AM

Stupid Mac::Glue Tricks: Saving Safari URLs with Tabs

[ #33299 ]

I don't know if Gruber-man ever came up with a solution to the unscriptable tabs, I have a workaround.

You cannot use Apple events to get every URL of every open document in Safari: the documents in nonvisible tabs are unavailable. So this workaround uses UI Scripting (turn it on in System Preferences -> Universal Access -> Enable access for assistive devices) to flip through the tabs. It (perhaps unreliably, if you have the same URL open in more than one tab) stops when the first URL fetched is equal to the last.

It does this for each window, then closes the window and moves on (it is not a simple matter to switch windows, and since I use this for quitting Safari, I want the windows closed anyway). It then simply prints out all the URLs into a Data::Dumper data structure.

#!/usr/bin/perl
use warnings;
use strict;
 
use Mac::Glue ':all';
 
my $safari = new Mac::Glue 'Safari';
my $sysevt = new Mac::Glue 'System Events';
 
my $next_tab = $sysevt->obj(
    menu_item               => 'Select Next Tab',
    menu                    => 1,
    menu_bar_item           => 'Window',
    menu_bar                => 1,
    application_process     => 'Safari'
);
 
$safari->activate;
 
my @windows;
my $win = 0;
 
my $windows = $safari->obj('windows');
for my $window ($windows->get) {
    my $url;
    while (defined(my $url = get_doc_url($window))) {
        push @{$windows[$win]}, $url if length $url;
    }
    $win++ if defined $windows[$win];
    $window->close;
}
 
use Data::Dumper;
print Dumper \@windows;
 
sub get_doc_url {
    my($window) = @_;
    my $document = $window->prop('document')->get;
    return unless $document;
 
    my $url = $document->prop('url')->get;
    $url = '' unless defined($url);
    return if @windows && $windows[$win] && @{$windows[$win]} &&
        $url eq $windows[$win][0];
 
    $next_tab->click;
 
    return $url;
}

Then you can do what you want the data structure. Here's what I do:

#!/usr/bin/perl
use warnings;
use strict;
 
use Mac::Glue ':all';
 
my $safari = new Mac::Glue 'Safari';
 
$safari->activate;
 
sub open_windows {
    my($windows) = @_;
    for my $window (@$windows) {
        $safari->make(new => 'document'); sleep 2;
        $safari->open_location($_) for @$window;
    }
 
}
 
my $VAR1;
 
$VAR1 = [
          [
            'http://pudge.net/',
            'http://pudge.net/tunes/'
          ],
          [
            'http://projects.pudge.net/'
          ]
        ];
 
open_windows($VAR1);

Saving and restoring to a file instead of copying/pasting the data structure is an exercise left to the reader.

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • Pudge,

    That's slick, and I hate when Safari loses my windows, but closing them for me would be awkward -- I might want to use this to back up state, not just capture it for later resumption.

    Is there any reason a Data Dumper structure is better than emitting a simple command line, starting with 'open ' and containing all the URLs found (wrapped in '' to protect against puctuation such as '?')? This is what I use to 'store' URLs when i have to quit Safari.
    • That's slick, and I hate when Safari loses my windows, but closing them for me would be awkward -- I might want to use this to back up state, not just capture it for later resumption.

      Right. But there's no real way to do that right now, that I can find.

      Is there any reason a Data Dumper structure is better than emitting a simple command line, starting with 'open ' and containing all the URLs found (wrapped in '' to protect against puctuation such as '?')? This is what I use to 'store' URLs when i have to quit Safari.

      The only thing was that my re-open command takes the data structure and opens them as they were before (including different windows for different sets of tabs). If you'd rather use opens, sure, you could do that.