Originally published 2008-11-23

Automatically Downloading Album Covers From Amazon Using Perl

I recently started using SqueezeCenter to stream music from my home computer to my computer at school. It has a nice AJAX web interface, and is a pretty slick system. The web interface will display cover art for each album. I've never cared about cover art before. At home, I use mplayer on the commandline to play my music, so I would never see the cover art. I keep my music meticulously organized into directories by artist and album, so I don't need a fancy music player with a library and such; in fact, those programs drive me absolutely insane. But, since SqueezeCenter can display album art, I suddenly wanted album art.

I found a few applications that download album art from Amazon, but none of them did exactly what I wanted. First, they would all try to download album art baesd on the artist and album found in each music file's tag. This doesn't work perfectly, especially since my music is in a multitude of formats (most of them non-MP3), and since I meticulously organize my music it's not necessary anyway. So that was problem one. Problem two is that they all wanted to either embed the cover art into the music file (fine, if excessive, for MP3s, but bad for other formats), or save the cover art somewhere based on the artist and album found in the tags. This was a big problem, since for much of my music the tags don't exactly match the directory names.

Sigh, I guess I'll have to write something. I found a blog post that describes how to get album art from Amazon using Perl. The script was almost what I needed, so I modified to to do exactly what I wanted. It takes as input a directory path in artist/album format. It tries to find the album art on Amazon, then downloads it to the directory as cover.jpg. It's also smart enough to use almost-matches, so if you have Album disc 1 and Album disc 2 in separate directories, it'll download the right album art for both. You can do something like find ~/media/Music -mindepth 2 -maxdepth 2 -type d -exec ./dlcoverart.pl "{}" \; to download album art for all your music.

Here's the script:

#!/usr/bin/perl -- # -*- Perl -*-

use strict;
use Net::Amazon;
use LWP::UserAgent;
use HTTP::Cookies;

my $lwpua = LWP::UserAgent->new();
my $amzua = Net::Amazon->new(token => 'YOUR-AMAZON-API-KEY');

my $artist;
my $album;
my $path = $ARGV[0];
if($path =~ /.*\/(.+?)\/(.+?)\/?$/) {
    $artist = $1;
    $album = $2;
} else {
    printf("Usage: dlcoverart.pl <path>\n");
    exit;
}

if($album =~ /(.+?) disc.+/i) {
    $album = $1;
}

# Get a request object
my $response = $amzua->search(artist => $artist,
                              mode => 'music',
                              keywords => $album);

my $result;
my $img;
if ($response->is_success()) {
    foreach $result ($response->properties) {
        my $fartist = $result->artist();
        my $falbum = $result->album();

        if($artist =~ /$fartist/i && $album =~ /$falbum/i) {
            printf("Found %s by %s\n", $falbum, $fartist);

            if(defined $result && exists $result->{'ImageUrlLarge'}) {
                $img = $lwpua->get($result->{'ImageUrlLarge'});
            } elsif(defined $result && exists $result->{'ImageUrlMedium'}) {
                $img = $lwpua->get($result->{'ImageUrlMedium'});
            } elsif(defined $result && exists $result->{'ImageUrlSmall'}) {
                $img = $lwpua->get($result->{'ImageUrlSmall'});
            } else {
                print("No images.\n");
                next;
            }
            
            if($img->is_success()) {
                unlink("$path/cover.jpg");
                open(F, ">$path/cover.jpg");
                print(F $img->content());
                close(F);
                printf("Downloaded %s/cover.jpg\n", $path);
                last;
            }
        }
    }
} else {
    print("Error: ", $response->message(), "\n");
}