PDA

View Full Version : OT: Getting Album Cover/Art with EAC or other tool?



Farid Shenassa
2003-11-20, 13:19
Thanks for the suggestion. Tried Tag/Rename, but didn't see anything having
to do with album art. There is image titles but nothing for album art.
And That is also grayed out.

Yes, I do recall the script. I'll search for that on yahoo.

Thanks


-----Original Message-----
From: Kevin Deane-Freeman [mailto:kevin (AT) deane-freeman (DOT) com]
Sent: Thursday, November 20, 2003 2:50 PM
To: SlimDevices Discussion
Subject: [slim] OT: Getting Album Cover/Art with EAC or other tool?

Quoting Farid Shenassa <fshenassa (AT) usaninc (DOT) com>:

> A bit off topic,
>
> But using EAC and LAME now to re-rip everything for the slimp3. However,
> though EAC does a real nice job with freedb, it doesn't get the album
> cover/art now supported by the slimp3 web interface.
>
> Is there a way to get it to do this, or a separate tool that can auto
check
> a album dir on disk and find/download the image file for it?
I used Tag&Rename to get my cover art from allmusic.com. You have to select
each album manually and grab the info, but it works. There was also a
script
posted that tries to use the Amazon SOAP interface to grabe covers. It
works
fairly well, but some images still come across as just blank placeholders.

-kdf

Kevin Deane-Freeman
2003-11-20, 13:33
Quoting Farid Shenassa <fshenassa (AT) usaninc (DOT) com>:

> Thanks for the suggestion. Tried Tag/Rename, but didn't see anything having
> to do with album art. There is image titles but nothing for album art.
> And That is also grayed out.
I think album art came in on newer releases only, also is ID3V2 only. You select
all the songs of one album, then you have the option in tools....get info from
allmusic.com, and it will open a broswer, let you serch for the album, then you
click "get info" and you will have an option box to grab any or all info.

-kdf
>
> Yes, I do recall the script. I'll search for that on yahoo.
>
> Thanks
>
>
> -----Original Message-----
> From: Kevin Deane-Freeman [mailto:kevin (AT) deane-freeman (DOT) com]
> Sent: Thursday, November 20, 2003 2:50 PM
> To: SlimDevices Discussion
> Subject: [slim] OT: Getting Album Cover/Art with EAC or other tool?
>
> Quoting Farid Shenassa <fshenassa (AT) usaninc (DOT) com>:
>
> > A bit off topic,
> >
> > But using EAC and LAME now to re-rip everything for the slimp3. However,
> > though EAC does a real nice job with freedb, it doesn't get the album
> > cover/art now supported by the slimp3 web interface.
> >
> > Is there a way to get it to do this, or a separate tool that can auto
> check
> > a album dir on disk and find/download the image file for it?
> I used Tag&Rename to get my cover art from allmusic.com. You have to select
> each album manually and grab the info, but it works. There was also a
> script
> posted that tries to use the Amazon SOAP interface to grabe covers. It
> works
> fairly well, but some images still come across as just blank placeholders.
>
> -kdf
>
>
>

Dan Sully
2003-11-20, 14:18
fetchCovers -

you need from CPAN:

Image::Info
LWP
MP3::Info
Net::Amazon

---------------------------------------------------------------------
#!/usr/bin/perl -w

# $Id$

use strict;

use File::Find;
use Getopt::Std;
use Image::Info qw(image_info dim);
use LWP::UserAgent;
use MP3::Info;
use Net::Amazon;
use Net::Amazon::Request::Artist;

use Log::Log4perl qw(:easy);
#Log::Log4perl->easy_init($DEBUG);

my %options = ();
my %seen = ();
my %cache = ();
my $ua = LWP::UserAgent->new();
my $debug = 0;
my $file;
my $exclude;
my $threshold = .60;

my $amazon = Net::Amazon->new(
'token' => 'REPLACE_WITH_YOUR_TOKEN',
'max_pages' => 20,
);

$|++;

sub main {

help() unless getopts('m:di:e:', \%options);
help() unless scalar keys %options > 0;

my $top = $options{'m'} || help();

$debug = $options{'d'};
$file = $options{'i'} || 'cover.jpg';
$exclude = $options{'e'} || "tmp|lost+found|Misc. Live";

if ($file !~ /\.jpg$/) {
print "File name must end with .jpg\n";
exit;
}

find(\&searchTree, $top);
}

