Skip Menu |

This queue is for tickets about the Mac-iTunes-Library CPAN distribution.

Report information
The Basics
Id: 50668
Status: resolved
Priority: 0/
Queue: Mac-iTunes-Library

People
Owner: dinomite [...] cpan.org
Requestors: mgrimes [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: (no value)
Fixed in: (no value)



Subject: [PATCH] basic implementation of playlists
Drew, First, thanks for the Mac::iTunes::Library module. I'm trying to sync music libraries between iTunes on a Mac and a PC, and custom music software on Linux. With your module, it just might be possible. One of the primary things I need is the ability to transfer playlists, so I added playlist parsing to your module. It is very much tossed together, but it works for me and all the tests pass. My changes are in the attached patch. Hope this is useful for you and others. -Mark
Subject: 0001-Added-very-basic-playlist-parsing.patch
From 568ba764bf2ef86a01f9c911532f5b45d90eab59 Mon Sep 17 00:00:00 2001 From: Mark Grimes <mgrimes@new-host-2.grimes.homeip.net> Date: Mon, 19 Oct 2009 21:52:57 -0400 Subject: [PATCH] Added very basic playlist parsing --- lib/Mac/iTunes/Library.pm | 19 +++++++++- lib/Mac/iTunes/Library/Playlist.pm | 5 ++- lib/Mac/iTunes/Library/XML.pm | 71 +++++++++++++++++++++++++++++------- t/ParsePlaylist.t | 31 ++++++++++++++++ 4 files changed, 110 insertions(+), 16 deletions(-) create mode 100644 t/ParsePlaylist.t diff --git a/lib/Mac/iTunes/Library.pm b/lib/Mac/iTunes/Library.pm index 6d2c49d..d2cb52b 100644 --- a/lib/Mac/iTunes/Library.pm +++ b/lib/Mac/iTunes/Library.pm @@ -69,7 +69,8 @@ sub new { Genre => {}, # Genre counts by tracks PGenre => {}, # Genre counts by playcount Type => {}, # Track types, file or URL - Items => {} + Items => {}, + Playlists => {}, }; bless $self, $class; @@ -457,6 +458,10 @@ sub _item { # First occurrence of this artist $self->{'Items'}{$artist}{$name} = [$item]; } + + # print "creating item: " . $item->trackID . "\n"; + $self->{'ItemsById'}{$item->trackID} = \$item; # TODO: this should be a ref + } #_item =item add( Mac::iTunes::Library::Item ) @@ -499,6 +504,18 @@ sub add { $self->_item($item); } #add +sub addPlaylist { + my $self = shift; + my $playlist = shift; + + $self->{'Playlists'}->{ $playlist->{'Playlist ID'} } = $playlist; +} + +sub playlists { + my $self = shift; + return %{$self->{'Playlists'}}; +} + 1; =head1 SEE ALSO diff --git a/lib/Mac/iTunes/Library/Playlist.pm b/lib/Mac/iTunes/Library/Playlist.pm index a5a6e1a..a5f983c 100644 --- a/lib/Mac/iTunes/Library/Playlist.pm +++ b/lib/Mac/iTunes/Library/Playlist.pm @@ -170,10 +170,10 @@ sub name { if (@_) { my $name = shift; - $self->{'name'} = $name; + $self->{'Name'} = $name; } - return $self->{'name'}; + return $self->{'Name'}; } #name =item playlistID( id ) @@ -288,6 +288,7 @@ sub addItem { unless ($item->isa('Mac::iTunes::Library::Item')); push @{$self->{'items'}}, $item; + # TODO: shouldn't this be referencing a track already in the lib? } #addItem =item addItems( Mac::iTunes::Library::Item ) diff --git a/lib/Mac/iTunes/Library/XML.pm b/lib/Mac/iTunes/Library/XML.pm index 5b8d30a..4c11079 100644 --- a/lib/Mac/iTunes/Library/XML.pm +++ b/lib/Mac/iTunes/Library/XML.pm @@ -7,7 +7,9 @@ use Carp; use Mac::iTunes::Library; use Mac::iTunes::Library::Item; +use Mac::iTunes::Library::Playlist; use XML::Parser; +# use Data::Dump qw(pp); require Exporter; our @ISA = qw(Exporter); @@ -53,7 +55,7 @@ my $library; # Characters that we collect my $characters = undef; # Keep track of where we are; push on each element name as we hit it -my @stack; +my (@stack, @pl_stack); my ($inTracks, $inPlaylists, $inMajorVersion, $inMinorVersion, $inApplicationVersion, $inFeatures, $inMusicFolder, $inLibraryPersistentID) = undef; @@ -75,14 +77,14 @@ sub parse { ### Parser start element sub start_element { my ($expat, $element, %attrs) = @_; - - # Don't deal with playlists yet - return if ($inPlaylists); # Keep a trail of our depth push @stack, $element; my $depth = scalar(@stack); + # print "*" if $inPlaylists; + # print "> $depth: $element" . pp( %attrs) . "\n" if $inPlaylists; + if ( $depth == 0 ) { } elsif ( $depth == 1 ) { # Hit the initial <plist version=""> tag @@ -91,12 +93,22 @@ sub start_element { } } elsif ( $depth == 2 ) { } elsif ( $depth == 3 ) { - if (($element eq 'true') or ($element eq 'false')) { - $library->showContentRatings($element); + if( $inPlaylists ){ + } else { + if (($element eq 'true') or ($element eq 'false')) { + $library->showContentRatings($element); + } } } elsif ( $depth == 4 ) { # We hit a new item in the XML; create a new object - $item = Mac::iTunes::Library::Item->new() if ($element eq 'dict'); + + if( $inPlaylists ){ + # print "create new playlist\n"; + $item = Mac::iTunes::Library::Playlist->new() if ($element eq 'dict'); + } else { + $item = Mac::iTunes::Library::Item->new() if ($element eq 'dict'); + } + } elsif( $depth == 5 ){ } } #start_element @@ -104,13 +116,13 @@ sub start_element { sub end_element { my ($expat, $element) = @_; - # Don't deal with playlists yet - return if ($inPlaylists); - # Prune the trail my $depth = scalar(@stack); pop @stack; + # print "*" if $inPlaylists; + # print "< $depth: $element\n" if $inPlaylists; + if ( $depth == 0 ) { # plist version } elsif ( $depth == 1 ) { # dict } elsif ( $depth == 2 ) { @@ -126,19 +138,43 @@ sub end_element { } } elsif ( $depth == 4 ) { # Ending an item; add it to the library and clean up - if ( $item ) { - $library->add($item); + if( $inPlaylists ){ + if ( $item ) { + # print pp $item; + # print "add pl to library\n"; + $library->addPlaylist($item); + } + } else { + if ( $item ) { + $library->add($item); + } } $item = undef if ($element eq 'dict'); } elsif ( $depth == 5 ) { # Set the attributes of the Mac::iTunes::Library::Item directly if ( $element =~ /(integer|string|date)/ ) { + if( $inPlaylists ){ + # print "$curKey = $characters\n"; + } $item->{$curKey} = $characters; $characters = undef; } elsif ( $element =~ /true/ ) { $item->{$curKey} = 1; } + } elsif( $depth == 7 ){ + if ( $element =~ /(integer)/ ) { + # print "Adding $curKey => $characters\n"; + + my $track = $library->{'ItemsById'}{$characters}; + if( ref $track and $$track ){ + $item->addItem( $$track ); + } else { + warn "Couldn't find track '$characters'\n"; + } + + $characters = undef; + } } } #end_element @@ -147,7 +183,8 @@ sub characters { my ($expat, $string) = @_; my $depth = scalar(@stack); - return if ($inPlaylists); + # print "*" if $inPlaylists; + # print "= $depth: $string\n" if $inPlaylists; if ( $depth == 0 ) { # plist version } elsif ( $depth == 1 ) { # dict @@ -203,6 +240,14 @@ sub characters { # Append it to the characters that we've gathered so far $characters .= $string; } + } elsif( $depth == 7 ) { + if ( $stack[$#stack] eq 'key' ) { + # Grab the key's name; always comes in a single chunk + $curKey = $string; + } elsif ( $stack[$#stack] =~ /(integer|string|date)/ ) { + # Append it to the characters that we've gathered so far + $characters .= $string; + } } } #characters diff --git a/t/ParsePlaylist.t b/t/ParsePlaylist.t new file mode 100644 index 0000000..d88788e --- /dev/null +++ b/t/ParsePlaylist.t @@ -0,0 +1,31 @@ +# Before `make install' is performed this script should be runnable with +# `make test'. After `make install' it should work as `perl Mac-iTunes-Item.t' + +=head1 SVN INFO + +$Revision: 66 $ +$Date: 2009-05-03 22:18:46 -0700 (Sun, 03 May 2009) $ +$Author: drewgstephens $ + +=cut + +######################### +use lib "."; +use 5; +use Test::More tests => 5; +BEGIN { use_ok('Mac::iTunes::Library::XML') }; +######################### + +my $lib = Mac::iTunes::Library::XML->parse('t/iTunes_Music_Library.xml'); + +use Data::Dump; + +# dd $lib; +# dd $lib->playlists; + +my %playlists = $lib->playlists; +is( scalar keys %playlists, 2, 'playlist count' ); +my $playlist = $playlists{10073}; +ok( $playlist, 'found expected playlist' ); +is( $playlist->name, '5 Stars', '... has the right name' ); +is( scalar $playlist->items, 17, '... has the right track count' ); -- 1.6.4.4
Subject: Re: [rt.cpan.org #50668] [PATCH] basic implementation of playlists
Date: Tue, 20 Oct 2009 00:31:18 -0700
To: bug-Mac-iTunes-Library [...] rt.cpan.org
From: Drew Stephens <dinomite [...] cpan.org>
Thanks for the patch, and I'm glad to hear the module is useful for you! With any luck, I'll get around to integrating your diff no later than this weekend. -Drew On Mon, Oct 19, 2009 at 7:07 PM, Mark Grimes via RT <bug-Mac-iTunes-Library@rt.cpan.org> wrote: Show quoted text
> Mon Oct 19 22:07:09 2009: Request 50668 was acted upon. > Transaction: Ticket created by MGRIMES >       Queue: Mac-iTunes-Library >     Subject: [PATCH] basic implementation of playlists >   Broken in: (no value) >    Severity: Normal >       Owner: Nobody >  Requestors: mgrimes@cpan.org >      Status: new >  Ticket <URL: https://rt.cpan.org/Ticket/Display.html?id=50668 > > > > Drew, > > First, thanks for the Mac::iTunes::Library module. I'm trying to sync > music libraries between iTunes on a Mac and a PC, and custom music > software on Linux. With your module, it just might be possible. > > One of the primary things I need is the ability to transfer playlists, > so I added playlist parsing to your module. It is very much tossed > together, but it works for me and all the tests pass. My changes are in > the attached patch. > > Hope this is useful for you and others. > > -Mark > >
Uploaded to PAUSE, on it's way to CPAN.