|
|
|
package Text::Playlist::XSPF;
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use warnings;
|
|
|
|
use feature qw(switch);
|
|
|
|
use utf8;
|
|
|
|
|
|
|
|
use base 'Text::Playlist';
|
|
|
|
use XML::XPath;
|
|
|
|
|
|
|
|
our $VERSION = "v0.1.0";
|
|
|
|
|
|
|
|
sub new {
|
|
|
|
my ($class) = @_;
|
|
|
|
|
|
|
|
return bless({ version => 0 }, $class);
|
|
|
|
}
|
|
|
|
|
|
|
|
sub parse {
|
|
|
|
my ($self, $text) = @_;
|
|
|
|
my @items = ();
|
|
|
|
|
|
|
|
my $xp = XML::XPath->new(xml => $text);
|
|
|
|
if (my $vers = $xp->find('/playlist/@version')) {
|
|
|
|
$self->{version} = $vers;
|
|
|
|
} else {
|
|
|
|
return "Can't find playlist version";
|
|
|
|
}
|
|
|
|
|
|
|
|
my $tracks = $xp->find('/playlist/trackList/track');
|
|
|
|
foreach my $track ($tracks->get_nodelist) {
|
|
|
|
my $item = {};
|
|
|
|
foreach my $child ($track->getChildNodes) {
|
|
|
|
next unless (ref $child eq 'XML::XPath::Node::Element');
|
|
|
|
my $value = $child->string_value();
|
|
|
|
given ($child->getName()) {
|
|
|
|
when (m/title/oi) { $item->{title} = $value; }
|
|
|
|
when (m/location/oi) { $item->{location} = $value; }
|
|
|
|
default { warn "garbage inside <track> element: $_ -> $value\n"; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
unless ($item->{title} and $item->{location}) {
|
|
|
|
warn "Missing mandatory 'title' or 'location' field\n";
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
push @items, $item;
|
|
|
|
}
|
|
|
|
|
|
|
|
return wantarray ? @items : [ @items ];
|
|
|
|
}
|
|
|
|
|
|
|
|
sub dump { die("dump() unimplemented for XSPF format\n"); }
|
|
|
|
|
|
|
|
1;
|
|
|
|
|
|
|
|
__END__
|
|
|
|
|
|
|
|
=pod
|
|
|
|
|
|
|
|
=head1 NAME
|
|
|
|
|
|
|
|
Text::Playlist::XSPF - parser for 'xspf' format
|
|
|
|
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
|
|
|
|
my $xspf = Text::Playlist::XSPF->new;
|
|
|
|
my @items = $xspf->load('/path/to/playlist.xspf');
|
|
|
|
|
|
|
|
foreach my $item (@items) {
|
|
|
|
<work with playlist items>
|
|
|
|
}
|
|
|
|
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
|
|
|
|
Fast-and-dirty parser for xspf playlist.
|
|
|
|
Will be usefull if you're just want to read playlist or simple want
|
|
|
|
to convert such playlist to more common alternative.
|
|
|
|
|
|
|
|
=head2 C<load>
|
|
|
|
=head2 C<parse>
|
|
|
|
=head2 C<save>
|
|
|
|
=head2 C<dump>
|
|
|
|
|
|
|
|
For description of these methods see description in base class L<Text::Playlist>
|
|
|
|
|
|
|
|
=head1 Item format
|
|
|
|
|
|
|
|
Each parsed item has the following keys in hashref:
|
|
|
|
|
|
|
|
* location -- path or url, required. Following formats acceptable:
|
|
|
|
- Windows Path : file:///C:/music/foo.mp3
|
|
|
|
- Linux Path : file:///media/music/foo.mp3
|
|
|
|
- Relative Path : music/foo.mp3
|
|
|
|
- External URL : http://www.example.com/music/bar.ogg
|
|
|
|
* title -- title for given item, required
|
|
|
|
|
|
|
|
=head1 TODO
|
|
|
|
|
|
|
|
C<dump()> method still not implemented
|
|
|
|
|
|
|
|
=head1 SEE ALSO
|
|
|
|
|
|
|
|
L<XML::Toolkit> -- contains complete implementation for work with XSPF format
|
|
|
|
|
|
|
|
=head1 LINKS
|
|
|
|
|
|
|
|
L<https://en.wikipedia.org/wiki/XML_Shareable_Playlist_Format>
|
|
|
|
|
|
|
|
=head1 AUTHORS
|
|
|
|
|
|
|
|
Alex 'AdUser' Z <aduser@cpan.org>
|
|
|
|
|
|
|
|
=cut
|