sub searchTree {
my $dir = $File::Find::dir;

return if $seen{$dir};
return if $dir =~ /$exclude/i;

opendir(DIR, $dir) || die "can't opendir $dir: $!";
my @files = readdir(DIR);
closedir(DIR);

# If we have an mp3 file here and there's not a cover here already

if ((grep {/\.mp3$/} @files) && !(grep {/\.jpg/i} @files)) {

# Mark that we've been here. No point doing a dir twice
$seen{$dir} = 1;

# XXX_ - this should be a commandline option.
next if -f "$dir/$file";

print "Now looking in: $dir\n";

# Let's just grab either the first file with a tracknumber of 1 (or 01) in the filename
# or -if that doesn't exist- just the first mp3 file we find. Use the info from him
my @list = grep ({/\.mp3$/} @files);

my @workfile = grep (/^0?1\D/, @list);

my $tag = get_mp3tag(shift @workfile || shift @list) || warn "No tag info in: $dir\n";

# Dumb bug in MP3::Info workaround
return if $tag == 1;

my $artist = cleanString($tag->{'ARTIST'});
my $album = cleanString(cleanAlbumTitle($tag->{'ALBUM'}));

if (!$artist || !$album) {
print "No artist or album in $dir\n" if $debug;
return;
}

# cache results per artist
unless ($cache{$artist}) {

print "Requesting artist: [$tag->{'ARTIST'}]\n" if $debug;

my $req = Net::Amazon::Request::Artist->new('artist' => $artist);

$cache{$artist} = $amazon->request($req);
}

fetchImageForAristAndAlbum($artist, $album, $cache{$artist}, $dir);
}
}

sub getImage {
my $url = shift;

my $image;

my $req = HTTP::Request->new('GET' => $url);
my $res = $ua->request($req);

if ($res->is_success()) {
$image = $res->content();
} else {
warn "Could not download image file for $url\n" if $debug;
return;
}

my ($height,$width) = dim( image_info(\$image) );

if (($height == 1) && ($width == 1)) {
# Sometimes Amazon gives us a 1x1 gif if it could not find the picture
print "\t1x1 image found. Moving on\n" if $debug > 1;
return;
}

return $image;
}

sub cleanString {
my $string = shift || return;

# cleanup spaces
$string =~ s/^\s*//g;
$string =~ s/\s*$//g;

return lc($string);
}

sub cleanAlbumTitle {
my $album = shift || return;

# Gets rid of things like "Disc 1" from the beginning or end of the album title
# That's just how I name multi disc sets -- so you can change this
# freely to suit your environment

# First remove anything between (). Use this one with caution.
$album =~ s/\(.*\)//;

# Remove from front
$album =~ s/^dis[ck]\W*\d+\W*//gi;

# And now from back
$album =~ s/\W*dis[ck]\W*\d+\W*$//gi;

return $album;
}

sub fetchImageForAristAndAlbum {
my ($artist, $album, $res, $dir) = @_;

# try and match on the artist + album first.
for my $property ($res->properties()) {

if (lc($property->artist()) eq $artist &&
lc($property->album()) eq $album) {

printf("\tGot an exact match for: %s - %s\n", $property->artist(), $property->album()) if $debug;

fetchImageForProperty($property, $dir);
return 1;
}
}

for my $property ($res->properties()) {

# First we tokenize everything we know about the album/artist
my (@myTokens, @amazonTokens, %seen);

push @myTokens, split(/\s+/, $artist);
push @myTokens, split(/\s+/, $album);

push @amazonTokens, split(/\s+/, $property->artist());
push @amazonTokens, split(/\s+/, $property->album());

# Now let's count the tokens and ignore common ones:
# "a" and "the" and any nonwords
map ($seen{lc($_)}++, grep(!/(\ba\b|the|\W)/i, @myTokens));
map ($seen{lc($_)}++, grep(!/(\ba\b|the|\W)/i, @amazonTokens));

# How many tokens did we see more than once?
my $total = scalar(keys %seen);
my $mult = grep(!/1/, values %seen);

# If we passed the threshold, let's call it close enough
if ($mult / $total >= $threshold) {

printf("\tGot a fuzzy match for: %s - %s\n", $property->artist(), $property->album()) if $debug;

fetchImageForProperty($property, $dir);
return 1;
}
}
}

sub fetchImageForProperty {
my ($property, $dir) = @_;

# Start by trying to get the large size image
# If it's not there, ask for smaller sized images
# We have to fetch the image each time because we have no
# way of knowing about a place-holder image until we look at it
for my $size (qw(ImageUrlLarge ImageUrlMedium ImageUrlSmall)) {

my $url = $property->$size() || next;

my $img = getImage($url) || next;

open(IMG,">$file") || die "Could not open $file in $dir for writing! $!\n";
print IMG $img;
close IMG;

last;
}

return 1;
}

sub help {

print <<EOF;
Usage: $0 -m "/path/to/top/mp3/dir" [options]

Options are:
-i image_name File name to save album cover as. Default: cover.jpg
-d Turn on verbose debugging
-e Directories to exclude seperated by a "|".
Use just the dir name, not the full path
(i.e. "temporary directory|dir to skip" etc.)

EOF

exit;
}

