Computers: May 2007 Archives
So I saw some Yojimbo scripts over at DF and I remembered I have a Yojimbo script I use quite a bit, to create a setlist in which I keep song lyrics and chords and so on.
The setup required is to change the $htmlfile variable for your location of the created setlist; create a "Music: Setlist" group in Yojimbo (which contains note items with titles for song names, tags for artist names, and the contents in the note [with an optional __BR__ text to force a column break, such as you can see in several of the songs).
And of course, you need Mac::Glue installed, and glues for Safari and Yojimbo created.
And you need a stylesheet, which you can get from the source in the finished file.
The setup required is to change the $htmlfile variable for your location of the created setlist; create a "Music: Setlist" group in Yojimbo (which contains note items with titles for song names, tags for artist names, and the contents in the note [with an optional __BR__ text to force a column break, such as you can see in several of the songs).
And of course, you need Mac::Glue installed, and glues for Safari and Yojimbo created.
And you need a stylesheet, which you can get from the source in the finished file.
#!/usr/bin/perl
use warnings;
use strict;
use File::Spec::Functions;
use Mac::Glue;
use URI::file;
our($header, $mid, $footer);
init();
my(%setlist);
my $artists = $setlist{ARTIST} = {};
my $songs = $setlist{SONG} = {};
my $yojimbo = new Mac::Glue 'Yojimbo';
my $browser = new Mac::Glue 'Safari';
my $set = $yojimbo->obj(collection => 'Music: Setlist');
my $count = my @items = $set->obj('items')->get;
for my $item (@items) {
my $song = $item->prop('name')->get;
my $text = $item->prop('contents')->get;
my($artist) = $item->prop(name => of => 'tag')->get;
$text =~ s/(\015\012|\015|\012)/\n/g;
my $key;
$key = $1 if $text =~ s/^(\[.+\])\s+//s;
(my $songlink = $song) =~ s/\W/_/g;
(my $artistlink = $artist) =~ s/\W/_/g;
push @{$artists->{$artist}}, $song;
$songs->{$song}{artist} = $artist;
$songs->{$song}{alink} = $artistlink;
$songs->{$song}{text} = $text;
$songs->{$song}{key} = $key if $key;
$songs->{$song}{link} = $songlink;
}
$count += scalar(keys %$artists) * 2;
##########################
my $htmlfile = catfile(
'/Users/pudge/MacOS/pudge/work/songs/music',
'setlist.html'
);
my $uri = URI::file->new($htmlfile);
open my $fh, '>', $htmlfile;
##########################
print $fh $header;
my $c = 0;
my $d = 1;
for my $artist (sort keys %$artists) {
my $artistr = $artists->{$artist};
print $fh qq[\t<li><a name="$songs->{$artistr->[0]}{alink}">$artist</a>] ;
print $fh qq[<ul class="setlist_inner">\n];
for my $song (sort @$artistr) {
my $songr = $songs->{$song};
print $fh qq[\t\t<li class="setlist_inner"><a href="#$songr->{link}">$song</a>];
print $fh " <i><small>$songr->{key}</small></i>" if $songr->{key};
print $fh "</li>\n";
$c++;
}
print $fh "\t</ul></li>\n";
$c += 2;
if ($c > $d*int($count/3)) {
print $fh qq[</ul></div>\n<div class="wrapper"><ul class="col">\n];
$d++;
$c--;
}
}
print $fh $mid;
for my $artist (sort keys %$artists) {
my $artistr = $artists->{$artist};
#print $fh "\t<h2>$artist</h2>\n";
for my $song (sort @$artistr) {
my $songr = $songs->{$song};
my $text = $songr->{text};
$text =~ s/</</g;
$text =~ s|__BR__\s+|</pre><pre>|gs;
print $fh qq[\t\t<h3><a name="$songr->{link}">$song</a>];
print $fh qq[ <i>$songr->{key}</i>] if $songr->{key};
print $fh qq[</h3>\n\t\t<a href="#top">Top</a>];
print $fh qq[ | <a href="#$songr->{alink}">$artist</a>];
print $fh qq[\n\n<pre>$text</pre>\n\n\n<hr>\n\n];
}
}
print $fh $footer;
##########################
close $fh;
$browser->activate;
$browser->open_location ($uri->as_string);
##########################
sub init {
$header = <<EOT;
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=iso-8859-1">
<title>Pudge Setlist</title>
<link href="../style.css" rel="stylesheet">
</head>
<body style="font-size: 11px">
<h1><a name="top">Pudge Setlist</a></h1>
<div class="wrapper"><ul class="col">
EOT
$mid = <<EOT;
</ul></div>
<div class="body">
EOT
$footer = <<EOT;
<pre>__END__</pre>
</div>
</body>
</htm l>
EOT
}
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.
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/perlThen you can do what you want the data structure. Here's what I do:
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;
}
#!/usr/bin/perlSaving and restoring to a file instead of copying/pasting the data structure is an exercise left to the reader.
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 = [
[
'https://pudge.net/',
'https://pudge.net/tunes/'
],
[
'http://projects.pudge.net/'
]
];
open_windows($VAR1);
pudge posted a photo:
The latest O'Reilly book is destined to be a big hit.
cf. www.flickr.com/photos/pkdouyk/241484893/ and www.catb.org/~esr/writings/sextips/ and www.oreilly.com/catalog/cathbazpaper/