Net::iTMS::Album - Represents an album in the iTunes Music Store


Net-iTMS documentation Contained in the Net-iTMS distribution.

Index


Code Index:

NAME

Top

Net::iTMS::Album - Represents an album in the iTunes Music Store

SYNOPSIS

Top

    use Net::iTMS::Album;

    my $album = Net::iTMS::Album->new($iTMS, $id);

    print "Album: ", $album->title, "\n";

    # $track will be a Net::iTMS::Song object
    for my $track ($album->tracks) {    # also $album->songs
        print "\t ", $track->number, ": ", $track->title, "\n";
    }

DESCRIPTION

Top

Net::iTMS::Album represents an album in the iTMS and encapsulates the associated data. If a piece of information hasn't been fetched from the iTMS, it will transparently fetch and store it for later use before returning.

If any method, excepting id, record_label, and thumb, is called, the information for the others will be fetched in the same request. This means, for these methods, the first call to one will have a time hit for the HTTP request, but subsequent calls won't.

Methods

new($itms, $albumId)

The first argument must be an instance of Net::iTMS, the second an iTMS album ID.

Returns a blessed hashref (object) for Net::iTMS::Album.

id

Returns the ID of the album (albumId).

title
name

Returns the title of the album.

artist

Returns a Net::iTMS::Artist object for the album's artist.

genre

Returns a Net::iTMS::Genre object for the album's genre.

cover

Returns a hashref with the keys url, width, and height which are for the album's cover.

thumb

Returns a hashref with the keys url, width, and height which are for the thumbnail of the album's cover (if available).

tracks
songs

Returns an array or arrayref (depending on context) of Net::iTMS::Song objects representing the tracklist of the album (in order of track number).

total_songs

Returns the total number of songs on the album available from the iTMS.

released

Returns the release date of the album (if available).

Returns the copyright information for the album (if available).

path

Returns an arrayref of hashrefs representing the album's "path" in the iTMS. The hashrefs contain the name of the node in the path and the iTMS URL of that node.

LICENSE

Top

Copyright 2004, Thomas R. Sibley.

You may use, modify, and distribute this package under the same terms as Perl itself.

AUTHOR

Top

Thomas R. Sibley, http://zulutango.org:82/

SEE ALSO

Top

Net::iTMS, Net::iTMS::Song, Net::iTMS::Artist, Net::iTMS::Genre


Net-iTMS documentation Contained in the Net-iTMS distribution.
package Net::iTMS::Album;
#
# Written by Thomas R. Sibley, <http://zulutango.org:82/>
#
use warnings;
use strict;

use vars '$VERSION';
$VERSION = '0.15';

use Net::iTMS::Error;

use overload
	'""'     => sub { shift->as_string },
	fallback => 1;

sub as_string {
    my $self = shift;
    
    return defined $self
            ? $self->name
            : undef;
}

sub new {
    my ($class, $itms, $id, %prefill) = @_;
    
    my $self = bless {
        id    => $id,
        error => '',
        debug => defined $itms->{debug} ? $itms->{debug} : 0,
        _itms => $itms,
    }, $class;
    
    if (%prefill) {
        $self->{$_} = $prefill{$_}
            for keys %prefill;
    }
    
    return $self;
}

sub id { return $_[0]->{id} }

sub title {
    my $self = shift;
    $self->_get_basic_info
        if not exists $self->{title};
    return $self->{title};
}

sub name { return $_[0]->title }

sub artist {
    my $self = shift;
    $self->_get_basic_info
        if not exists $self->{artist};
    return $self->{artist};
}

sub genre {
    my $self = shift;
    $self->_get_basic_info
        if not exists $self->{genre};
    return $self->{genre};
}

sub cover {
    my $self = shift;
    $self->_get_basic_info
        if not exists $self->{cover};
    return $self->{cover};
}

sub thumb {
    my $self = shift;
    return $self->{thumb};
}

sub record_label {
    my $self = shift;
    return $self->{record_label};
}

sub copyright {
    my $self = shift;
    $self->_get_basic_info
        if not exists $self->{copyright};
    return $self->{copyright};
}

sub released {
    my $self = shift;
    $self->_get_basic_info
        if not exists $self->{released};
    return $self->{released};
}

sub tracks {
    my $self = shift;
    $self->_get_basic_info
        if not exists $self->{tracks};
    return wantarray ? @{$self->{tracks}} : $self->{tracks};
}

sub songs { return $_[0]->tracks }

sub total_songs {
    my $self = shift;
    $self->_get_basic_info
        if not exists $self->{total_songs};
    return $self->{total_songs};
}

sub info {
    my $self = shift;
    $self->_get_basic_info
        if not exists $self->{info};
    return wantarray ? @{$self->{info}} : $self->{info};
}

sub notes {
    my $self = shift;
    $self->_get_basic_info
        if not exists $self->{notes};
    return wantarray ? @{$self->{notes}} : $self->{notes};
}

