use Getopt::Long;
use IO::Socket::INET6;
+use Scalar::Util qw(reftype);
use FindBin;
use constant {
use Encode;
my $SELF = "$FindBin::Bin/$FindBin::Script";
+my $MUSIC = $ENV{MUSIC} // "/srv/music";
+
+# get_item_thumbnails({ options }, file, ...)
+# get_item_thumbnails(file, ...)
+#
+# For each music file listed, obtain a thumbnail (if any) for the
+# cover art.
+#
+# The first argument is a hash reference to control the mode of
+# operation; it may be omitted for default options.
+#
+# get_item_thumbnails({ small => 1 }, ...) - smaller thumbnails
+#
+# The returned list consists of strings (in the same order as the filename
+# arguments) suitable for use directly in FVWM menus; by default the filename
+# is bracketed by asterisks (e.g., "*thumbnail.png*"); in small mode it is
+# surrounded by % (e.g., "%thumbnail.png%"). If no cover art was found, the
+# empty string is returned for that file.
+sub get_item_thumbnails {
+ my @results = ();
+ my $flags = {};
+ my @opts = ();
+
+ $flags = shift if (reftype($_[0]) eq "HASH");
+ return @results unless @_;
+
+ my $c = "*";
+ if ($flags->{small}) {
+ push @opts, "--small";
+ $c = "%";
+ }
+
+ foreach (@_) {
+ open THUMB, "-|", "$FindBin::Bin/thumbnail.zsh", "--music",
+ @opts, $_;
+ my $thumb = <THUMB>;
+ chomp $thumb;
+
+ $thumb = "$c$thumb$c" if (-f $thumb);
+ push @results, $thumb;
+ close THUMB;
+ die("thumbnail.zsh failed") if ($?);
+ }
+
+ return @results;
+}
+
+# Given a music filename, search for the cover art in the same directory.
+sub mpd_cover_filename {
+ my ($dir) = @_;
+ my $file;
+
+ $dir =~ s/\/[^\/]*$//;
+ foreach ("cover.png", "cover.jpg", "cover.tiff", "cover.bmp") {
+ if (-f "$dir/$_") {
+ $file = "$dir/$_";
+ last;
+ }
+ }
+ return unless defined $file;
+
+ # Follow one level of symbolic link to get to the scans directory.
+ $file = readlink($file) // $file;
+ $file = "$dir/$file" unless ($file =~ /^\//);
+ return $file;
+}
sub cmd
{
{ # work around 'use locale' breaking s///i
my $i = 0;
use locale;
- foreach (sort keys(%albums)) {
- my $key = $_;
- my $a_album = sanitise($key, 1);
- open THUMB, "-|", "$FindBin::Bin/thumbnail.zsh",
- "--small", "--music", $albums{$key};
- my $thumb = <THUMB>;
- close THUMB;
- die("Incompetent use of thumbnail.zsh") if ($?);
+ my @keys = sort keys %albums;
+ my @thumbs = get_item_thumbnails({ small => 1 },
+ map { $albums{$_} } @keys);
- $thumb =~ s/\n//sg;
- $thumb = "%$thumb%" if (-f $thumb);
+ foreach my $key (@keys) {
+ my $a_album = sanitise($key, 1);
+ my $thumb = shift @thumbs;
cmd("AddToMenu $menu \"$thumb$a_album\" Popup MenuMPDArt_$i");
{ # work around 'use locale' breaking s///i
use locale;
+
+ my @thumbs = get_item_thumbnails({ small => 1 },
+ map { $_->{file} } @titles);
+ for (my $i = 0; $i < @titles; $i++) {
+ $titles[$i]->{thumb} = $thumbs[$i];
+ }
+
foreach (sort titlesort @titles) {
- my ($t_file, $t_artist, $t_title, $t_id) = (
+ my ($t_file, $t_artist, $t_title, $t_id, $thumb) = (
$_->{file},
$_->{Artist},
$_->{Title},
$_->{Id},
+ $_->{thumb}
);
# MPD searches are case-insensitive.
$t_artist = sanitise($t_artist, 1);
$t_title = sanitise($t_title, 1);
- open THUMB, "-|", "$FindBin::Bin/thumbnail.zsh",
- "--small", "--music", $t_file;
- my $thumb = <THUMB>;
- close(THUMB);
- die("Incompetent use of thumbnail.zsh") if ($?);
-
- $thumb =~ s/\n//sg;
- $thumb = "%$thumb%" if (-f $thumb);
-
cmd("AddToMenu $menu \"$thumb$t_artist - $t_title\""
." Exec exec $FindBin::Bin/mpdexec.pl"
." playid $t_id");
}
die("Failed data query\n") unless (keys(%entry) > 0);
- open THUMB, "-|", "$FindBin::Bin/thumbnail.zsh",
- "--image", "--music", $entry{file};
- my $thumb = <THUMB>;
- my $scan = <THUMB>;
- close(THUMB);
- die("Incompetent use of thumbnail.zsh") if ($?);
-
- $thumb =~ s/\n//sg;
- $scan =~ s/\n//sg;
+ my ($thumb) = get_item_thumbnails($entry{file});
+ if ($thumb) {
+ my $cover = mpd_cover_filename("$MUSIC/$entry{file}");
- if (-f $thumb) {
- cmd("AddToMenu $menu \"*$thumb*\" "
- ."Exec exec geeqie ".shellify($scan, 0));
+ cmd("AddToMenu $menu \"$thumb\" "
+ ."Exec exec geeqie ".shellify($cover, 0));
}
+
cmd("AddToMenu $menu \"Title: ".sanitise($entry{Title}, 0)
."\" Popup MenuMPDTitle");
cmd("AddToMenu $menu \"Artist: ".sanitise($entry{Artist}, 0)