main();

__END__

Victor Brilon
2003-11-20, 18:29
Dan,

Er....umm.....

With a few minor modifications, this is almost exactly my code that
originally I wrote.
http://www.victorland.com/slimp3

It looks like you made some useful changes in the code -- why not submit
a patch to me to include them in the original code?

I don't mind (in fact I quite enjoy it) when people use code I created,
put please at least have the decency to credit the original author. At
the very least respect the GPL license that this software was released
under.

Thanks,
Victor

Dan Sully wrote:
> fetchCovers -
>
> you need from CPAN:
>
> Image::Info
> LWP
> MP3::Info
> Net::Amazon
>
> ---------------------------------------------------------------------
> #!/usr/bin/perl -w
>
> # $Id$
>
> use strict;
>
> use File::Find;
> use Getopt::Std;
> use Image::Info qw(image_info dim);
> use LWP::UserAgent;
> use MP3::Info;
> use Net::Amazon;
> use Net::Amazon::Request::Artist;
>
> use Log::Log4perl qw(:easy);
> #Log::Log4perl->easy_init($DEBUG);
>
> my %options = ();
> my %seen = ();
> my %cache = ();
> my $ua = LWP::UserAgent->new();
> my $debug = 0;
> my $file;
> my $exclude;
> my $threshold = .60;
>
> my $amazon = Net::Amazon->new(
> 'token' => 'REPLACE_WITH_YOUR_TOKEN',
> 'max_pages' => 20,
> );
>
> $|++;
>
> sub main {
>
> help() unless getopts('m:di:e:', \%options);
> help() unless scalar keys %options > 0;
>
> my $top = $options{'m'} || help();
>
> $debug = $options{'d'};
> $file = $options{'i'} || 'cover.jpg';
> $exclude = $options{'e'} || "tmp|lost+found|Misc. Live";
>
> if ($file !~ /\.jpg$/) {
> print "File name must end with .jpg\n";
> exit;
> }
>
> find(\&searchTree, $top);
> }
>
> sub searchTree {
> my $dir = $File::Find::dir;
>
> return if $seen{$dir};
> return if $dir =~ /$exclude/i;
>
> opendir(DIR, $dir) || die "can't opendir $dir: $!";
> my @files = readdir(DIR);
> closedir(DIR);
>
> # If we have an mp3 file here and there's not a cover here already
>
> if ((grep {/\.mp3$/} @files) && !(grep {/\.jpg/i} @files)) {
>
> # Mark that we've been here. No point doing a dir twice
> $seen{$dir} = 1;
>
> # XXX_ - this should be a commandline option.
> next if -f "$dir/$file";
>
> print "Now looking in: $dir\n";
>
> # Let's just grab either the first file with a tracknumber of 1 (or 01) in the filename
> # or -if that doesn't exist- just the first mp3 file we find. Use the info from him
> my @list = grep ({/\.mp3$/} @files);
>
> my @workfile = grep (/^0?1\D/, @list);
>
> my $tag = get_mp3tag(shift @workfile || shift @list) || warn "No tag info in: $dir\n";
>
> # Dumb bug in MP3::Info workaround
> return if $tag == 1;
>
> my $artist = cleanString($tag->{'ARTIST'});
> my $album = cleanString(cleanAlbumTitle($tag->{'ALBUM'}));
>
> if (!$artist || !$album) {
> print "No artist or album in $dir\n" if $debug;
> return;
> }
>
> # cache results per artist
> unless ($cache{$artist}) {
>
> print "Requesting artist: [$tag->{'ARTIST'}]\n" if $debug;
>
> my $req = Net::Amazon::Request::Artist->new('artist' => $artist);
>
> $cache{$artist} = $amazon->request($req);
> }
>
> fetchImageForAristAndAlbum($artist, $album, $cache{$artist}, $dir);
> }
> }
>
> sub getImage {
> my $url = shift;
>
> my $image;
>
> my $req = HTTP::Request->new('GET' => $url);
> my $res = $ua->request($req);
>
> if ($res->is_success()) {
> $image = $res->content();
> } else {
> warn "Could not download image file for $url\n" if $debug;
> return;
> }
>
> my ($height,$width) = dim( image_info(\$image) );
>
> if (($height == 1) && ($width == 1)) {
> # Sometimes Amazon gives us a 1x1 gif if it could not find the picture
> print "\t1x1 image found. Moving on\n" if $debug > 1;
> return;
> }
>
> return $image;
> }
>
> sub cleanString {
> my $string = shift || return;
>
> # cleanup spaces
> $string =~ s/^\s*//g;
> $string =~ s/\s*$//g;
>
> return lc($string);
> }
>
> sub cleanAlbumTitle {
> my $album = shift || return;
>
> # Gets rid of things like "Disc 1" from the beginning or end of the album title
> # That's just how I name multi disc sets -- so you can change this
> # freely to suit your environment
>
> # First remove anything between (). Use this one with caution.
> $album =~ s/\(.*\)//;
>
> # Remove from front
> $album =~ s/^dis[ck]\W*\d+\W*//gi;
>
> # And now from back
> $album =~ s/\W*dis[ck]\W*\d+\W*$//gi;
>
> return $album;
> }
>
> sub fetchImageForAristAndAlbum {
> my ($artist, $album, $res, $dir) = @_;
>
> # try and match on the artist + album first.
> for my $property ($res->properties()) {
>
> if (lc($property->artist()) eq $artist &&
> lc($property->album()) eq $album) {
>
> printf("\tGot an exact match for: %s - %s\n", $property->artist(), $property->album()) if $debug;
>
> fetchImageForProperty($property, $dir);
> return 1;
> }
> }
>
> for my $property ($res->properties()) {
>
> # First we tokenize everything we know about the album/artist
> my (@myTokens, @amazonTokens, %seen);
>
> push @myTokens, split(/\s+/, $artist);
> push @myTokens, split(/\s+/, $album);
>
> push @amazonTokens, split(/\s+/, $property->artist());
> push @amazonTokens, split(/\s+/, $property->album());
>
> # Now let's count the tokens and ignore common ones:
> # "a" and "the" and any nonwords
> map ($seen{lc($_)}++, grep(!/(\ba\b|the|\W)/i, @myTokens));
> map ($seen{lc($_)}++, grep(!/(\ba\b|the|\W)/i, @amazonTokens));
>
> # How many tokens did we see more than once?
> my $total = scalar(keys %seen);
> my $mult = grep(!/1/, values %seen);
>
> # If we passed the threshold, let's call it close enough
> if ($mult / $total >= $threshold) {
>
> printf("\tGot a fuzzy match for: %s - %s\n", $property->artist(), $property->album()) if $debug;
>
> fetchImageForProperty($property, $dir);
> return 1;
> }
> }
> }
>
> sub fetchImageForProperty {
> my ($property, $dir) = @_;
>
> # Start by trying to get the large size image
> # If it's not there, ask for smaller sized images
> # We have to fetch the image each time because we have no
> # way of knowing about a place-holder image until we look at it
> for my $size (qw(ImageUrlLarge ImageUrlMedium ImageUrlSmall)) {
>
> my $url = $property->$size() || next;
>
> my $img = getImage($url) || next;
>
> open(IMG,">$file") || die "Could not open $file in $dir for writing! $!\n";
> print IMG $img;
> close IMG;
>
> last;
> }
>
> return 1;
> }
>
> sub help {
>
> print <<EOF;
> Usage: $0 -m "/path/to/top/mp3/dir" [options]
>
> Options are:
> -i image_name File name to save album cover as. Default: cover.jpg
> -d Turn on verbose debugging
> -e Directories to exclude seperated by a "|".
> Use just the dir name, not the full path
> (i.e. "temporary directory|dir to skip" etc.)
>
> EOF
>
> exit;
> }
>
> main();
>
> __END__
>

