All pastes #175210 Raw Edit

jespern

public text v1 · immutable
·published 2006-09-18 16:16 UTC
rendered paste body
# i7AWF.pm - $Id$
#
# Fetches (free) artwork from iTMS, iTunes 7 style.
# Copyright (c) 2006 Jesper Noehr <jesper@noehr.org>
# Version 0.1 - Licensed under the Creative Commons share-alike license.

package i7AWF;

use strict;
use LWP::UserAgent;
use Digest::MD5 qw/md5_hex/;
use MIME::Base64;
use Compress::Zlib;
use XML::Simple;

# Define some constants. Notice the i7_STORE, which points to the local store. Change if you want to.

use constant {
    i7_UA => "iTunes/7.0 (Macintosh; U; PPC Mac OS X 10.4.7)",
    i7_URL => 'http://ax.phobos.apple.com.edgesuite.net/WebObjects/MZSearch.woa/wa/coverArtMatch?an=%s&pn=%s',
    i7_STORE => 143457,
};

sub new {
    my( $class ) = shift;
    return bless { artist => undef, album => undef, }, $class;
}

# Setters

sub artist {
    my( $self, $artist ) = @_;
    $self->{ 'artist' } = $artist;
}

sub album {
    my( $self, $album ) = @_;
    $self->{ 'album' } = $album;
}

# Actual request. Creates new UA if not used before, and creates a new request object, per call.
# Caches result, and passes on to some nifty XML parsers. Notice content is GZIP'ed.

sub payload {
    my( $self ) = @_;

    if (!defined $self->{ 'UA' }) {
	$self->{ 'UA' } = new LWP::UserAgent;
	$self->{ 'UA' }->agent( i7_UA );
    }

    my $comped_url = sprintf( i7_URL, $self->{ 'artist' }, $self->{ 'album'} );
    $comped_url =~ s/\s/%20/g;

    my $req = HTTP::Request->new( GET => $comped_url );
    $req->header
	( "X-Apple-Tz" => "7200",
	  "X-Apple-Store-Front" => i7_STORE,
	  "Accept-Language","en-us, en;q=0.50",
	  "X-Apple-Validation" => $self->comp_seed( $comped_url, i7_UA ),
	  "Accept-Encoding" => "gzip, x-aes-cbc",
	  "Connection" => "close",
	  "Host" => "ax.phobos.apple.com.edgesuite.net",
	);

    $self->{ 'cached' } = $self->{ 'UA' }->request( $req );

    if ( !$self->{ 'cached' }->is_success ) {
	return $self->{ 'cached' }->status_line;
    }

    return $self->get_URL( Compress::Zlib::memGunzip( $self->{ 'cached' }->content ) );

}

# Returns the URL (if found), or undef on error. Payload calls this, but you can call it manually on the cached result.

sub get_URL {
    my( $self, $result ) = @_;

    # If this is called before payload, simply call it.
    if ( !$self->{ 'cached' } ) {
	return $self->payload;
    }

    my $xs = new XML::Simple;
    my $xh = $xs->XMLin( $result );
    my $xp = $xh->{ 'Protocol' }->{ 'plist' }->{ 'dict' };

    return undef unless $xp->{ 'integer' } == 0;

    return $xp->{ 'string' } [0];
}

# Some magic. Generates a seed we use for X-Apple-Validation. Adapted from LWP::UserAgent::iTMS_Client.

sub comp_seed {
    my ( $self, $url, $user_agent ) = @_;
    my $random  = sprintf( "%04X%04X", rand(0x10000), rand(0x10000) );
    my $static  = decode_base64("ROkjAaKid4EUF5kGtTNn3Q==");
    my $url_end = ( $url =~ m|.*/.*/.*(/.+)$| ) ? $1 : '?';
    my $digest  = md5_hex( $url_end, $user_agent, $static, $random );
    return $random . '-' . uc $digest;
}

=head1 NAME

i7AWF - Fetches artwork from iTMS, iTunes 7 style

=head1 SYNOPSIS

    use i7AWF;
    my $i7 = new i7AWF;

    $i7->artist("Dire Straits");
    $i7->album("Sultans of Swing");

    print $i7->payload;

=head1 DESCRIPTION

This perl module fetches missing artwork from iTMS, in the style of
how iTunes 7 does it. It will give you an URL, with the 600x600 album cover.

=head1 METHODS

=item B<new>

    Create a new i7AWF object.

=item B<artist>

    Sets the artist to the given argument.

=item B<album>

    Sets the album to the given argument.

=item B<payload>

    Will perform the actual request to the iTMS servers.
    Upon success, it will return the URL.

=item B<get_URL>

    This is what payload calls in the end. It uses the cached
    result that came in the payload. This means that you can use this
    continuously without re-fetching the request. If there is no cached result,
    get_URL will call payload first.

=head1 AUTHOR

Jesper Noehr L<jesper@noehr.org>

=head1 COPYRIGHT

=over 4

Copyright (c) 2006 Jesper Noehr. All rights reserved.
Licensed under the Creative Commons share-alike license.

=back

=cut

1;