see also: cover art in FLAC tags
see also: now playing
After my desktop machine went OOM again today and had to be
rebooted, I figured I would finally install the current version of the
slimserver, which is the 100M of perl bloatware that drives my various
squeezebox players. I hate to
upgrade this, because I have to port forward my weird hacks each
time.
(Aside: Another reason I haven't touched the slimserver in a year
is that the current versions depend on a local MySQL server for
some idiotic reason. BARF. No. You do not need a SQL engine
to drive what is, in my case, about 1200 CDs, which weighs in at 500K
of data. And even if you think you do, you never heard of sqlite? You had to bundle mysql, the
rip-roaringest piece of half-assed crap that anyone ever mistook for a
database? BARF.)
On the other hand, the new slimserver is a whole lot faster than
the old one. Moving on.
My only local modification teaches the slimserver to understand the
wacky FLAC coverart
blocks which are an extension I made up. My old patch against
6.2.2 doesn't apply anymore, so I had to sort it out again, which
fortunately wasn't too hard. Yeah, I'm just going to paste the patch
right here, because I am lazy. Hope you like reading perl diffs with
your morning coffee.
diff -rcN SlimServer_v6.5.4/Slim/Formats/FLAC.pm
SlimServer_v6.5.4-hacked/Slim/Formats/FLAC.pm
*** SlimServer_v6.5.4/Slim/Formats/FLAC.pm 2007-05-24
18:02:36.000000000 -0700
--- SlimServer_v6.5.4-hacked/Slim/Formats/FLAC.pm 2007-10-06--
--00:07:41.000000000 -0700
***************
*** 65,70 ****
--- 65,75 ----
# as PIC1 + artwork. So the raw data is +4 from the beginning.
my $ESCIENT_ARTWORK = 1163084622;
+ # flac-image also stores cover art in a FLAC application block, but with
+ # a different application id and a 72-byte header--same thing, only
+ # different.
+ my $FLAC_IMAGE = 0x696d6167; # == "imag" in ASCII
+
=head2 getTag( $filename )
Extract and return audio information & any embedded metadata found.
***************
*** 293,300 ****
if (substr($artwork, 0, 4, '') eq 'PIC1') {
$tags->{'ARTWORK'} = $artwork;
}
! }
return $tags;
}
--- 298,318 ----
if (substr($artwork, 0, 4, '') eq 'PIC1') {
$tags->{'ARTWORK'} = $artwork;
}
!
! } elsif ($flac->application($FLAC_IMAGE)) {
!
! # we don't bother to look at the mime-type field except
! # to check that it starts with 'image', because Info.pm is
! # going to apply magic to try to guess the mime-type anyway.
!
! my $artwork = $flac->application($FLAC_IMAGE);
!
! if (substr($artwork, 4, 5) eq 'image') {
! $tags->{'ARTWORK'} = substr($artwork, 72);
! }
+ }
+
return $tags;
}
diff -rcN SlimServer_v6.5.4/Slim/Music/Info.pm
SlimServer_v6.5.4-hacked/Slim/Music/Info.pm
*** SlimServer_v6.5.4/Slim/Music/Info.pm 2007-05-24
18:02:33.000000000 -0700
--- SlimServer_v6.5.4-hacked/Slim/Music/Info.pm 2007-10-06--
--00:22:13.000000000 -0700
***************
*** 944,950 ****
sub isFLAC {
my $pathOrObj = shift;
! return isType($pathOrObj, 'flc', @_);
}
sub isAIFF {
--- 944,952 ----
sub isFLAC {
my $pathOrObj = shift;
! return 1 if isType($pathOrObj, 'flc', @_);
! return 1 if isType($pathOrObj, 'fec', @_);
! return 0;
}
sub isAIFF {
That's all I need to do to the slimserver. I had to update the Weblogger
plugin as well, and fyi, the current version 0.99c has a bug that stops
multipart POST from working. You need to change this one line, or you
will get nothing but "Can't coerce array to hash" errors out
of it:
--- Plugin.pm~ 2006-10-07 03:44:42.000000000 -0700
+++ Plugin.pm 2007-10-06 02:09:48.000000000 -0700
@@ -955,7 +955,7 @@
my($client,$url,$paramlist,$timeout)=@_;
# Prepare our HTTP request...
- my $request=POST $url, Content_Type => 'form-data', Content => [%$paramlist];
+ my $request=POST $url, Content_Type => 'form-data', Content => $paramlist;
# Create our UserAgent, and send the file/params...
# (submit our faked "form" data)
I sent this last bit to Dan the weblogger man, so if it really is a
bug, maybe it will get fixed.
06 Oct 2007 03:00 PT
- persistent link
- trackback
- 0 comments
This isn't really a hack in the sense that I thought of something
clever to do, but it amuses me nonetheless. One of my many squeezeboxes is in the bedroom,
and it has its own remote control of course, but I can't read the
screen from the bed without putting my glasses on. Obviously I could
move the squeezebox, or the bed, or I could put my glasses on.
But why do that when there is a less obvious solution: I can
forward a port so that the server that controls the squeezeboxes is
reachable from the Internet. Then I can use the Blackberry which is
always close by. So I can now change the volume or play a CD by
sending commands up through T-Mobile, across the internets, to my ISP,
down the DSL, through the NAT router, to the slimserver machine in the
closet, across the ethernet to the squeezebox which is eight feet
away. This works better than you would expect; the total round trip
from me pressing a button to hearing its effect is about half a
second.
Even more important, I now carry this power in my pants wherever I
go, so if I suddenly need to play Cowboy Bebop in my living room while
I am in the airport in Chicago, I can do so. Booya!
22 Jan 2007 01:04 PT
- persistent link
- trackback
- 0 comments
Obviously, if I'm going to keep up with the cool kids, my site here
is going to have to display the exact song that I am listening to, in
real time, with the complete information and cover art. No simple
hand-updated list of "favorite CDs" or anything like that
will do.
Now, my music playing device is the Squeezebox, which is fed by the
Slimserver, which is open source and written in Perl, just like
Blosxom. So this is certainly possible; the only question is how much
work it is going to be.
Push or pull?
The first decision is going to be, do I want the web page to
"pull" the song information off of the slimserver every time
it is displayed, or is it better to have the slimserver
"push" the updated information each time the song changes?
Either network transaction would cost about the same, and they would
be about equally easy to implement, so the question is, which will
happen more times in a typical day: song transitions on the
slimserver, or page views on my site?
Obviously, at the moment, there are far more song changes than site
visitors, and it will probably stay that way for quite a while.
However, there is a much firmer upper bound on the number of song
transitions, because even when the Squeezeboxes are in continuous
operation, there is only one update to push every three to five
minutes. On the other hand, there could possibly be hundreds or
thousands of hits to the web site in a day (I did not say
likely, just possible). So I am going with the server-pushed
updates for now. The idea is to get the slimserver to notify the blog
somehow when the song changes.
Generate updates with Weblogger plugin for Slimserver.
Luckily, there is already a slimserver plugin by Danny Rego, called
Weblogger,
that can generate various kinds of notifications when the song
changes. I installed this without any difficulty and configured my
two Squeezeboxes to send HTTP POST updates to a URL on my web server.
(NB: if the web server ran on the same machine as the slimserver, I would
have been able to write the transitions to a file and read that file
directly from the blog, which would have been easier.) I set the
Weblogger plugin to "post as file" which is the only way to
get the cover art sent as part of the update.
The bridge: a Perl CGI on the web server
Of course, Weblogger won't work until I put a CGI script at its
configured URL to catch the incoming updates and write them to the
disk. So I wrote a trivial Perl CGI script to do this, called
catch-weblogger. All it does is save the two files that Weblogger
POSTs (a bit of HTML called songinfo.txt, and a cover art
image named albumart.jpg) into the Blosxom plugins/state
directory. The active ingredients look like this:
my $STATE_DIR = '/home/mikey/www/blosxom/plugins/state';
my $q = new CGI;
print "Content-type: text/plain\n\n";
open OUT, ">$STATE_DIR/songinfo.txt" or die("can't open songinfo.txt: $!");
print OUT $q->param("songinfo.txt");
close OUT or warn("can't close songinfo.txt: $!");
open OUT, ">$STATE_DIR/albumart.jpg" or die("can't open albumart.jpg: $!");
print OUT $q->param("albumart.jpg");
close OUT or warn("can't close albumart.jpg: $!");
print "OK"; # weblogger looks for an "OK" response
exit(0);
The last piece: a Blosxom plugin to make the data available
Now that the files songinfo.txt and
albumart.jpg are being automatically created and updated
in the Blosxom plugins/state directory, all we need is
a
little Blosxom plugin to make them available to blog templates.
This is even simpler than the catch-weblogger part:
sub head {
# the songinfo.txt is already a bite-size piece of HTML, but we parse it
# ourselves so that we can display any format we want
my %song;
open SONG, "<$blosxom::plugin_state_dir/songinfo.txt";
while (<SONG>) {
m/<b>([\w ]+):<\/b> (.*?)<br>/ && ($song{$1} = $2);
m/<img src="(.*?)">/ && ($song{"url"} = $1);
}
close SONG;
our $now_playing;
$now_playing = "<div class=\"nowplaying\">\n";
$now_playing .= "<p align=\"center\"><img width=\"140px\" height=\"140px\" src=\"";
$now_playing .= $song{"url"};
$now_playing .= "\" alt=\"album cover art\" /></p>\n";
$now_playing .= "<p style=\"margin-left: 8px\">" . $song{"Song"} . "<br />";
$now_playing .= "from <i>" . $song{"Album"} . "</i> by " . $song{"Artist"} . "<br />";
$now_playing .= "in the " . $song{"Played on"} . "<br />";
$now_playing .= "at " . $song{"Last Updated"} . "</p>\n";
$now_playing .= "</div>\n";
return 1;
}
Now with this plugin running, all you have to do is put
$slimserver::now_playing in your Blosxom flavour
templates whereever you want, and you should get a nice fancy box such
as the one probably displayed somewhere on this page.
13 Nov 2005 23:56 PT
- persistent link
- trackback
- 0 comments