Dan Sully
2003-11-20, 23:27
* Victor Brilon <victor (AT) victorland (DOT) com> shaped the electrons to say...

> With a few minor modifications, this is almost exactly my code that
> originally I wrote.
> http://www.victorland.com/slimp3
>
> It looks like you made some useful changes in the code -- why not submit
> a patch to me to include them in the original code?
>
> I don't mind (in fact I quite enjoy it) when people use code I created,
> put please at least have the decency to credit the original author. At
> the very least respect the GPL license that this software was released
> under.

Ack - sorry about that. It got dumped into my cvs tree and I hacked it up a
bunch. If I recall, my changes didn't really map cleanly onto your code. I
can try and wedge them in there if you'd like.

-D
--
Flash, don't heckle the supervillan!

Victor Brilon
2003-11-21, 05:23
No problem at all -- if you'd like to send me an email offline just
describing the changes you made and I'd be happy to write the actual
code to do so.

Thanks!
Victor

Dan Sully wrote:
> * Victor Brilon <victor (AT) victorland (DOT) com> shaped the electrons to say...
>
>
>>With a few minor modifications, this is almost exactly my code that
>>originally I wrote.
>>http://www.victorland.com/slimp3
>>
>>It looks like you made some useful changes in the code -- why not submit
>>a patch to me to include them in the original code?
>>
>>I don't mind (in fact I quite enjoy it) when people use code I created,
>>put please at least have the decency to credit the original author. At
>>the very least respect the GPL license that this software was released
>>under.
>
>
> Ack - sorry about that. It got dumped into my cvs tree and I hacked it up a
> bunch. If I recall, my changes didn't really map cleanly onto your code. I
> can try and wedge them in there if you'd like.
>
> -D