sub path {
    my $self = shift;
    $self->_get_basic_info
        if not exists $self->{path};
    return wantarray ? @{$self->{path}} : $self->{path};
}

#
# This populates the basic data from a viewAlbum request
#
sub _get_basic_info {
    my $self = shift;
    
    my $twig = $self->{_itms}->{_request}->url('viewAlbum', $self->id);
    
    my $root = $twig->root;
    my $path = $root->first_child('Path');
    my $sv   = $root->first_child('ScrollView');
    
    $self->{genre} = $self->{_itms}->get_genre($root->att('genreId'));
    
    #
    # Path
    #
    for my $child ($path->children('PathElement')) {
        push @{$self->{path}}, {
            name => $child->att('displayName'),
            url  => $child->trimmed_text,
        };
    }
    
    $path->delete;

    #
    # Name and cover
    #
    # We could just depend on the right twig being the first
    # in the document everytime, but let's not
    #
    my $album;
    for my $child ($sv->descendants('ViewAlbum')) {
        if (defined $child->{att}{draggingName}
                and $child->first_child_matches('PictureView')) {
            # This is the one we want, so break out
            $album = $child;
            last;
        }
    }
    
    $self->{title} = $album->att('draggingName');

    my $pic = $album->first_child('PictureView');
    $self->{cover} = {
        height => $pic->att('height'),
        width  => $pic->att('width'),
        url    => $pic->att('url'),
    };
    
    $pic->delete;
    $album->delete;

    if ($root->att('genreId') == 50000024) {
        # have to bail for now
        $sv->delete;
        $twig->purge;
        return;
    }

    #
    # Artist
    #
    if (not defined $self->{artist}) {
        my $artist;
        for my $child ($sv->descendants('ViewArtist')) {
            if (defined $child->{att}{id}
                    and $child->{att}{id} eq $root->att('artistId')) {
                # This is the one we want, so break out
                $artist = $child;
                last;
            }
        }

        if (defined $artist) {
            $self->{artist} = $self->{_itms}->get_artist(
                                    $root->att('artistId'),
                                    name => $artist->trimmed_text,
                              );
            $artist->delete;
        }
    }
    
    #
    # Info
    #
    for my $text ($sv->first_child('MatrixView')
                     ->first_child('VBoxView')
                     ->first_child('MatrixView')
                     ->first_child('VBoxView')
                     ->children('TextView')) {
        if ($text->contains_only_text and $text->trimmed_text ne '') {
            my $val = $text->trimmed_text;
            push @{$self->{info}}, $val;
            
            $val =~ s/^\s*//;
            $val =~ s/\s*$//;
            
            if    ($val =~ s/^Release Date:\s*//) { $self->{released}    = $val; }
            elsif ($val =~ s/^Total Songs:\s*//)  { $self->{total_songs} = $val; }
            elsif ($val =~ s/^Genre:\s*//)        { $self->{genre}{name} = $val; }
            elsif ($val =~ s/^.+\s*(?>\d{4})//)   { $self->{copyright}   = $val; }
        }
    }
    
    #
    # Notes
    #
    my $notes = $sv->first_child('MatrixView')
                   ->first_child('VBoxView')
                   ->last_child('HBoxView');

    if (defined $notes) {
        $notes = $notes->first_child('VBoxView');
        if (defined $notes) {
            for my $text ($notes->first_child('TextView')
                                ->next_siblings('TextView')) {
                push @{$self->{notes}}, $text->trimmed_text;
            }
        }
        $notes->delete;
    }
    
    $sv->delete;
    
    #
    # Tracks
    #
    my $plist = $root->first_child('TrackList')
                     ->first_child('plist')
                     ->first_child('dict')
                     ->first_child('array');
    
    $self->{tracks} = [ ];
    
    for my $dict ($plist->children('dict')) {
        my %data;
        for my $key ($dict->children('key')) {
            $data{$key->trimmed_text} = $key->next_sibling('#ELT')->trimmed_text;
        }

        $data{releaseDate} =~ s/A-Za-z//g;
        $data{copyright}   =~ s/^.+\s*(?>\d{4})//;
        $data{copyright}   =~ s/\s*$//;
                
        push @{$self->{tracks}},
             $self->{_itms}->get_song(
                    $data{songId},
                    title       => $data{songName},
                    album       => $self,
                    artist      => $self->{artist},
                    genre       => $self->{_itms}->get_genre(
                                        $data{genreId},
                                        name => $data{genre},
                                   ),
                    year        => $data{year},
                    number      => $data{trackNumber},
                    count       => $data{trackCount},
                    disc_number => $data{discNumber},
                    disc_count  => $data{discCount},
                    explicit    => $data{explicit},
                    comments    => $data{comments},
                    copyright   => $data{copyright},
                    preview_url => $data{previewURL},
                    released    => $data{releaseDate},
                    price       => $data{priceDisplay},
                    vendor      => $data{vendorId},
             );
    }
    $plist->delete;
    $twig->purge;
    
    $self->{total_songs} = $self->{tracks}[0]{count}
        if not $self->{total_songs};
}

42;