POE-Component-Client-MPD-2.000/0000755000076400001440000000000012346054456015333 5ustar jquelinusersPOE-Component-Client-MPD-2.000/lib/0000755000076400001440000000000012346054456016101 5ustar jquelinusersPOE-Component-Client-MPD-2.000/lib/POE/0000755000076400001440000000000012346054456016524 5ustar jquelinusersPOE-Component-Client-MPD-2.000/lib/POE/Component/0000755000076400001440000000000012346054456020466 5ustar jquelinusersPOE-Component-Client-MPD-2.000/lib/POE/Component/Client/0000755000076400001440000000000012346054456021704 5ustar jquelinusersPOE-Component-Client-MPD-2.000/lib/POE/Component/Client/MPD/0000755000076400001440000000000012346054456022324 5ustar jquelinusersPOE-Component-Client-MPD-2.000/lib/POE/Component/Client/MPD/Connection.pm0000644000076400001440000002656112346054456024773 0ustar jquelinusers# # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; package POE::Component::Client::MPD::Connection; # ABSTRACT: module handling the tcp connection with mpd $POE::Component::Client::MPD::Connection::VERSION = '2.000'; use Audio::MPD::Common::Item; use POE; use POE::Component::Client::TCP; use Readonly; use POE::Component::Client::MPD::Message; # for exported constants # -- attributes # -- public methods sub spawn { my ($type, $args) = @_; # connect to mpd server. my $id = POE::Component::Client::TCP->new( RemoteAddress => $args->{host}, RemotePort => $args->{port}, Filter => 'POE::Filter::Line', Args => [ $args ], Alias => '_mpd_conn', ServerError => sub { }, # quiet errors Started => \&_Started, Connected => \&_Connected, ConnectError => \&_ConnectError, Disconnected => \&_Disconnected, ServerInput => \&_ServerInput, InlineStates => { send => \&send, # send data disconnect => \&disconnect, # force quit }, ); return $id; } # -- public events sub disconnect { $_[HEAP]->{auto_reconnect} = 0; # no more auto-reconnect. $_[KERNEL]->yield( 'shutdown' ); # shutdown socket. } sub send { my ($k, $h, $msg) = @_[KERNEL, HEAP, ARG0]; # Test to see if we're currently connected to MPD... if ($h->{connected}) { # ... if we are, it's all good, so send messages ... $h->{server}->put( @{ $msg->_commands } ); push @{ $h->{fifo} }, $msg; } elsif ($h->{auto_reconnect} == 1) { # ... and if not, retry the send in 2 seconds. $k->delay_set(send => 2, $msg); } } # -- private events # # event: Started($id) # # Called whenever the session is started, but before the tcp connection is # established. Receives the session $id of the poe-session that will be our # peer during the life of this session. # sub _Started { my ($h, $args) = @_[HEAP, ARG0]; # storing params $h->{session} = $args->{id}; # poe-session peer $h->{max_retries} = $args->{max_retries} // 5; # max retries before giving up $h->{retry_wait} = $args->{retry_wait} // 2; # sleep time before retry # setting session vars $h->{auto_reconnect} = 1; # on-disconnect policy $h->{retries_left} = $h->{max_retries}; # how much chances is there still? } # # event: Connected() # # Called whenever the tcp connection is established. # sub _Connected { my $h = $_[HEAP]; $h->{fifo} = []; # reset current messages $h->{incoming} = []; # reset incoming data $h->{is_mpd} = 0; # is remote server a mpd sever? $h->{retries_left} = $h->{max_retries}; # reset connection retries count } # # event: ConnectError($syscall, $errno, $errstr) # # Called whenever the tcp connection fails to be established. Generally # due to mpd server not started, or wrong host / port, etc. Receives # the $syscall that failed, as well as $errno and $errstr. # sub _ConnectError { my ($k, $h, $syscall, $errno, $errstr) = @_[KERNEL, HEAP, ARG0, ARG1, ARG2]; return unless $h->{auto_reconnect}; # check if this is the last allowed error. $h->{retries_left}--; my ($event, $msg); if ( $h->{retries_left} > 0 ) { # nope, we can reconnect $event = 'mpd_connect_error_retriable'; $msg = ''; # auto-reconnect in $retry_wait seconds $k->delay_add('reconnect' => $h->{retry_wait}); } else { # yup, it was our last chance. $event = 'mpd_connect_error_fatal'; $msg = 'Too many failed attempts! error was: '; } # signal that there was a problem during connection my $error = $msg . "$syscall: ($errno) $errstr"; $k->post( $h->{session}, $event, $error ); } # # event: Disconnected() # # Called whenever the tcp connection is broken / finished. # sub _Disconnected { my ($k, $h) = @_[KERNEL, HEAP]; # signal that we're disconnected $k->post($h->{session}, 'mpd_disconnected'); # auto-reconnect in $retry_wait seconds return unless $h->{auto_reconnect}; $k->delay_add('reconnect' => $h->{retry_wait}); } # # event: ServerInput($input) # # Called whenever the tcp peer sends data over the wires, with the $input # transmitted given as param. # sub _ServerInput { my ($k, $h, $input) = @_[KERNEL, HEAP, ARG0]; # did we check we were talking to a mpd server? if ( not $h->{is_mpd} ) { _got_first_input_line($k, $h, $input); return; } # table of dispatch: check input against regex, and process it. if ( $input =~ /^OK$/ ) { _got_data_eot($k, $h); } elsif ( $input =~ /^ACK (.*)/ ) { _got_error($k, $h, $1); } else { _got_data($k, $h, $input); } } # -- private subs # # _got_data($kernel, $heap, $input); # # called when receiving another piece of data. # sub _got_data { my ($k, $h, $input) = @_; # regular data, to be cooked (if needed) and stored. my $msg = $h->{fifo}[0]; if ( $msg->_cooking eq "raw" ) { # nothing to do, just push the data. push @{ $h->{incoming} }, $input; } elsif ( $msg->_cooking eq "as_items" ) { # Lots of POCOCM methods are sending commands and then parse the # output to build an amc-item. my ($k,$v) = split /:\s+/, $input, 2; $k = lc $k; $k =~ s/-/_/; if ( $k eq 'file' || $k eq 'directory' || $k eq 'playlist' ) { # build a new amc-item my $item = Audio::MPD::Common::Item->new( $k => $v ); push @{ $h->{incoming} }, $item; } # just complete the current amc-item $h->{incoming}[-1]->$k($v); } elsif ( $msg->_cooking eq "as_kv" ) { # Lots of POCOCM methods are sending commands and then parse the # output to get a list of key / value (with the colon ":" acting # as separator). my @data = split(/:\s+/, $input, 2); push @{ $h->{incoming} }, @data; } elsif ( $msg->_cooking eq "strip_first" ) { # Lots of POCOCM methods are sending commands and then parse the # output to remove the first field (with the colon ":" acting as # separator). $input = ( split(/:\s+/, $input, 2) )[1]; push @{ $h->{incoming} }, $input; } } # # _got_data_eot($kernel, $heap) # # called when the stream of data is finished. used to send the received # data. # sub _got_data_eot { my ($k, $h) = @_; my $session = $h->{session}; my $msg = shift @{ $h->{fifo} }; # remove completed msg $msg->_set_data($h->{incoming}); # complete message with data $msg->set_status(1); # success $k->post($session, 'mpd_data', $msg); # signal poe session $h->{incoming} = []; # reset incoming data } # # _got_error($kernel, $heap, $errstr); # # called when the mpd server reports an error. used to report the error # to the pococm. # sub _got_error { my ($k, $h, $errstr) = @_; my $session = $h->{session}; my $msg = shift @{ $h->{fifo} }; $k->post($session, 'mpd_error', $msg, $errstr); } # # _got_first_input_line($kernel, $heap, $input); # # called when the mpd server fires the first line. used to check whether # we are talking to a regular mpd server. # sub _got_first_input_line { my ($k, $h, $input) = @_; if ( $input =~ /^OK MPD (.*)$/ ) { $h->{is_mpd} = 1; # remote server *is* a mpd sever $k->post($h->{session}, 'mpd_connected', $1); } else { # oops, it appears that it's not a mpd server... $k->post( $h->{session}, 'mpd_connect_error_fatal', "Not a mpd server - welcome string was: '$input'", ); } } 1; __END__ =pod =head1 NAME POE::Component::Client::MPD::Connection - module handling the tcp connection with mpd =head1 VERSION version 2.000 =head1 DESCRIPTION This module will spawn a poe session responsible for low-level communication with mpd. It is written as a L, which is taking care of everything needed. Note that you're B supposed to use this class directly: it's one of the helper class for L. =head1 ATTRIBUTES =head2 host The hostname of the mpd server. Mandatory, no default. =head2 port The port of the mpd server. Mandatory, no default. =head2 id The POE session id of the peer to dialog with. Mandatory, no default. =head2 max_retries How much time to attempt reconnection before giving up. Defaults to 5. =head2 retry_wait How much time to wait (in seconds) before attempting socket reconnection. Defaults to 2. =head1 METHODS =head2 my $id = POE::Component::Client::MPD::Connection->spawn( \%params ); This method will create a L session responsible for low-level communication with mpd. It will return the poe id of the session newly created. =head1 PUBLIC EVENTS ACCEPTED =head2 disconnect( ) Request the pococm-connection to be shutdown. This does B shut down the MPD server. No argument. =head2 send( $message ) Request pococm-conn to send the C<$message> over the wires. Note that this request is a L object properly filled up, and that the C<_commands()> attribute should B be newline terminated. =head1 PUBLIC EVENTS FIRED The following events are fired from the spawned session. =head2 mpd_connected( $version ) Fired when the session is connected to a mpd server. This event isn't fired when the socket connection takes place, but when the session has checked that remote peer is a real mpd server. C<$version> is the advertised mpd server version. =head2 mpd_connect_error_fatal( $errstr ) Fired when the session encounters a fatal error. This happens either when the session is connected to a server which happens to be something else than a mpd server, or if there was more than C (see C params) connection retries in a row. C<$errstr> will contain the problem encountered. No retries will be done. =head2 mpd_connect_error_retriable( $errstr ) Fired when the session has troubles connecting to the server. C<$errstr> will point the faulty syscall that failed. Re-connection will be tried after C<$retry_wait> seconds (see C params). =head2 mpd_data( $msg ) Fired when C<$msg> has been sent over the wires, and mpd server has answered with success. The actual output should be looked up in C<$msg->_data>. =head2 mpd_disconnected( ) Fired when the socket has been disconnected for whatever reason. Note that this event is B fired in the case of a programmed shutdown (see C event above). A reconnection will be automatically re-tried after C<$retry_wait> (see C params). =head2 mpd_error( $msg, $errstr ) Fired when C<$msg> has been sent over the wires, and mpd server has answered with the error message C<$errstr>. =head1 AUTHOR Jerome Quelin =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2007 by Jerome Quelin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut POE-Component-Client-MPD-2.000/lib/POE/Component/Client/MPD/Collection.pm0000644000076400001440000001753412346054456024767 0ustar jquelinusers# # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; package POE::Component::Client::MPD::Collection; # ABSTRACT: module handling collection commands $POE::Component::Client::MPD::Collection::VERSION = '2.000'; use Moose; use MooseX::Has::Sugar; use POE; use POE::Component::Client::MPD::Message; has mpd => ( ro, required, weak_ref, );# isa=>'POE::Component::Client::MPD' ); # -- Collection: retrieving songs & directories sub _do_all_items { my ($self, $msg) = @_; my $path = $msg->params->[0] // ''; # FIXME: padre// $msg->_set_commands ( [ qq{listallinfo "$path"} ] ); $msg->_set_cooking ( 'as_items' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_all_items_simple { my ($self, $msg) = @_; my $path = $msg->params->[0] // ''; # FIXME: padre// $msg->_set_commands ( [ qq{listall "$path"} ] ); $msg->_set_cooking ( 'as_items' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_items_in_dir { my ($self, $msg) = @_; my $path = $msg->params->[0] // ''; # FIXME: padre// $msg->_set_commands ( [ qq{lsinfo "$path"} ] ); $msg->_set_cooking ( 'as_items' ); $self->mpd->_send_to_mpd( $msg ); } # -- Collection: retrieving the whole collection # event: coll.all_songs() # FIXME? sub _do_all_albums { my ($self, $msg) = @_; $msg->_set_commands ( [ 'list album' ] ); $msg->_set_cooking ( 'strip_first' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_all_artists { my ($self, $msg) = @_; $msg->_set_commands ( [ 'list artist' ] ); $msg->_set_cooking ( 'strip_first' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_all_titles { my ($self, $msg) = @_; $msg->_set_commands ( [ 'list title' ] ); $msg->_set_cooking ( 'strip_first' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_all_files { my ($self, $msg) = @_; $msg->_set_commands ( [ 'list filename' ] ); $msg->_set_cooking ( 'strip_first' ); $self->mpd->_send_to_mpd( $msg ); } # -- Collection: picking songs sub _do_song { my ($self, $msg) = @_; my $what = $msg->params->[0]; $msg->_set_commands ( [ qq{find filename "$what"} ] ); $msg->_set_cooking ( 'as_items' ); $msg->_set_transform( 'as_scalar' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_songs_with_filename_partial { my ($self, $msg) = @_; my $what = $msg->params->[0]; $msg->_set_commands ( [ qq{search filename "$what"} ] ); $msg->_set_cooking ( 'as_items' ); $self->mpd->_send_to_mpd( $msg ); } # -- Collection: songs, albums & artists relations sub _do_albums_by_artist { my ($self, $msg) = @_; my $what = $msg->params->[0]; $msg->_set_commands ( [ qq{list album "$what"} ] ); $msg->_set_cooking ( 'strip_first' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_songs_by_artist { my ($self, $msg) = @_; my $what = $msg->params->[0]; $msg->_set_commands ( [ qq{find artist "$what"} ] ); $msg->_set_cooking ( 'as_items' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_songs_by_artist_partial { my ($self, $msg) = @_; my $what = $msg->params->[0]; $msg->_set_commands ( [ qq{search artist "$what"} ] ); $msg->_set_cooking ( 'as_items' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_songs_from_album { my ($self, $msg) = @_; my $what = $msg->params->[0]; $msg->_set_commands ( [ qq{find album "$what"} ] ); $msg->_set_cooking ( 'as_items' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_songs_from_album_partial { my ($self, $msg) = @_; my $what = $msg->params->[0]; $msg->_set_commands ( [ qq{search album "$what"} ] ); $msg->_set_cooking ( 'as_items' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_songs_with_title { my ($self, $msg) = @_; my $what = $msg->params->[0]; $msg->_set_commands ( [ qq{find title "$what"} ] ); $msg->_set_cooking ( 'as_items' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_songs_with_title_partial { my ($self, $msg) = @_; my $what = $msg->params->[0]; $msg->_set_commands ( [ qq{search title "$what"} ] ); $msg->_set_cooking ( 'as_items' ); $self->mpd->_send_to_mpd( $msg ); } no Moose; __PACKAGE__->meta->make_immutable; 1; __END__ =pod =head1 NAME POE::Component::Client::MPD::Collection - module handling collection commands =head1 VERSION version 2.000 =head1 DESCRIPTION L is responsible for handling general purpose commands. They are in a dedicated module to achieve easier code maintenance. To achieve those commands, send the corresponding event to the L session you created: it will be responsible for dispatching the event where it is needed. Under no circumstance should you call directly subs or methods from this module directly. Read L's pod to learn how to deal with answers from those commands. Following is a list of collection-related events accepted by POCOCM. =head1 RETRIEVING SONGS & DIRECTORIES =head2 coll.all_items( [$path] ) Return all Ls (both songs & directories) currently known by mpd. If C<$path> is supplied (relative to mpd root), restrict the retrieval to songs and dirs in this directory. =head2 coll.all_items_simple( [$path] ) Return all Ls (both songs & directories) currently known by mpd. If C<$path> is supplied (relative to mpd root), restrict the retrieval to songs and dirs in this directory. B: the L objects will only have their attribute file filled. Any other attribute will be empty, so don't use this sub for any other thing than a quick scan! =head2 coll.items_in_dir( [$path] ) Return the items in the given C<$path>. If no C<$path> supplied, do it on mpd's root directory. Note that this sub does not work recusrively on all directories. =head1 RETRIEVING THE WHOLE COLLECTION =head2 coll.all_albums( ) Return the list of all albums (strings) currently known by mpd. =head2 coll.all_artists( ) Return the list of all artists (strings) currently known by mpd. =head2 coll.all_titles( ) Return the list of all titles (strings) currently known by mpd. =head2 coll.all_files( ) Return a mpd_result event with the list of all filenames (strings) currently known by mpd. =head1 PICKING A SONG =head2 coll.song( $path ) Return the L which correspond to C<$path>. =head2 coll.songs_with_filename_partial( $string ) Return the Ls containing C<$string> in their path. =head1 SONGS, ALBUMS & ARTISTS RELATIONS =head2 coll.albums_by_artist( $artist ) Return all albums (strings) performed by C<$artist> or where C<$artist> participated. =head2 coll.songs_by_artist( $artist ) Return all Ls performed by C<$artist>. =head2 coll.songs_by_artist_partial( $artist ) Return all Ls performed by C<$artist>. =head2 coll.songs_from_album( $album ) Return all Ls appearing in C<$album>. =head2 coll.songs_from_album_partial( $string ) Return all Ls appearing in album containing C<$string>. =head2 coll.songs_with_title( $title ) Return all Ls which title is exactly C<$title>. =head2 coll.songs_with_title_partial( $string ) Return all Ls where C<$string> is part of the title. =head1 AUTHOR Jerome Quelin =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2007 by Jerome Quelin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut POE-Component-Client-MPD-2.000/lib/POE/Component/Client/MPD/Commands.pm0000644000076400001440000002772712346054456024442 0ustar jquelinusers# # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; package POE::Component::Client::MPD::Commands; # ABSTRACT: module handling basic mpd commands $POE::Component::Client::MPD::Commands::VERSION = '2.000'; use Moose; use MooseX::Has::Sugar; use POE; use Readonly; use POE::Component::Client::MPD::Message; Readonly my $K => $poe_kernel; # -- attributes has mpd => ( ro, required, weak_ref, );# isa=>'POE::Component::Client::MPD' ); # -- MPD interaction: general commands sub _do_version { my ($self, $msg) = @_; $msg->set_status(1); $K->post( $msg->_from, 'mpd_result', $msg, $self->mpd->version ); } sub _do_password { my ($self, $msg) = @_; my $pw = $msg->params->[0]; $msg->_set_commands( [ qq{password $pw} ] ); $msg->_set_cooking ( 'raw' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_kill { my ($self, $msg) = @_; $msg->_set_commands ( [ 'kill' ] ); $msg->_set_cooking ( 'raw' ); $self->mpd->_send_to_mpd( $msg ); $K->delay_set('disconnect'=>1); } sub _do_updatedb { my ($self, $msg) = @_; my $path = $msg->params->[0] // ''; # FIXME: padre// $msg->_set_commands( [ qq{update "$path"} ] ); $msg->_set_cooking ( 'raw' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_urlhandlers { my ($self, $msg) = @_; $msg->_set_commands ( [ 'urlhandlers' ] ); $msg->_set_cooking ( 'strip_first' ); $self->mpd->_send_to_mpd( $msg ); } # -- MPD interaction: handling volume & output sub _do_volume { my ($self, $msg) = @_; my $volume; if ( $msg->params->[0] =~ /^(-|\+)(\d+)/ ) { my ($op, $delta) = ($1, $2); if ( not defined $msg->_data ) { # no status yet - fire an event $msg->_set_post( 'volume' ); $self->mpd->_dispatch('status', $msg); return; } # already got a status result my $curvol = $msg->_data->volume; $volume = $op eq '+' ? $curvol + $delta : $curvol - $delta; } else { $volume = $msg->params->[0]; } $msg->_set_commands ( [ "setvol $volume" ] ); $msg->_set_cooking ( 'raw' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_output_enable { my ($self, $msg) = @_; my $output = $msg->params->[0]; $msg->_set_commands ( [ "enableoutput $output" ] ); $msg->_set_cooking ( 'raw' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_output_disable { my ($self, $msg) = @_; my $output = $msg->params->[0]; $msg->_set_commands ( [ "disableoutput $output" ] ); $msg->_set_cooking ( 'raw' ); $self->mpd->_send_to_mpd( $msg ); } # -- MPD interaction: retrieving info from current state sub _do_stats { my ($self, $msg) = @_; $msg->_set_commands ( [ 'stats' ] ); $msg->_set_cooking ( 'as_kv' ); $msg->_set_transform( 'as_stats' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_status { my ($self, $msg) = @_; $msg->_set_commands ( [ 'status' ] ); $msg->_set_cooking ( 'as_kv' ); $msg->_set_transform( 'as_status' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_current { my ($self, $msg) = @_; $msg->_set_commands ( [ 'currentsong' ] ); $msg->_set_cooking ( 'as_items' ); $msg->_set_transform( 'as_scalar' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_song { my ($self, $msg) = @_; my $song = $msg->params->[0]; $msg->_set_commands ( [ defined $song ? "playlistinfo $song" : 'currentsong' ] ); $msg->_set_cooking ( 'as_items' ); $msg->_set_transform( 'as_scalar' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_songid { my ($self, $msg) = @_; my $song = $msg->params->[0]; $msg->_set_commands ( [ defined $song ? "playlistid $song" : 'currentsong' ] ); $msg->_set_cooking ( 'as_items' ); $msg->_set_transform( 'as_scalar' ); $self->mpd->_send_to_mpd( $msg ); } # -- MPD interaction: altering settings sub _do_repeat { my ($self, $msg) = @_; my $mode = $msg->params->[0]; if ( defined $mode ) { $mode = $mode ? 1 : 0; # force integer } else { if ( not defined $msg->_data ) { # no status yet - fire an event $msg->_set_post( 'repeat' ); $self->mpd->_dispatch('status', $msg); return; } $mode = $msg->_data->repeat ? 0 : 1; # negate current value } $msg->_set_cooking ( 'raw' ); $msg->_set_commands( [ "repeat $mode" ] ); $self->mpd->_send_to_mpd( $msg ); } sub _do_fade { my ($self, $msg) = @_; my $seconds = $msg->params->[0] // 0; # FIXME: padre// $msg->_set_commands ( [ "crossfade $seconds" ] ); $msg->_set_cooking ( 'raw' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_random { my ($self, $msg) = @_; my $mode = $msg->params->[0]; if ( defined $mode ) { $mode = $mode ? 1 : 0; # force integer } else { if ( not defined $msg->_data ) { # no status yet - fire an event $msg->_set_post( 'random' ); $self->mpd->_dispatch('status', $msg); return; } $mode = $msg->_data->random ? 0 : 1; # negate current value } $msg->_set_cooking ( 'raw' ); $msg->_set_commands( [ "random $mode" ] ); $self->mpd->_send_to_mpd( $msg ); } # -- MPD interaction: controlling playback sub _do_play { my ($self, $msg) = @_; my $number = $msg->params->[0] // ''; # FIXME: padre// $msg->_set_commands ( [ "play $number" ] ); $msg->_set_cooking ( 'raw' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_playid { my ($self, $msg) = @_; my $number = $msg->params->[0] // ''; # FIXME: padre// $msg->_set_commands ( [ "playid $number" ] ); $msg->_set_cooking ( 'raw' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_pause { my ($self, $msg) = @_; my $state = $msg->params->[0] // ''; # FIXME: padre// $msg->_set_commands ( [ "pause $state" ] ); $msg->_set_cooking ( 'raw' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_stop { my ($self, $msg) = @_; $msg->_set_commands ( [ 'stop' ] ); $msg->_set_cooking ( 'raw' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_next { my ($self, $msg) = @_; $msg->_set_commands ( [ 'next' ] ); $msg->_set_cooking ( 'raw' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_prev { my ($self, $msg) = @_; $msg->_set_commands ( [ 'previous' ] ); $msg->_set_cooking ( 'raw' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_seek { my ($self, $msg) = @_; my ($time, $song) = @{ $msg->params }[0,1]; $time ||= 0; $time = int $time; if ( not defined $song ) { if ( not defined $msg->_data ) { # no status yet - fire an event $msg->_set_post( 'seek' ); $self->mpd->_dispatch('status', $msg); return; } $song = $msg->_data->song; } $msg->_set_cooking ( 'raw' ); $msg->_set_commands( [ "seek $song $time" ] ); $self->mpd->_send_to_mpd( $msg ); } sub _do_seekid { my ($self, $msg) = @_; my ($time, $songid) = @{ $msg->params }[0,1]; $time ||= 0; $time = int $time; if ( not defined $songid ) { if ( not defined $msg->_data ) { # no status yet - fire an event $msg->_set_post( 'seekid' ); $self->mpd->_dispatch('status', $msg); return; } $songid = $msg->_data->songid; } $msg->_set_cooking ( 'raw' ); $msg->_set_commands( [ "seekid $songid $time" ] ); $self->mpd->_send_to_mpd( $msg ); } no Moose; __PACKAGE__->meta->make_immutable; 1; __END__ =pod =head1 NAME POE::Component::Client::MPD::Commands - module handling basic mpd commands =head1 VERSION version 2.000 =head1 DESCRIPTION L is responsible for handling general purpose commands. They are in a dedicated module to achieve easier code maintenance. To achieve those commands, send the corresponding event to the POCOCM session you created: it will be responsible for dispatching the event where it is needed. Under no circumstance should you call directly subs or methods from this module directly. Read POCOCM's pod to learn how to deal with answers from those commands. Following is a list of general purpose events accepted by POCOCM. =head1 CONTROLLING THE SERVER =head2 version( ) Return mpd's version number as advertised during connection. Note that mpd returns B version when connected. This protocol version can differ from the real mpd version. eg, mpd version 0.13.2 is "speaking" and thus advertising version 0.13.0. =head2 password( $password ) Sends a connection password to mpd. Used internally on connect, but can be called whenever if you're feeling like it. =head2 kill( ) Kill the mpd server, and request the pococm to be shutdown. =head2 updatedb( [$path] ) Force mpd to rescan its collection. If C<$path> (relative to MPD's music directory) is supplied, MPD will only scan it - otherwise, MPD will rescan its whole collection. =head2 urlhandlers( ) Return an array of supported URL schemes. =head1 HANDLING VOLUME & OUTPUT =head2 volume( $volume ) Sets the audio output volume percentage to absolute C<$volume>. If C<$volume> is prefixed by '+' or '-' then the volume is changed relatively by that value. =head2 output_enable( $output ) Enable the specified audio output. C<$output> is the ID of the audio output. =head2 output_disable( $output ) Disable the specified audio output. C<$output> is the ID of the audio output. =head1 RETRIEVING INFO FROM CURRENT STATE =head2 stats( ) Return an L object with the current statistics of MPD. =head2 status( ) Return an L object with the current status of MPD. =head2 current( ) Return an L representing the song currently playing. =head2 song( [$song] ) Return an L representing the song number C<$song>. If C<$song> is not supplied, returns the current song. =head2 songid( [$songid] ) Return an L representing the song id C<$songid>. If C<$songid> is not supplied, returns the current song. =head1 ALTERING MPD SETTINGS =head2 repeat( [$repeat] ) Set the repeat mode to C<$repeat> (1 or 0). If C<$repeat> is not specified then the repeat mode is toggled. =head2 fade( [$seconds] ) Enable crossfading and set the duration of crossfade between songs. If C<$seconds> is not specified or C<$seconds> is 0, then crossfading is disabled. =head2 random( [$random] ) Set the random mode to C<$random> (1 or 0). If C<$random> is not specified then the random mode is toggled. =head1 CONTROLLING PLAYBACK =head2 play( [$song] ) Begin playing playlist at song number C<$song>. If no argument supplied, resume playing. =head2 playid( [$song] ) Begin playing playlist at song ID C<$song>. If no argument supplied, resume playing. =head2 pause( [$sate] ) Pause playback. If C<$state> is 0 then the current track is unpaused, if C<$state> is 1 then the current track is paused. Note that if C<$state> is not given, pause state will be toggled. =head2 stop( ) Stop playback. =head2 next( ) Play next song in playlist. =head2 prev( ) Play previous song in playlist. =head2 seek( $time, [$song] ) Seek to C<$time> seconds in song number C<$song>. If C<$song> number is not specified then the perl module will try and seek to C<$time> in the current song. =head2 seekid( $time, [$songid] ) Seek to C<$time> seconds in song ID C<$songid>. If C<$songid> number is not specified then the perl module will try and seek to C<$time> in the current song. =head1 AUTHOR Jerome Quelin =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2007 by Jerome Quelin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut POE-Component-Client-MPD-2.000/lib/POE/Component/Client/MPD/Playlist.pm0000644000076400001440000001675012346054456024474 0ustar jquelinusers# # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; package POE::Component::Client::MPD::Playlist; # ABSTRACT: module handling playlist commands $POE::Component::Client::MPD::Playlist::VERSION = '2.000'; use Moose; use MooseX::Has::Sugar; use POE; use Readonly; use POE::Component::Client::MPD::Message; # -- attributes has mpd => ( ro, required, weak_ref, );# isa=>'POE::Component::Client::MPD' ); # -- Playlist: retrieving information sub _do_as_items { my ($self, $msg) = @_; $msg->_set_commands ( [ 'playlistinfo' ] ); $msg->_set_cooking ( 'as_items' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_items_changed_since { my ($self, $msg) = @_; my $plid = $msg->params->[0]; $msg->_set_commands ( [ "plchanges $plid" ] ); $msg->_set_cooking ( 'as_items' ); $self->mpd->_send_to_mpd( $msg ); } # -- Playlist: adding / removing songs sub _do_add { my ($self, $msg) = @_; my $args = $msg->params; my @pathes = @$args; # args of the poe event my @commands = ( # build the commands 'command_list_begin', map( qq{add "$_"}, @pathes ), 'command_list_end', ); $msg->_set_commands ( \@commands ); $msg->_set_cooking ( 'raw' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_delete { my ($self, $msg) = @_; my $args = $msg->params; my @numbers = @$args; my @commands = ( # build the commands 'command_list_begin', map( qq{delete $_}, reverse sort {$a<=>$b} @numbers ), 'command_list_end', ); $msg->_set_commands ( \@commands ); $msg->_set_cooking ( 'raw' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_deleteid { my ($self, $msg) = @_; my $args = $msg->params; my @songids = @$args; my @commands = ( # build the commands 'command_list_begin', map( qq{deleteid $_}, @songids ), 'command_list_end', ); $msg->_set_commands ( \@commands ); $msg->_set_cooking ( 'raw' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_clear { my ($self, $msg) = @_; $msg->_set_commands ( [ 'clear' ] ); $msg->_set_cooking ( 'raw' ); $self->mpd->_send_to_mpd( $msg ); } sub _do_crop { my ($self, $msg) = @_; if ( not defined $msg->_data ) { # no status yet - fire an event $msg->_set_post( 'pl.crop' ); $self->mpd->_dispatch('status', $msg); return; } # now we know what to remove my $cur = $msg->_data->song; my $len = $msg->_data->playlistlength - 1; my @commands = ( 'command_list_begin', map( { $_ != $cur ? "delete $_" : '' } reverse 0..$len ), 'command_list_end' ); $msg->_set_cooking ( 'raw' ); $msg->_set_commands ( \@commands ); $self->mpd->_send_to_mpd( $msg ); } # -- Playlist: changing playlist order sub _do_shuffle { my ($self, $msg) = @_; $msg->_set_cooking ( 'raw' ); $msg->_set_commands ( [ 'shuffle' ] ); $self->mpd->_send_to_mpd( $msg ); } sub _do_swap { my ($self, $msg) = @_; my ($from, $to) = @{ $msg->params }[0,1]; $msg->_set_cooking ( 'raw' ); $msg->_set_commands ( [ "swap $from $to" ] ); $self->mpd->_send_to_mpd( $msg ); } sub _do_swapid { my ($self, $msg) = @_; my ($from, $to) = @{ $msg->params }[0,1]; $msg->_set_cooking ( 'raw' ); $msg->_set_commands ( [ "swapid $from $to" ] ); $self->mpd->_send_to_mpd( $msg ); } sub _do_move { my ($self, $msg) = @_; my ($song, $pos) = @{ $msg->params }[0,1]; $msg->_set_cooking ( 'raw' ); $msg->_set_commands ( [ "move $song $pos" ] ); $self->mpd->_send_to_mpd( $msg ); } sub _do_moveid { my ($self, $msg) = @_; my ($songid, $pos) = @{ $msg->params }[0,1]; $msg->_set_cooking ( 'raw' ); $msg->_set_commands ( [ "moveid $songid $pos" ] ); $self->mpd->_send_to_mpd( $msg ); } # -- Playlist: managing playlists sub _do_load { my ($self, $msg) = @_; my $playlist = $msg->params->[0]; $msg->_set_cooking ( 'raw' ); $msg->_set_commands ( [ qq{load "$playlist"} ] ); $self->mpd->_send_to_mpd( $msg ); } sub _do_save { my ($self, $msg) = @_; my $playlist = $msg->params->[0]; $msg->_set_cooking ( 'raw' ); $msg->_set_commands ( [ qq{save "$playlist"} ] ); $self->mpd->_send_to_mpd( $msg ); } sub _do_rm { my ($self, $msg) = @_; my $playlist = $msg->params->[0]; $msg->_set_cooking ( 'raw' ); $msg->_set_commands ( [ qq{rm "$playlist"} ] ); $self->mpd->_send_to_mpd( $msg ); } no Moose; __PACKAGE__->meta->make_immutable; 1; __END__ =pod =head1 NAME POE::Component::Client::MPD::Playlist - module handling playlist commands =head1 VERSION version 2.000 =head1 DESCRIPTION L is responsible for handling general purpose commands. They are in a dedicated module to achieve easier code maintenance. To achieve those commands, send the corresponding event to the POCOCM session you created: it will be responsible for dispatching the event where it is needed. Under no circumstance should you call directly subs or methods from this module directly. Read L's pod to learn how to deal with answers from those commands. Following is a list of playlist-related events accepted by POCOCM. =head1 RETRIEVING INFORMATION =head2 pl.as_items( ) Return an array of Ls, one for each of the songs in the current playlist. =head2 pl.items_changed_since( $plversion ) Return a list with all the songs (as L objects) added to the playlist since playlist C<$plversion>. =head1 ADDING / REMOVING SONGS =head2 pl.add( $path, $path, ... ) Add the songs identified by C<$path> (relative to MPD's music directory) to the current playlist. =head2 pl.delete( $number, $number, ... ) Remove song C<$number> (starting from 0) from the current playlist. =head2 pl.deleteid( $songid, $songid, ... ) Remove the specified C<$songid> (as assigned by mpd when inserted in playlist) from the current playlist. =head2 pl.clear( ) Remove all the songs from the current playlist. =head2 pl.crop( ) Remove all of the songs from the current playlist *except* the current one. =head1 CHANGING PLAYLIST ORDER =head2 pl.shuffle( ) Shuffle the current playlist. =head2 pl.swap( $song1, $song2 ) Swap positions of song number C<$song1> and C<$song2> in the current playlist. =head2 pl.swapid( $songid1, $songid2 ) Swap positions of song id C<$songid1> and C<$songid2> in the current playlist. =head2 pl.move( $song, $newpos ) Move song number C<$song> to the position C<$newpos>. =head2 pl.moveid( $songid, $newpos ) Move song id C<$songid> to the position C<$newpos>. =head1 MANAGING PLAYLISTS =head2 pl.load( $playlist ) Load list of songs from specified C<$playlist> file. =head2 pl.save( $playlist ) Save the current playlist to a file called C<$playlist> in MPD's playlist directory. =head2 pl.rm( $playlist ) Delete playlist named C<$playlist> from MPD's playlist directory. =head1 AUTHOR Jerome Quelin =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2007 by Jerome Quelin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut POE-Component-Client-MPD-2.000/lib/POE/Component/Client/MPD/Message.pm0000644000076400001440000000365412346054456024256 0ustar jquelinusers# # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; package POE::Component::Client::MPD::Message; # ABSTRACT: a message from POCOCM $POE::Component::Client::MPD::Message::VERSION = '2.000'; use Moose; use MooseX::Has::Sugar; use MooseX::SemiAffordanceAccessor; use MooseX::Types::Moose qw{ ArrayRef Bool Str }; use POE::Component::Client::MPD::Types; has request => ( ro, required, isa=>'Maybe[Str]' ); has params => ( ro, required, isa=>ArrayRef ); has status => ( rw, isa=>Bool ); has _data => ( rw ); has _commands => ( rw, isa=>ArrayRef ); has _cooking => ( rw, isa=>'Cooking' ); has _transform => ( rw, isa=>'Transform' ); has _post => ( rw, isa=>'Maybe[Str]' ); has _from => ( rw, isa=>Str ); no Moose; __PACKAGE__->meta->make_immutable; 1; __END__ =pod =head1 NAME POE::Component::Client::MPD::Message - a message from POCOCM =head1 VERSION version 2.000 =head1 SYNOPSIS print $msg->data . "\n"; =head1 DESCRIPTION L is more a placeholder for a hash ref with some pre-defined keys. =head1 PUBLIC METHODS This module has a C constructor, which should only be called by one of the C's modules. The other public methods are the following accessors: =over 4 =item * request() The event sent to POCOCM. =item * params() The params of the event to POCOCM, as sent by client. =item * status() The status of the request. True for success, False in case of error. =back =head1 AUTHOR Jerome Quelin =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2007 by Jerome Quelin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut POE-Component-Client-MPD-2.000/lib/POE/Component/Client/MPD/Types.pm0000644000076400001440000000400112346054456023761 0ustar jquelinusers# # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.008; use warnings; use strict; package POE::Component::Client::MPD::Types; # ABSTRACT: types used in the distribution $POE::Component::Client::MPD::Types::VERSION = '2.000'; use Moose::Util::TypeConstraints; use Sub::Exporter -setup => { exports => [ qw{ Cooking Transform } ] }; enum Cooking => [ qw{ raw as_items as_kv strip_first } ]; enum Transform => [ qw{ as_scalar as_stats as_status } ]; 1; __END__ =pod =head1 NAME POE::Component::Client::MPD::Types - types used in the distribution =head1 VERSION version 2.000 =head1 DESCRIPTION This module implements the specific types used by the distribution, and exports them. It is using L underneath, so you can use all the shenanigans to change the export names. Current types defined and exported: =over 4 =item * C - a simple enum to know what to do about that data =over 4 =item * C - data should not be touched =item * C - data is to be transformed as L =item * C - data is to be cooked as key/values (hash) =item * C - data should have its first field stripped =back =item * C - a simple enum to know what to do about the data, B it has been cooked. Possible values are: =over 4 =item * C - return the first element instead of the full list =item * C - transform the data from key/value to C =item * C - transform the data from key/value to C =back =back =head1 AUTHOR Jerome Quelin =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2007 by Jerome Quelin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut POE-Component-Client-MPD-2.000/lib/POE/Component/Client/MPD/Test.pm0000644000076400001440000000762112346054456023607 0ustar jquelinusers# # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; package POE::Component::Client::MPD::Test; # ABSTRACT: automate pococ-mpd testing $POE::Component::Client::MPD::Test::VERSION = '2.000'; use Moose 0.92; use MooseX::Has::Sugar; use MooseX::POE; use MooseX::SemiAffordanceAccessor; use MooseX::Types::Moose qw{ ArrayRef Str }; use POE; use Readonly; Readonly my $K => $poe_kernel; has alias => ( ro, isa=>Str, default=>'tester' ); has tests => ( ro, auto_deref, required, isa => ArrayRef, traits => [ 'Array' ], handles => { peek => [ get => 0 ], pop_test => 'shift', nbtests => 'count', }, ); # -- builders & initializer # # START() # # called as poe session initialization # sub START { my $self = shift; $K->alias_set($self->alias); # refcount++ $K->yield( 'next_test' ); # launch the first test. } # -- public events event next_test => sub { my $self = shift; if ( $self->nbtests == 0 ) { # no more tests. $K->alias_remove( $self->alias ); $K->post('mpd', 'disconnect'); return; } # post next event. my $test = $self->peek; my $event = $test->[0]; my $args = $test->[1]; $K->post( 'mpd', $event, @$args ); }; event mpd_result => sub { my ($self, $msg, $results) = @_[OBJECT, ARG0, ARG1]; my $test = $self->peek; $test->[3]->($msg, $results); # check if everything went fine $K->delay_set( next_test => $test->[2] ); # call next test after some time $self->pop_test; # remove test being played }; 1; __END__ =pod =head1 NAME POE::Component::Client::MPD::Test - automate pococ-mpd testing =head1 VERSION version 2.000 =head1 SYNOPSIS POE::Component::Client::MPD->spawn( ... ); POE::Component::Client::MPD::Test->new( { tests => [ [ 'event', [ $arg1, $arg2, ... ], $sleep, \&check_results ], ... ] } ); POE::Kernel->run; =head1 DESCRIPTION This module implements a L used to schedule tests according to a plan, calling hooks used to check whether a given test was successful. To use it, you need to first spawn a L session - it's this session that will be tested. And don't forget to call L's mainloop! Once started, it will fire the first event to the L session, wait for the return message, call the check callback, and wait a bit... before starting again with the next event in the list. When all events have been sent, the session will shut down itself. =head1 ATTRIBUTES =head2 alias The session alias. Defaults to C. =head2 tests The list (array ref) of tests to run. It is required in the constructor call. Each list item is an array reference with the following sub-items: =over 4 =item * event - the event to send to the L session =item * args - event arguments (an array reference) =item * sleep - number of seconds to wait before calling next events =item * callback - a sub reference to check the results of current event. The real tests should be done in this sub. It will be called with the message received and the message payload. =back =head1 PUBLIC EVENTS ACCEPTED =head2 next_test( ) Called to schedule the next test. =head2 mpd_result( $msg ) Called when mpd talks back, with C<$msg> as a L param. =for Pod::Coverage::TrustPod START =head1 AUTHOR Jerome Quelin =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2007 by Jerome Quelin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut POE-Component-Client-MPD-2.000/lib/POE/Component/Client/MPD.pm0000644000076400001440000003527312346054456022674 0ustar jquelinusers# # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; package POE::Component::Client::MPD; # ABSTRACT: full-blown poe-aware mpd client library $POE::Component::Client::MPD::VERSION = '2.000'; use Audio::MPD::Common::Stats; use Audio::MPD::Common::Status; use Carp; use List::AllUtils qw{ any }; use Moose; use MooseX::Has::Sugar; use MooseX::POE; use MooseX::SemiAffordanceAccessor; use MooseX::Types::Moose qw{ Int Str }; use POE; use Readonly; use POE::Component::Client::MPD::Commands; use POE::Component::Client::MPD::Collection; use POE::Component::Client::MPD::Connection; use POE::Component::Client::MPD::Message; use POE::Component::Client::MPD::Playlist; Readonly my $K => $poe_kernel; # -- attributes has host => ( ro, lazy_build, isa=>Str ); has password => ( ro, lazy_build ); has port => ( ro, lazy_build, isa=>Int ); has alias => ( ro, isa=>Str, default=>'mpd' ); has status_msgs_to => ( ro, isa=>Str, predicate=>'has_peer' ); has version => ( rw, isa=>Str ); has _collection => ( ro, lazy_build, isa=>'POE::Component::Client::MPD::Collection' ); has _commands => ( ro, lazy_build, isa=>'POE::Component::Client::MPD::Commands' ); has _playlist => ( ro, lazy_build, isa=>'POE::Component::Client::MPD::Playlist' ); has _socket => ( rw, isa=>Str ); # -- builder & initializers # # my ($passwd, $host, $port) = _parse_env_var(); # # parse MPD_HOST environment variable, and extract its components. the # canonical format of MPD_HOST is passwd@host:port. # sub _parse_env_var { return (undef, undef, undef) unless defined $ENV{MPD_HOST}; return ($1, $2, $3) if $ENV{MPD_HOST} =~ /^([^@]+)\@([^:@]+):(\d+)$/; # passwd@host:port return ($1, $2, undef) if $ENV{MPD_HOST} =~ /^([^@]+)\@([^:@]+)$/; # passwd@host return (undef, $1, $2) if $ENV{MPD_HOST} =~ /^([^:@]+):(\d+)$/; # host:port return (undef, $ENV{MPD_HOST}, undef); } sub _build_host { return ( _parse_env_var() )[1] || 'localhost'; } sub _build_port { return $ENV{MPD_PORT} || ( _parse_env_var() )[2] || 6600; } sub _build_password { return $ENV{MPD_PASSWORD} || ( _parse_env_var() )[0] || ''; } sub _build__collection { POE::Component::Client::MPD::Collection->new(mpd=>$_[0]); } sub _build__commands { POE::Component::Client::MPD::Commands ->new(mpd=>$_[0]); } sub _build__playlist { POE::Component::Client::MPD::Playlist ->new(mpd=>$_[0]); } # -- public methods sub spawn { my $self = shift->new(@_); return $self->{session_id}; } # -- private methods sub _dispatch { my ($self, $event, $msg) = @_; # dispatch the event. if ( $event =~ /^pl\.(.*)$/ ) { # playlist commands my $meth = "_do_$1"; $self->_playlist->$meth($msg); } elsif ( $event =~ /^coll\.(.*)$/ ) { # collection commands my $meth = "_do_$1"; $self->_collection->$meth($msg); } else { # basic commands my $meth = "_do_$event"; $self->_commands->$meth($msg); } } # # $mpd->_send_to_mpd( $msg ); # # send $msg to mpd using pococm. # sub _send_to_mpd { my ($self, $msg) = @_; $K->post( $self->_socket => send => $msg ); } # -- public events. # # catch-all handler for pococm events that drive mpd. # event _default => sub { my ($self, $event, $params) = @_[OBJECT, ARG0, ARG1]; # check if event is handled. my @events_commands = qw{ password version kill updatedb urlhandlers volume output_enable output_disable stats status current song songid repeat fade random play playid pause stop next prev seek seekid }; my @events_playlist = qw{ pl.as_items pl.items_changed_since pl.add pl.delete pl.deleteid pl.clear pl.crop pl.shuffle pl.swap pl.swapid pl.move pl.moveid pl.load pl.save pl.rm }; my @events_collection = qw{ coll.all_items coll.all_items_simple coll.items_in_dir coll.all_albums coll.all_artists coll.all_titles coll.all_files coll.song coll.songs_with_filename_partial coll.albums_by_artist coll.songs_by_artist coll.songs_by_artist_partial coll.songs_from_album coll.songs_from_album_partial coll.songs_with_title coll.songs_with_title_partial }; my @ok_events = ( @events_commands, @events_playlist, @events_collection ); return unless any { $event eq $_ } @ok_events; # create the message that will hold my $msg = POE::Component::Client::MPD::Message->new( { _from => $_[SENDER]->ID, request => $event, # /!\ $_[STATE] eq 'default' params => $params, #_commands => #_cooking => #_transform => #_post => } ); # dispatch the event so it is handled by the correct object/method. $self->_dispatch($event, $msg); }; event disconnect => sub { my $self = shift; $K->alias_remove( $self->alias ); # refcount-- $K->post( $self->_socket, 'disconnect' ); # pococm-conn }; # -- protected events fired by pococm-conn # # event: mpd_connect_error_retriable( $reason ) # event: mpd_connect_error_fatal( $reason ) event mpd_connect_error_retriable => \&_mpd_connect_error; event mpd_connect_error_fatal => \&_mpd_connect_error; # Called when pococm-conn could not connect to a mpd server. It can be # either retriable, or fatal. In bth case, we just need to forward the # error to our peer session. # sub _mpd_connect_error { my ($self, $reason) = @_[OBJECT, ARG0]; return unless $self->has_peer; $K->post($self->status_msgs_to, 'mpd_connect_error', $reason); } # # event: mpd_connected( $version ) # # Called when pococm-conn made sure we're talking to a mpd server. # event mpd_connected => sub { my ($self, $version) = @_[OBJECT, ARG0]; $self->set_version( $version ); return unless $self->has_peer; $K->post($self->status_msgs_to, 'mpd_connected'); $K->yield(password => $self->password) if $self->password; # FIXME: send status information to peer }; # # event: mpd_disconnected() # # Called when pococm-conn got disconnected by mpd. # event mpd_disconnected => sub { my ($self, $version) = @_[OBJECT, ARG0]; return unless $self->has_peer; $K->post($self->status_msgs_to, 'mpd_disconnected'); }; # # Event: mpd_data( $msg ) # # Received when mpd finished to send back some data. # event mpd_data => sub { my ($self, $msg) = @_[OBJECT, ARG0]; # transform data if needed. if ( defined $msg->_transform ) { if ( $msg->_transform eq "as_scalar" ) { my $data = $msg->_data->[0]; $msg->_set_data($data); } elsif ( $msg->_transform eq "as_stats" ) { my %stats = @{ $msg->_data }; my $stats = Audio::MPD::Common::Stats->new( \%stats ); $msg->_set_data($stats); } elsif ( $msg->_transform eq "as_status" ) { my %status = @{ $msg->_data }; my $status = Audio::MPD::Common::Status->new( \%status ); $msg->_set_data($status); } } # check for post-callback. if ( defined $msg->_post ) { my $event = $msg->_post; # save postback. $msg->_set_post( undef ); # remove postback. $self->_dispatch($event, $msg); return; } # send result. $K->post($msg->_from, 'mpd_result', $msg, $msg->_data); }; # # Event: mpd_error( $msg, $errstr ) # # Received when mpd didn't understood a command. # event mpd_error => sub { my ($msg, $errstr) = @_[ARG0, ARG1]; $msg->set_status(0); # failure $K->post( $msg->_from, 'mpd_error', $msg, $errstr ); }; # -- private events # # Event: _start( \%params ) # # Called when the poe session gets initialized. Receive a reference # to %params, same as spawn() received. # sub START { my $self = shift; $K->alias_set( $self->alias ); # refcount++ # create the connection to mpd. we *cannot* do this with a # lazy_build, otherwise the connection will be started too late... my $socket = POE::Component::Client::MPD::Connection->spawn( { host => $self->host, port => $self->port, password => $self->password, id => $self->alias, } ); $self->_set_socket( $socket ); } no Moose; __PACKAGE__->meta->make_immutable; 1; __END__ =pod =head1 NAME POE::Component::Client::MPD - full-blown poe-aware mpd client library =head1 VERSION version 2.000 =head1 SYNOPSIS use POE qw{ Component::Client::MPD }; POE::Component::Client::MPD->spawn( { host => 'localhost', port => 6600, password => 's3kr3t', # mpd password alias => 'mpd', # poe alias status_msgs_to => 'myapp', # session to send status info to } ); # ... later on ... $_[KERNEL]->post( mpd => 'next' ); =head1 DESCRIPTION POCOCM gives a clear message-passing interface (sitting on top of POE) for talking to and controlling MPD (Music Player Daemon) servers. A connection to the MPD server is established as soon as a new POCOCM object is created. Commands are then sent to the server as messages are passed. =head1 ATTRIBUTES =head2 host The hostname where MPD is running. Defaults to environment var C, then to 'localhost'. Note that C can be of the form C (each of C or C<:port> can be omitted). =head2 port The port that MPD server listens to. Defaults to environment var C, then to parsed C (cf above), then to 6600. =head2 password The password to access special MPD functions. Defaults to environment var C, then to parsed C (cf above), then to empty string. =head2 alias A string to alias the newly created POE session. Defaults to C. =head2 status_msgs_to A session (name or id) to whom to send connection status to. Optional, although recommended. No default. When this is done, pococm will send *additional* events to the session, such as: C when pococm is connected, C when pococm is disconnected, etc. You thus need to register some handlers for those events. =head1 METHODS =head2 my $id = POE::Component::Client::MPD->spawn( \%params ); This method will create a POE session responsible for communicating with mpd. It will return the poe id of the session newly created. You can tune it by passing some arguments as a hash reference. See the attributes for allowed values. =head1 PUBLIC EVENTS ACCEPTED =head2 MPD-related events The goal of a POCOCM session is to drive a remote MPD server. This can be achieved by a lot of events. Due to their sheer number, they have been regrouped logically in modules. However, note that to use those events, you need to send them to the POCOCM session that you created with C (see above). Indeed, the logical split is only internal: you are to use the same peer. For a list of public events that update and/or query MPD, see embedded pod in: =over 4 =item * L for general commands =item * L for playlist-related commands. Those events begin with C. =item * L for collection- related commands. Those events begin with C. =back =head2 disconnect( ) Request the POCOCM to be shutdown. Leave mpd running. Generally sent when one wants to exit her program. =for Pod::Coverage::TrustPod START =head1 EVENTS FIRED A POCOCM session will fire events, either to answer an incoming event, or to inform about some changes regarding the remote MPD server. =head2 Answer events For each incoming event received by the POCOCM session, it will fire back one of the following answers: =over 4 =item * mpd_result( $msg, $answer ) Indicates a success. C<$msg> is a L object with the original request, to identify the issued command (see L pod for more information). Its C attribute is true, further confirming success. C<$answer> is what has been answered by the MPD server. Depending on the command, it can be either: =over 4 =item * C: commands C, etc. =item * an L object: command C =item * an L object: command C =item * an L object: commands C, etc. =item * an array reference: commands C, etc. =item * etc. =back Refer to the documentation of each event to know what type of answer you can expect. =item * mpd_error( $msg, $errstr ) Indicates a failure. C<$msg> is a L object with the original request, to identify the issued command (see L pod for more information). Its C attribute is false, further confirming failure. C<$errstr> is what the error message as returned been answered by the MPD server. =back =head2 Auto-generated events If you supplied the C attribute, the following events are fired to this peer by pococm: =over 4 =item * mpd_connect_error( $reason ) Called when pococm-conn could not connect to a mpd server. It can be either retriable, or fatal. Check C<$reason> for more information. =item * mpd_connected( ) Called when pococm-conn made sure we're talking to a mpd server. =item * mpd_disconnected( ) Called when pococm-conn has been disconnected from mpd server. =back =head1 SEE ALSO You can find more information on the mpd project on its homepage at L, or its wiki L. You may want to have a look at L, a non-L aware module to access MPD. You can look for information on this module at: =over 4 =item * Search CPAN L =item * See open / report bugs L =item * Mailing-list (same as L) L =item * Git repository L =item * AnnoCPAN: Annotated CPAN documentation L =item * CPAN Ratings L =back =head1 AUTHOR Jerome Quelin =head1 COPYRIGHT AND LICENSE This software is copyright (c) 2007 by Jerome Quelin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. =cut POE-Component-Client-MPD-2.000/examples/0000755000076400001440000000000012346054456017151 5ustar jquelinusersPOE-Component-Client-MPD-2.000/examples/client.pl0000755000076400001440000000145112346054456020770 0ustar jquelinusers#!/usr/bin/env perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # # use warnings; use strict; use FindBin qw{ $Bin }; use lib "$Bin/../lib"; use POE; use POE::Component::Client::MPD; POE::Component::Client::MPD->spawn( {alias => 'mpd'} ); POE::Session->create( inline_states => { _start => \&start, _stop => sub { print "bye-bye\n"; }, mpd_result => \&result, } ); POE::Kernel->run; exit; sub start { my $k = $_[KERNEL]; $k->alias_set('client'); # increment refcount $k->post( 'mpd', 'coll:all_files' ); } sub result { print "yeah!\n"; } POE-Component-Client-MPD-2.000/t/0000755000076400001440000000000012346054456015576 5ustar jquelinusersPOE-Component-Client-MPD-2.000/t/000-report-versions-tiny.t0000644000076400001440000000605612346054456022431 0ustar jquelinusersuse strict; use warnings; use Test::More 0.88; # This is a relatively nice way to avoid Test::NoWarnings breaking our # expectations by adding extra tests, without using no_plan. It also helps # avoid any other test module that feels introducing random tests, or even # test plans, is a nice idea. our $success = 0; END { $success && done_testing; } # List our own version used to generate this my $v = "\nGenerated by Dist::Zilla::Plugin::ReportVersions::Tiny v1.10\n"; eval { # no excuses! # report our Perl details my $want = '5.010'; $v .= "perl: $] (wanted $want) on $^O from $^X\n\n"; }; defined($@) and diag("$@"); # Now, our module version dependencies: sub pmver { my ($module, $wanted) = @_; $wanted = " (want $wanted)"; my $pmver; eval "require $module;"; if ($@) { if ($@ =~ m/Can't locate .* in \@INC/) { $pmver = 'module not found.'; } else { diag("${module}: $@"); $pmver = 'died during require.'; } } else { my $version; eval { $version = $module->VERSION; }; if ($@) { diag("${module}: $@"); $pmver = 'died during VERSION check.'; } elsif (defined $version) { $pmver = "$version"; } else { $pmver = ''; } } # So, we should be good, right? return sprintf('%-45s => %-10s%-15s%s', $module, $pmver, $wanted, "\n"); } eval { $v .= pmver('Audio::MPD::Common::Item','any version') }; eval { $v .= pmver('Audio::MPD::Common::Stats','any version') }; eval { $v .= pmver('Audio::MPD::Common::Status','any version') }; eval { $v .= pmver('Carp','any version') }; eval { $v .= pmver('File::Spec','any version') }; eval { $v .= pmver('IO::Handle','any version') }; eval { $v .= pmver('IPC::Open3','any version') }; eval { $v .= pmver('List::AllUtils','any version') }; eval { $v .= pmver('Module::Build','0.3601') }; eval { $v .= pmver('Moose','0.92') }; eval { $v .= pmver('Moose::Util::TypeConstraints','any version') }; eval { $v .= pmver('MooseX::Has::Sugar','any version') }; eval { $v .= pmver('MooseX::POE','any version') }; eval { $v .= pmver('MooseX::SemiAffordanceAccessor','any version') }; eval { $v .= pmver('MooseX::Types::Moose','any version') }; eval { $v .= pmver('POE','any version') }; eval { $v .= pmver('POE::Component::Client::TCP','any version') }; eval { $v .= pmver('Readonly','any version') }; eval { $v .= pmver('Sub::Exporter','any version') }; eval { $v .= pmver('Test::Corpus::Audio::MPD','1.120990') }; eval { $v .= pmver('Test::More','0.88') }; eval { $v .= pmver('strict','any version') }; eval { $v .= pmver('warnings','any version') }; # All done. $v .= <<'EOT'; Thanks for using my code. I hope it works for you. If not, please try and include this output in the bug report. That will help me reproduce the issue and solve your problem. EOT diag($v); ok(1, "we really didn't test anything, just reporting data"); $success = 1; # Work around another nasty module on CPAN. :/ no warnings 'once'; $Template::Test::NO_FLUSH = 1; exit 0; POE-Component-Client-MPD-2.000/t/release-pod-coverage.t0000644000076400001440000000116512346054456021757 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # BEGIN { unless ($ENV{RELEASE_TESTING}) { require Test::More; Test::More::plan(skip_all => 'these tests are for release candidate testing'); } } # This file was automatically generated by Dist::Zilla::Plugin::PodCoverageTests. use Test::Pod::Coverage 1.08; use Pod::Coverage::TrustPod; all_pod_coverage_ok({ coverage_class => 'Pod::Coverage::TrustPod' }); POE-Component-Client-MPD-2.000/t/release-pod-syntax.t0000644000076400001440000000105112346054456021504 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # BEGIN { unless ($ENV{RELEASE_TESTING}) { require Test::More; Test::More::plan(skip_all => 'these tests are for release candidate testing'); } } # This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests. use Test::More; use Test::Pod 1.41; all_pod_files_ok(); POE-Component-Client-MPD-2.000/t/63-coll-relations.t0000644000076400001440000001005712346054456021143 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; use POE; use POE::Component::Client::MPD; use POE::Component::Client::MPD::Test; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 38; # launch fake mpd POE::Component::Client::MPD->spawn; # launch the tests POE::Component::Client::MPD::Test->new( { tests => [ # [ 'event', [ $arg1, $arg2, ... ], $sleep, \&check_results ] # albums_by_artist [ 'coll.albums_by_artist', ['dir1-artist'], 0, \&check_albums_by_artist ], # songs_by_artist [ 'coll.songs_by_artist', ['dir1-artist'], 0, \&check_songs_by_artist ], # songs_by_artist_partial [ 'coll.songs_by_artist_partial', ['artist'], 0, \&check_songs_by_artist_partial ], # songs_from_album [ 'coll.songs_from_album', ['our album'], 0, \&check_songs_from_album ], # songs_from_album_partial [ 'coll.songs_from_album_partial', ['album'], 0, \&check_songs_from_album_partial ], # songs_with_title [ 'coll.songs_with_title', ['ok-title'], 0, \&check_songs_with_title ], # songs_with_title_partial [ 'coll.songs_with_title_partial', ['title'], 0, \&check_songs_with_title_partial ], ] } ); POE::Kernel->run; exit; #-- sub check_success { my ($msg) = @_; is($msg->status, 1, "command '" . $msg->request . "' returned an ok status"); } sub check_albums_by_artist { my ($msg, $items) = @_; check_success($msg); # mpd 0.14 returns empty strings too is(scalar @$items, 2, 'albums_by_artist() return the album'); is($items->[1], 'our album', 'albums_by_artist() return plain strings'); } sub check_songs_by_artist { my ($msg, $items) = @_; check_success($msg); is(scalar @$items, 3, 'songs_by_artist() return all the songs found' ); isa_ok($_, 'Audio::MPD::Common::Item::Song', 'songs_by_artist() return') for @$items; is($items->[0]->artist, 'dir1-artist', 'songs_by_artist() return correct objects'); } sub check_songs_by_artist_partial { my ($msg, $items) = @_; check_success($msg); is(scalar @$items, 3, 'songs_by_artist_partial() return all the songs found'); isa_ok($_, 'Audio::MPD::Common::Item::Song', 'songs_by_artist_partial() return') for @$items; like($items->[0]->artist, qr/artist/, 'songs_by_artist_partial() return correct objects'); } sub check_songs_from_album { my ($msg, $items) = @_; check_success($msg); is(scalar @$items, 3, 'songs_from_album() return all the songs found'); isa_ok($_, 'Audio::MPD::Common::Item::Song', 'songs_from_album() return') for @$items; is($items->[0]->album, 'our album', 'songs_from_album() return correct objects' ); } sub check_songs_from_album_partial { my ($msg, $items) = @_; check_success($msg); is(scalar @$items, 3, 'songs_from_album_partial() return all the songs found' ); isa_ok($_, 'Audio::MPD::Common::Item::Song', 'songs_from_album_partial() return') for @$items; like($items->[0]->album, qr/album/, 'songs_from_album_partial() return correct objects'); } sub check_songs_with_title { my ($msg, $items) = @_; check_success($msg); is(scalar @$items, 1, 'songs_with_title() return all the songs found'); isa_ok($_, 'Audio::MPD::Common::Item::Song', 'songs_with_title() return') for @$items; is($items->[0]->title, 'ok-title', 'songs_with_title() return correct objects'); } sub check_songs_with_title_partial { my ($msg, $items) = @_; check_success($msg); is(scalar @$items, 4, 'songs_with_title_partial() return all the songs found'); isa_ok($_, 'Audio::MPD::Common::Item::Song', 'songs_with_title_partial() return') for @$items; like($items->[0]->title, qr/title/, 'songs_with_title_partial() return correct objects'); } POE-Component-Client-MPD-2.000/t/44-cmds-playback.t0000644000076400001440000001600512346054456020724 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; use POE; use POE::Component::Client::MPD; use POE::Component::Client::MPD::Test; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 63; # launch fake mpd POE::Component::Client::MPD->spawn; # launch the tests my @songs = qw{ title.ogg dir1/title-artist-album.ogg dir1/title-artist.ogg dir2/album.ogg }; POE::Component::Client::MPD::Test->new( { tests => [ # [ 'event', [ $arg1, $arg2, ... ], $sleep, \&check_results ] #[ $PLAYLIST, 'pl.clear', [], 0, &check_success ], [ 'pl.add', \@songs, 0, \&check_success ], # play [ 'play', [], 0, \&check_success ], [ 'status', [], 0, \&check_play1 ], [ 'play', [2], 0, \&check_success ], [ 'status', [], 0, \&check_play2 ], # playid [ 'play', [0], 0, \&check_success ], [ 'pause', [], 0, \&check_success ], [ 'playid', [], 0, \&check_success ], [ 'status', [], 0, \&check_playid1 ], [ 'playid', [1], 0, \&check_success ], [ 'status', [], 0, \&check_playid2 ], # pause [ 'pause', [1], 0, \&check_success ], [ 'status', [], 0, \&check_pause1 ], [ 'pause', [0], 0, \&check_success ], [ 'status', [], 0, \&check_pause2 ], [ 'pause', [], 0, \&check_success ], [ 'status', [], 0, \&check_pause3 ], [ 'pause', [], 0, \&check_success ], [ 'status', [], 0, \&check_pause4 ], # stop [ 'stop', [], 0, \&check_success ], [ 'status', [], 0, \&check_stop ], # prev / next [ 'play', [1], 0, \&check_success ], [ 'pause', [], 0, \&check_success ], [ 'next', [], 0, \&check_success ], [ 'status', [], 0, \&check_prev ], [ 'prev', [], 0, \&check_success ], [ 'status', [], 0, \&check_next ], # seek [ 'seek', [1,2], 0, \&check_success ], [ 'pause', [1], 1, \&check_success ], [ 'status', [], 0, \&check_seek1 ], [ 'seek', [], 0, \&check_success ], [ 'pause', [1], 1, \&check_success ], [ 'status', [], 0, \&check_seek2 ], [ 'seek', [1], 0, \&check_success ], [ 'pause', [1], 1, \&check_success ], [ 'status', [], 0, \&check_seek3 ], # seekid [ 'seekid', [1,1], 0, \&check_success ], [ 'status', [], 0, \&check_seekid1 ], [ 'seekid', [], 0, \&check_success ], [ 'pause', [1], 1, \&check_success ], [ 'status', [], 0, \&check_seekid2 ], [ 'seekid', [1], 0, \&check_success ], [ 'pause', [1], 1, \&check_success ], [ 'status', [], 0, \&check_seekid3 ], ] } ); POE::Kernel->run; exit; #-- sub check_success { my ($msg) = @_; is($msg->status, 1, "command '" . $msg->request . "' returned an ok status"); } sub check_play1 { my ($msg, $status) = @_; check_success($msg); SKIP: { skip "detection method doesn't always work - depends on timing", 1; is($_[1]->state, 'play', 'play() starts playback'); } } sub check_play2 { my ($msg, $status) = @_; check_success($msg); SKIP: { skip "detection method doesn't always work - depends on timing", 1; is($_[1]->song, 2, 'play() can start playback at a given song'); } } sub check_playid1 { my ($msg, $status) = @_; check_success($msg); SKIP: { skip "detection method doesn't always work - depends on timing", 1; is($_[1]->state, 'play', 'playid() starts playback'); } } sub check_playid2 { my ($msg, $status) = @_; check_success($msg); SKIP: { skip "detection method doesn't always work - depends on timing", 1; is($_[1]->songid, 1, 'playid() can start playback at a given song'); } } sub check_pause1 { my ($msg, $status) = @_; check_success($msg); SKIP: { skip "detection method doesn't always work - depends on timing", 1; is($status->state, 'pause', 'pause() forces playback pause'); } } sub check_pause2 { my ($msg, $status) = @_; check_success($msg); SKIP: { skip "detection method doesn't always work - depends on timing", 1; is($status->state, 'play', 'pause() forces playback resume'); } } sub check_pause3 { my ($msg, $status) = @_; check_success($msg); SKIP: { skip "detection method doesn't always work - depends on timing", 1; is($status->state, 'pause', 'pause() toggles to pause'); } } sub check_pause4 { my ($msg, $status) = @_; check_success($msg); SKIP: { skip "detection method doesn't always work - depends on timing", 1; is($status->state, 'play', 'pause() toggles to play'); } } sub check_stop { check_success($_[0]); is($_[1]->state, 'stop', 'stop() forces full stop'); } sub check_prev { check_success($_[0]); is($_[1]->song, 2, 'next() changes track to next one'); } sub check_next { check_success($_[0]); is($_[1]->song, 1, 'prev() changes track to previous one'); } sub check_seek1 { my ($msg, $status) = @_; check_success($msg); SKIP: { skip "detection method doesn't always work - depends on timing", 2; is($status->song, 2, 'seek() can change the current track'); is($status->time->sofar_secs, 1, 'seek() seeks in the song'); } } sub check_seek2 { my ($msg, $status) = @_; check_success($msg); SKIP: { skip "detection method doesn't always work - depends on timing", 1; is($_[1]->time->sofar_secs, 0, 'seek() defaults to beginning of song'); } } sub check_seek3 { my ($msg, $status) = @_; check_success($msg); SKIP: { skip "detection method doesn't always work - depends on timing", 1; is($_[1]->time->sofar_secs, 1, 'seek() defaults to current song '); } } sub check_seekid1 { my ($msg, $status) = @_; check_success($msg); is($status->songid, 1, 'seekid() can change the current track'); SKIP: { skip "detection method doesn't always work - depends on timing", 1; is($status->time->sofar_secs, 1, 'seekid() seeks in the song'); } } sub check_seekid2 { my ($msg, $status) = @_; check_success($msg); SKIP: { skip "detection method doesn't always work - depends on timing", 1; is($_[1]->time->sofar_secs, 0, 'seekid() defaults to beginning of song'); } } sub check_seekid3 { my ($msg, $status) = @_; check_success($msg); SKIP: { skip "detection method doesn't always work - depends on timing", 1; is($_[1]->time->sofar_secs, 1, 'seekid() defaults to current song'); } } POE-Component-Client-MPD-2.000/t/60-coll-retrieve.t0000644000076400001440000000546612346054456020775 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; use POE; use POE::Component::Client::MPD; use POE::Component::Client::MPD::Test; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 35; # launch fake mpd POE::Component::Client::MPD->spawn; # launch the tests POE::Component::Client::MPD::Test->new( { tests => [ # [ 'event', [ $arg1, $arg2, ... ], $sleep, \&check_results ] # all_items [ 'coll.all_items', [], 0, \&check_all_items1 ], [ 'coll.all_items', ['dir1'], 0, \&check_all_items2 ], # all_items_simple [ 'coll.all_items_simple', [], 0, \&check_all_items_simple1 ], [ 'coll.all_items_simple', ['dir1'], 0, \&check_all_items_simple2 ], # items_in_dir [ 'coll.items_in_dir', [], 0, \&check_items_in_dir1 ], [ 'coll.items_in_dir', ['dir1'], 0, \&check_items_in_dir2 ], ] } ); POE::Kernel->run; exit; #-- sub check_success { my ($msg) = @_; is($msg->status, 1, "command '" . $msg->request . "' returned an ok status"); } sub check_all_items1 { my ($msg, $items) = @_; check_success($msg); is(scalar @$items, 7, 'all_items() return all 6 items'); isa_ok($_, 'Audio::MPD::Common::Item', 'all_items() return') for @$items; } sub check_all_items2 { my ($msg, $items) = @_; check_success($msg); is(scalar @$items, 3, 'all_items() can be restricted to a subdir'); is($items->[0]->directory, 'dir1', 'all_items() return a subdir first'); is($items->[1]->artist, 'dir1-artist', 'all_items() can be restricted to a subdir'); } sub check_all_items_simple1 { my ($msg, $items) = @_; check_success($msg); is(scalar @$items, 7, 'all_items_simple() return all 6 items'); isa_ok($_, 'Audio::MPD::Common::Item', 'all_items_simple() return') for @$items; } sub check_all_items_simple2 { my ($msg, $items) = @_; check_success($msg); is(scalar @$items, 3, 'all_items_simple() can be restricted to a subdir'); is($items->[0]->directory, 'dir1', 'all_items_simple() return a subdir first'); is($items->[1]->artist, undef, 'all_items_simple() does not return full tags'); } sub check_items_in_dir1 { my ($msg, $items) = @_; check_success($msg); is(scalar @$items, 5, 'items_in_dir() defaults to root' ); isa_ok($_, 'Audio::MPD::Common::Item', 'items_in_dir() return') for @$items; } sub check_items_in_dir2 { my ($msg, $items) = @_; check_success($msg); is(scalar @$items, 2, 'items_in_dir() can take a param'); } POE-Component-Client-MPD-2.000/t/43-cmds-settings.t0000644000076400001440000000466612346054456021007 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; use POE; use POE::Component::Client::MPD; use POE::Component::Client::MPD::Test; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 30; # launch fake mpd POE::Component::Client::MPD->spawn; # launch the tests POE::Component::Client::MPD::Test->new( { tests => [ # [ 'event', [ $arg1, $arg2, ... ], $sleep, \&check_results ] # repeat [ 'repeat', [1], 0, \&check_success ], [ 'status', [], 0, \&check_repeat_is_on ], [ 'repeat', [0], 0, \&check_success ], [ 'status', [], 0, \&check_repeat_is_off ], [ 'repeat', [], 1, \&check_success ], [ 'status', [], 0, \&check_repeat_is_on ], [ 'repeat', [], 1, \&check_success ], [ 'status', [], 0, \&check_repeat_is_off ], # fade [ 'fade', [15], 0, \&check_success ], [ 'status', [], 0, \&check_fade_is_on ], [ 'fade', [], 0, \&check_success ], [ 'status', [], 0, \&check_fade_is_off ], # random [ 'random', [1], 0, \&check_success ], [ 'status', [], 0, \&check_random_is_on ], [ 'random', [0], 0, \&check_success ], [ 'status', [], 0, \&check_random_is_off ], [ 'random', [], 1, \&check_success ], [ 'status', [], 0, \&check_random_is_on ], [ 'random', [], 1, \&check_success ], [ 'status', [], 0, \&check_random_is_off ], ] } ); POE::Kernel->run; exit; #-- sub check_success { my ($msg) = @_; is($msg->status, 1, "command '" . $msg->request . "' returned an ok status"); } sub check_repeat_is_on { check_success($_[0]); is($_[1]->repeat, 1, 'repeat is on'); } sub check_repeat_is_off { check_success($_[0]); is($_[1]->repeat, 0, 'repeat is off'); } sub check_random_is_on { check_success($_[0]); is($_[1]->random, 1, 'random is on'); } sub check_random_is_off { check_success($_[0]); is($_[1]->random, 0, 'random is off'); } sub check_fade_is_on { check_success($_[0]); is($_[1]->xfade, 15, 'enabling fading'); } sub check_fade_is_off { check_success($_[0]); is($_[1]->xfade, 0, 'disabling fading by default'); } POE-Component-Client-MPD-2.000/t/40-cmds-general.t0000644000076400001440000000372112346054456020550 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; use POE; use POE::Component::Client::MPD; use POE::Component::Client::MPD::Test; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all=>$@ if $@ =~ s/\n+BEGIN failed--compilation aborted.*//s; plan tests => 10; # launch fake mpd POE::Component::Client::MPD->spawn; # launch the tests POE::Component::Client::MPD::Test->new( { tests => [ # [ 'event', [ $arg1, $arg2, ... ], $sleep, \&check_results ] # updatedb [ 'updatedb', [], 1, \&check_success ], [ 'stats', [], 0, \&check_update ], [ 'updatedb', ['dir1'], 0, \&check_success ], [ 'stats', [], 0, \&check_update ], # version # needs to be *after* updatedb, so version messages can be treated # by socket. [ 'version', [], 0, \&check_version ], # urlhandlers [ 'urlhandlers', [], 0, \&check_urlhandlers ], ] } ); POE::Kernel->run; exit; #-- sub check_success { my ($msg) = @_; is($msg->status, 1, "command '" . $msg->request . "' returned an ok status"); } sub check_update { my ($msg, $stats) = @_; check_success($msg); isnt( $stats->db_update, 0, 'database has been updated' ); } sub check_urlhandlers { my ($msg, $handlers) = @_; check_success($msg); ok( scalar @$handlers >= 1, 'at least one url handler supported' ); } sub check_version { my ($msg, $vers) = @_; SKIP: { my $output = qx{echo | nc -w1 localhost 6600 2>/dev/null}; skip 'need netcat installed', 2 unless $output =~ /^OK .* ([\d.]+)\n/; check_success($msg); is($vers, $1, 'mpd version grabbed during connection is correct'); } } POE-Component-Client-MPD-2.000/t/21-conn-non_mpd.t0000644000076400001440000000236512346054456020576 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; # -- test session { package My::Session; use MooseX::POE; use Readonly; use Test::More; Readonly my $ALIAS => 'tester'; Readonly my $K => $poe_kernel; sub START { $K->alias_set( $ALIAS ); } # refcount++ event mpd_connect_error_fatal => sub { my $arg = $_[ARG0]; like($arg, qr/^Not a mpd server - welcome string was:/, 'wrong server'); $K->alias_remove( $ALIAS ); # refcount-- $K->post( _mpd_conn => 'disconnect' ); }; no Moose; __PACKAGE__->meta->make_immutable; 1; } # -- main test use POE; use POE::Component::Client::MPD::Connection; use Test::More; my $sendmail_running = grep { /:25\s.*LISTEN/ } qx{ netstat -an }; plan skip_all => 'need some sendmail server running' unless $sendmail_running; plan tests => 1; My::Session->new; POE::Component::Client::MPD::Connection->spawn( { host => 'localhost', port => 25, id => 'tester', } ); POE::Kernel->run; exit; POE-Component-Client-MPD-2.000/t/23-conn-dialog.t0000644000076400001440000001053212346054456020400 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; # -- test session { package My::Session; use MooseX::Has::Sugar; use MooseX::POE; use MooseX::Types::Moose qw{ ArrayRef }; use POE::Component::Client::MPD::Message; use Readonly; use Test::More; Readonly my $ALIAS => 'tester'; Readonly my $K => $poe_kernel; has tests => ( ro, auto_deref, required, isa => ArrayRef, traits => ['Array'], handles => { peek => [ get => 0 ], pop_test => 'shift', nbtests => 'count', }, ); # -- initializers # event: _start() # called when the poe session has started. sub START { $K->alias_set( $ALIAS ); # refcount++ $K->delay( _next_test => 1 ); # launch the first test } # -- public events # event: _mpd_data ( $msg ) # event: _mpd_error( $msg ) # called when mpd talks back, with $msg as a pococm-message param. sub _mpd_result { my ($self, $state, $arg0, $arg1) = @_[OBJECT, STATE, ARG0, ARG1]; my $test = $self->pop_test; # remove test being played my $event = $test->[2]; is($state, $event, "got a $event event"); $test->[3]->($arg0, $arg1); # check if everything went fine $K->yield( '_next_test' ); # call next test } event mpd_data => \&_mpd_result; event mpd_error => \&_mpd_result; # -- private events # event: _next_test() # called to schedule the next test. event _next_test => sub { my $self = shift; if ( $self->nbtests == 0 ) { # no more tests. $K->alias_remove($ALIAS); $K->post( _mpd_conn => 'disconnect' ); return; } # post next event. my $msg = POE::Component::Client::MPD::Message->new({ request => 'foo', params=>[], }); my $test = $self->peek; $msg->_set_commands( [ $test->[0] ] ); $msg->_set_cooking ( $test->[1] ); $K->post( _mpd_conn => 'send', $msg ); }; no Moose; __PACKAGE__->meta->make_immutable; 1; } # -- main tester package main; use POE::Component::Client::MPD::Message; use POE::Component::Client::MPD::Connection; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+BEGIN failed--compilation aborted.*//s; plan tests => 34; # tests to be run My::Session->new( { tests => [ [ 'bad command', 'raw', 'mpd_error', \&_check_bad_command ], [ 'password fail', 'raw', 'mpd_error', \&_check_bad_password ], [ 'password foobar', 'raw', 'mpd_data', \&_check_good_password ], [ 'status', 'raw', 'mpd_data', \&_check_data_raw ], [ 'lsinfo', 'as_items', 'mpd_data', \&_check_data_as_items ], [ 'stats', 'strip_first', 'mpd_data', \&_check_data_strip_first ], [ 'stats', 'as_kv', 'mpd_data', \&_check_data_as_kv ], ] } ); POE::Component::Client::MPD::Connection->spawn( { host => 'localhost', port => 6600, id => 'tester', } ); POE::Kernel->run; exit; #-- # private subs sub _check_bad_command { like($_[1], qr/unknown command "bad"/, 'unknown command'); } sub _check_bad_password { like($_[1], qr/incorrect password/, 'bad password'); } sub _check_good_password { is($_[1], undef, 'no error message'); } sub _check_data_as_items { is($_[1], undef, 'no error message'); isa_ok($_, 'Audio::MPD::Common::Item', '$AS_ITEMS returns') for @{ $_[0]->_data }; } sub _check_data_as_kv { is($_[1], undef, 'no error message'); my %h = @{ $_[0]->_data }; unlike( $h{$_}, qr/\D/, '$AS_KV cooks as a hash' ) for keys %h; # stats return numerical data as second field. } sub _check_data_raw { is($_[1], undef, 'no error message'); isnt(scalar @{ $_[0]->_data }, 0, 'commands return stuff' ); } sub _check_data_strip_first { is($_[1], undef, 'no error message'); unlike( $_, qr/\D/, '$STRIP_FIRST return only 2nd field' ) for @{ $_[0]->_data }; # stats return numerical data as second field. } POE-Component-Client-MPD-2.000/t/41-cmds-output.t0000644000076400001440000000534412346054456020477 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; use POE; use POE::Component::Client::MPD; use POE::Component::Client::MPD::Test; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all=>$@ if $@ =~ s/\n+BEGIN failed--compilation aborted.*//s; plan tests => 20; # launch fake mpd POE::Component::Client::MPD->spawn; # launch the tests my @songs = qw{ title.ogg dir1/title-artist-album.ogg dir1/title-artist.ogg }; POE::Component::Client::MPD::Test->new( { tests => [ # [ 'event', [ $arg1, $arg2, ... ], $sleep, \&check_results ] # volume [ 'volume', [10], 0, \&check_success ], # init to sthg we know [ 'volume', [4], 0, \&check_success ], [ 'status', [], 0, \&check_volume_absolute ], [ 'volume', ['+5'], 1, \&check_success ], [ 'status', [], 0, \&check_volume_relative_pos ], [ 'volume', ['-4'], 1, \&check_success ], [ 'status', [], 0, \&check_volume_relative_neg ], # output_disable. [ 'pl.add', \@songs, 0, \&check_success ], [ 'play', [], 0, \&check_success ], [ 'output_disable', [0], 1, \&check_success ], [ 'status', [], 0, \&check_output_disable ], # enable_output. [ 'output_enable', [0], 1, \&check_success ], [ 'play', [], 0, \&check_success ], [ 'pause', [], 0, \&check_success ], [ 'status', [], 0, \&check_output_enable ], ] } ); POE::Kernel->run; exit; #-- sub check_success { my ($msg) = @_; is($msg->status, 1, "command '" . $msg->request . "' returned an ok status"); } sub check_volume_absolute { my ($msg, $status) = @_; check_success($msg); is($status->volume, 4, 'setting volume'); } sub check_volume_relative_pos { my ($msg, $status) = @_; check_success($msg); is($status->volume, 9, 'increasing volume'); } sub check_volume_relative_neg { my ($msg, $status) = @_; check_success($msg); is($status->volume, 5, 'decreasing volume'); } sub check_output_disable { my ($msg, $status) = @_; check_success($msg); SKIP: { skip "detection method doesn't always work - depends on timing", 1; like($status->error, qr/^problems/, 'disabling output' ); } } sub check_output_enable { my ($msg, $status) = @_; check_success($msg); is($status->error, undef, 'enabling output' ); } POE-Component-Client-MPD-2.000/t/20-conn-failed.t0000644000076400001440000000326412346054456020366 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; my $max_retries = 3; # -- test session { package My::Session; use MooseX::Has::Sugar; use MooseX::POE; use MooseX::Types::Moose qw{ Int }; use Readonly; use Test::More; Readonly my $ALIAS => 'tester'; Readonly my $K => $poe_kernel; has count => ( rw, default=>0, isa=>Int ); sub START { $K->alias_set( $ALIAS ); } # refcount++ event mpd_connect_error_retriable => sub { my ($self, $errstr) = @_[OBJECT, ARG0]; like($errstr, qr/^connect: \(\d+\) /, 'retriable error trapped'); $self->count( $self->count + 1 ); }; event mpd_connect_error_fatal => sub { my ($self, $errstr) = @_[OBJECT, ARG0]; # checks is($self->count, $max_retries-1, 'retriable errors are tried again $max_retries times'); like($errstr, qr/^Too many failed attempts!/, 'too many errors lead to fatal error'); # cleanup $K->post( _mpd_conn => 'disconnect' ); $K->alias_remove( $ALIAS ); # refcount-- }; no Moose; __PACKAGE__->meta->make_immutable; 1; } # -- main test use POE; use POE::Component::Client::MPD::Connection; use Test::More tests => 4; My::Session->new; POE::Component::Client::MPD::Connection->spawn( { host => 'localhost', port => 16600, id => 'tester', retry_wait => 0, max_retries => $max_retries, } ); POE::Kernel->run; exit; POE-Component-Client-MPD-2.000/t/61-coll-whole.t0000644000076400001440000000420412346054456020254 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; use List::AllUtils qw{ any }; use POE; use POE::Component::Client::MPD; use POE::Component::Client::MPD::Test; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 12; # launch fake mpd POE::Component::Client::MPD->spawn; # launch the tests POE::Component::Client::MPD::Test->new( { tests => [ # [ 'event', [ $arg1, $arg2, ... ], $sleep, \&check_results ] # all_albums [ 'coll.all_albums', [], 0, \&check_all_albums ], # all_artists [ 'coll.all_artists', [], 0, \&check_all_artists ], # all_titles [ 'coll.all_titles', [], 0, \&check_all_titles ], # all_files [ 'coll.all_files', [], 0, \&check_all_files ], ] } ); POE::Kernel->run; exit; #-- sub check_success { my ($msg) = @_; is($msg->status, 1, "command '" . $msg->request . "' returned an ok status"); } sub check_all_albums { my ($msg, $items) = @_; check_success($msg); # mpd 0.14 returns empty strings too is(scalar @$items, 2, 'all_albums() return the albums'); is($items->[1], 'our album', 'all_albums() return strings'); } sub check_all_artists { my ($msg, $items) = @_; check_success($msg); # mpd 0.14 returns empty strings too is(scalar @$items, 2, 'all_artists() return the artists'); ok( any { $_ eq 'dir1-artist' } @$items, 'all_artists() return strings'); } sub check_all_titles { my ($msg, $items) = @_; check_success($msg); # mpd 0.14 returns empty strings too is(scalar @$items, 4, 'all_titles() return the titles'); ok( any { /-title$/ } @$items, 'all_titles() return strings'); } sub check_all_files { my ($msg, $items) = @_; check_success($msg); is(scalar @$items, 5, 'all_files() return the pathes'); like($items->[0], qr/\.ogg$/, 'all_files() return strings'); } POE-Component-Client-MPD-2.000/t/40-cmds-kill.t0000644000076400001440000000236612346054456020072 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; # -- test session { package My::Session; use MooseX::POE; use Test::More; sub START { POE::Kernel->alias_set( 'tester' ); # refcount++ POE::Kernel->delay_set( kill => 0.5 ); # FIXME: use connected event to start tests in pococm-test } event check => sub { my @procs = grep { /\smpd\s/ } grep { !/grep/ } qx{ ps -ef }; is( scalar @procs, 0, 'kill shuts down mpd' ); }; event kill => sub { POE::Kernel->delay_set( check => 1 ); POE::Kernel->post( mpd => 'kill' ); POE::Kernel->alias_remove( 'tester' ); # refcount-- }; no Moose; __PACKAGE__->meta->make_immutable; 1; } # -- main test package main; use POE; use POE::Component::Client::MPD; use Test::More; eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+BEGIN failed--compilation aborted.*//s; plan tests => 1; POE::Component::Client::MPD->spawn; My::Session->new; POE::Kernel->run; exit; POE-Component-Client-MPD-2.000/t/42-cmds-info.t0000644000076400001440000000574712346054456020102 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; use POE; use POE::Component::Client::MPD; use POE::Component::Client::MPD::Test; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 29; # launch fake mpd POE::Component::Client::MPD->spawn; # launch the tests my @songs = qw{ title.ogg dir1/title-artist-album.ogg dir1/title-artist.ogg }; POE::Component::Client::MPD::Test->new( { tests => [ # [ 'event', [ $arg1, $arg2, ... ], $sleep, \&check_results ] # stats [ 'updatedb', [], 0, \&check_success ], [ 'pl.add', \@songs, 0, \&check_success ], [ 'stats', [], 0, \&check_stats ], # status [ 'play', [], 0, \&check_success ], [ 'pause', [], 0, \&check_success ], [ 'status', [], 0, \&check_status ], # current [ 'current', [], 0, \&check_current ], # song [ 'song', [1], 0, \&check_song ], [ 'song', [], 0, \&check_song_current ], # songid (use the same checkers as song) [ 'songid', [2], 0, \&check_song ], [ 'songid', [], 0, \&check_song_current ], ] } ); POE::Kernel->run; exit; #-- sub check_success { my ($msg) = @_; is($msg->status, 1, "command '" . $msg->request . "' returned an ok status"); } sub check_stats { my ($msg, $stats) = @_; check_success($msg); isa_ok($stats, 'Audio::MPD::Common::Stats', 'stats() return'); is($stats->artists, 1, 'one artist in the database'); is($stats->albums, 1, 'one album in the database'); is($stats->songs, 5, '5 songs in the database'); is($stats->playtime, 0, 'already played 0 seconds'); is($stats->db_playtime, 10, '10 seconds worth of music in the db'); isnt($stats->uptime, undef, 'uptime is defined'); isnt($stats->db_update, 0, 'database has been updated'); } sub check_status { my ($msg, $status) = @_; check_success($msg); isa_ok( $status, 'Audio::MPD::Common::Status', 'status() return'); } sub check_current { my ($msg, $song) = @_; check_success($msg); isa_ok($song, 'Audio::MPD::Common::Item::Song', 'current() return'); } sub check_song { my ($msg, $song) = @_; check_success($msg); isa_ok($song, 'Audio::MPD::Common::Item::Song', 'song(id) return' ); is($song->file, 'dir1/title-artist-album.ogg', 'song(id) returns the wanted song'); } sub check_song_current { my ($msg, $song) = @_; check_success($msg); isa_ok($song, 'Audio::MPD::Common::Item::Song', 'song(id) return' ); is($song->file, 'title.ogg', 'song(id) defaults to current song' ); } POE-Component-Client-MPD-2.000/t/62-coll-pick.t0000644000076400001440000000324212346054456020066 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; use POE; use POE::Component::Client::MPD; use POE::Component::Client::MPD::Test; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 9; # launch fake mpd POE::Component::Client::MPD->spawn; # launch the tests my $path = 'dir1/title-artist-album.ogg'; POE::Component::Client::MPD::Test->new( { tests => [ # [ 'event', [ $arg1, $arg2, ... ], $sleep, \&check_results ] # song [ 'coll.song', [$path], 0, \&check_song ], # songs_with_filename_partial [ 'coll.songs_with_filename_partial', ['album'], 0, \&check_song_partial ], ] } ); POE::Kernel->run; exit; #-- sub check_success { my ($msg) = @_; is($msg->status, 1, "command '" . $msg->request . "' returned an ok status"); } sub check_song { my ($msg, $song) = @_; check_success($msg); isa_ok($song, 'Audio::MPD::Common::Item::Song', 'song() return'); is($song->file, $path, 'song() return the correct song'); is($song->title, 'foo-title', 'song() return a full AMCI::Song'); } sub check_song_partial { my ($msg, $items) = @_; check_success($msg); isa_ok($_, 'Audio::MPD::Common::Item::Song', 'songs_with_filename_partial() return') for @$items; like($items->[0]->file, qr/album/, 'songs_with_filename_partial() return the correct song'); } POE-Component-Client-MPD-2.000/t/51-pl-add_rm.t0000644000076400001440000000555112346054456020053 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; use POE; use POE::Component::Client::MPD; use POE::Component::Client::MPD::Test; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 23; # launch fake mpd POE::Component::Client::MPD->spawn; # launch the tests my @songs = qw{ title.ogg dir1/title-artist-album.ogg dir1/title-artist.ogg dir2/album.ogg }; POE::Component::Client::MPD::Test->new( { tests => [ # [ 'event', [ $arg1, $arg2, ... ], $sleep, \&check_results ] # delete / deleteid # should come first to be sure songid #0 is really here. [ 'pl.clear', [], 0, \&check_success ], [ 'pl.add', \@songs, 0, \&check_success ], [ 'status', [], 0, \&get_nb ], [ 'pl.delete', [1,2], 0, \&check_success ], [ 'status', [], 0, \&check_del ], [ 'status', [], 0, \&get_nb ], [ 'pl.deleteid', [1], 0, \&check_success ], [ 'status', [], 0, \&check_delid ], # add [ 'pl.clear', [], 0, \&check_success ], [ 'status', [], 0, \&get_nb ], [ 'pl.add', [ 'title.ogg' ], 0, \&check_success ], [ 'pl.add', \@songs, 0, \&check_success ], [ 'status', [], 0, \&check_add ], # clear [ 'pl.add', \@songs, 0, \&check_success ], [ 'pl.clear', [], 0, \&check_success ], [ 'status', [], 0, \&check_clear ], # crop [ 'pl.add', \@songs, 0, \&check_success ], [ 'play', [1], 0, \&check_success ], # to set song [ 'stop', [], 0, \&check_success ], # test hangs - dunno why #[ 'pl.crop', [], 1, \&check_success ], #[ 'status', [], 0, \&check_crop ], ] } ); POE::Kernel->run; exit; #-- my $nb; sub check_success { my ($msg) = @_; is($msg->status, 1, "command '" . $msg->request . "' returned an ok status"); } sub get_nb { check_success($_[0]); $nb = $_[1]->playlistlength } sub check_add { check_success($_[0]); is($_[1]->playlistlength, $nb+5, 'add() songs'); } sub check_del { check_success($_[0]); is($_[1]->playlistlength, $nb-2, 'delete() songs'); } sub check_delid { check_success($_[0]); is($_[1]->playlistlength, $nb-1, 'deleteid() songs'); } sub check_clear { check_success($_[0]); is($_[1]->playlistlength, 0, 'clear() leaves 0 song'); } sub check_crop { check_success($_[0]); is($_[1]->playlistlength, 1, 'crop() leaves only 1 song'); } POE-Component-Client-MPD-2.000/t/53-pl-manage.t0000644000076400001440000000347612346054456020063 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; use POE; use POE::Component::Client::MPD; use POE::Component::Client::MPD::Test; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 11; # launch fake mpd POE::Component::Client::MPD->spawn; # launch the tests POE::Component::Client::MPD::Test->new( { tests => [ # [ 'event', [ $arg1, $arg2, ... ], $sleep, \&check_results ] # load [ 'pl.clear', [], 0, \&check_success ], [ 'pl.load', ['test'], 0, \&check_success ], [ 'pl.as_items', [], 0, \&check_load ], # save [ 'pl.save', ['test-jq'], 0, \&check_success ], [ 'status', [], 0, \&check_save ], # rm [ 'pl.rm', ['test-jq'], 0, \&check_success ], [ 'status', [], 0, \&check_rm ], ] } ); POE::Kernel->run; exit; #-- sub check_success { my ($msg) = @_; is($msg->status, 1, "command '" . $msg->request . "' returned an ok status"); } sub check_load { my ($msg, $items) = @_; check_success($msg); is(scalar @$items, 1, 'pl.load() adds songs'); is($items->[0]->title, 'ok-title', 'pl.load() adds the correct songs'); } sub check_save { my ($msg, $status) = @_; check_success($msg); my $pdir = playlist_dir(); ok(-f "$pdir/test-jq.m3u", 'pl.save() creates a playlist'); } sub check_rm { my ($msg, $status) = @_; check_success($msg); my $pdir = playlist_dir(); ok(! -f "$pdir/test-jq.m3u", 'rm() removes a playlist'); } POE-Component-Client-MPD-2.000/t/52-pl-change.t0000644000076400001440000000451312346054456020050 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; use POE; use POE::Component::Client::MPD; use POE::Component::Client::MPD::Test; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 20; # launch fake mpd POE::Component::Client::MPD->spawn; # launch the tests my @songs = qw{ title.ogg dir1/title-artist-album.ogg dir1/title-artist.ogg dir2/album.ogg }; POE::Component::Client::MPD::Test->new( { tests => [ # [ 'event', [ $arg1, $arg2, ... ], $sleep, \&check_results ] # pl.swapid # test should come first to know the song id [ 'pl.clear', [], 0, \&check_success ], [ 'pl.add', \@songs, 0, \&check_success ], [ 'pl.swapid', [1,3], 0, \&check_success ], [ 'pl.as_items', [], 0, \&check_2ndpos ], [ 'pl.swapid', [1,3], 0, \&check_success ], # pl.moveid # test should come second to know the song id [ 'pl.moveid', [1,2], 0, \&check_success ], [ 'pl.as_items', [], 0, \&check_2ndpos ], [ 'pl.moveid', [1,0], 0, \&check_success ], # pl.swap [ 'pl.swap', [0,2], 0, \&check_success ], [ 'pl.as_items', [], 0, \&check_2ndpos ], [ 'pl.swap', [0,2], 0, \&check_success ], # pl.move [ 'pl.move', [0,2], 0, \&check_success ], [ 'pl.as_items', [], 0, \&check_2ndpos ], # pl.shuffle [ 'status', [], 0, \&get_plvers ], [ 'pl.shuffle', [], 0, \&check_success ], [ 'status', [], 0, \&check_shuffle ], ] } ); POE::Kernel->run; exit; #-- my $plvers; sub get_plvers { $plvers=$_[1]->playlist; } sub check_success { my ($msg) = @_; is($msg->status, 1, "command '" . $msg->request . "' returned an ok status"); } sub check_shuffle { my ($msg, $status) = @_; check_success($msg); is($status->playlist, $plvers+1, 'shuffle() changes playlist version'); } sub check_2ndpos { my ($msg, $items) = @_; check_success($msg); is($items->[2]->title, 'ok-title', 'swap[id()] / swap[id()] changes songs'); } POE-Component-Client-MPD-2.000/t/00-compile.t0000644000076400001440000000241512346054456017632 0ustar jquelinusersuse 5.006; use strict; use warnings; # this test was generated with Dist::Zilla::Plugin::Test::Compile 2.042 use Test::More tests => 8 + ($ENV{AUTHOR_TESTING} ? 1 : 0); my @module_files = ( 'POE/Component/Client/MPD.pm', 'POE/Component/Client/MPD/Collection.pm', 'POE/Component/Client/MPD/Commands.pm', 'POE/Component/Client/MPD/Connection.pm', 'POE/Component/Client/MPD/Message.pm', 'POE/Component/Client/MPD/Playlist.pm', 'POE/Component/Client/MPD/Test.pm', 'POE/Component/Client/MPD/Types.pm' ); # no fake home requested my $inc_switch = -d 'blib' ? '-Mblib' : '-Ilib'; use File::Spec; use IPC::Open3; use IO::Handle; open my $stdin, '<', File::Spec->devnull or die "can't open devnull: $!"; my @warnings; for my $lib (@module_files) { # see L my $stderr = IO::Handle->new; my $pid = open3($stdin, '>&STDERR', $stderr, $^X, $inc_switch, '-e', "require q[$lib]"); binmode $stderr, ':crlf' if $^O eq 'MSWin32'; my @_warnings = <$stderr>; waitpid($pid, 0); is($?, 0, "$lib loaded ok"); if (@_warnings) { warn @_warnings; push @warnings, @_warnings; } } is(scalar(@warnings), 0, 'no warnings found') if $ENV{AUTHOR_TESTING}; POE-Component-Client-MPD-2.000/t/50-pl-info.t0000644000076400001440000000337212346054456017556 0ustar jquelinusers#!perl # # This file is part of POE-Component-Client-MPD # # This software is copyright (c) 2007 by Jerome Quelin. # # This is free software; you can redistribute it and/or modify it under # the same terms as the Perl 5 programming language system itself. # use 5.010; use strict; use warnings; use POE; use POE::Component::Client::MPD; use POE::Component::Client::MPD::Test; use Test::More; # are we able to test module? eval 'use Test::Corpus::Audio::MPD'; plan skip_all => $@ if $@ =~ s/\n+Compilation failed.*//s; plan tests => 14; # launch fake mpd POE::Component::Client::MPD->spawn; # launch the tests my @songs = qw{ title.ogg dir1/title-artist-album.ogg dir1/title-artist.ogg dir2/album.ogg }; POE::Component::Client::MPD::Test->new( { tests => [ # [ 'event', [ $arg1, $arg2, ... ], $sleep, \&check_results ] [ 'pl.clear', [], 0, \&check_success ], [ 'pl.add', \@songs, 0, \&check_success ], # pl.as_items [ 'pl.as_items', [], 0, \&check_as_items ], # pl.items_changed_since [ 'pl.items_changed_since', [0], 0, \&check_items_changed ], ] } ); POE::Kernel->run; exit; #-- sub check_success { my ($msg) = @_; is($msg->status, 1, "command '" . $msg->request . "' returned an ok status"); } sub check_as_items { my ($msg, $items) = @_; check_success($msg); isa_ok($_, 'Audio::MPD::Common::Item::Song', 'pl.as_items() return') for @$items; is($items->[0]->title, 'ok-title', 'first song reported first'); } sub check_items_changed { my ($msg, $items) = @_; check_success($msg); isa_ok($_, 'Audio::MPD::Common::Item::Song', 'items_changed_since() return') for @$items; is($items->[0]->title, 'ok-title', 'first song reported first'); } POE-Component-Client-MPD-2.000/AUTHOR_PLEDGE0000644000076400001440000000105712346054456017303 0ustar jquelinusers # CPAN Covenant for POE-Component-Client-MPD I, Jerome Quelin, hereby give modules@perl.org permission to grant co-maintainership to POE-Component-Client-MPD, if all the following conditions are met: (1) I haven't released the module for a year or more (2) There are outstanding issues in the module's public bug tracker (3) Email to my CPAN email address hasn't been answered after a month (4) The requester wants to make worthwhile changes that will benefit CPAN In the event of my death, then the time-limits in (1) and (3) do not apply. POE-Component-Client-MPD-2.000/weaver.ini0000644000076400001440000000265212346054456017332 0ustar jquelinusers[@CorePrep] [Name] [Version] [Region / prelude] [Generic / SYNOPSIS] [Generic / DESCRIPTION] [Generic / OVERVIEW] [Collect / ATTRIBUTES] command = attr [Collect / METHODS] command = method [Collect / EVENTS] command = event header = PUBLIC EVENTS ACCEPTED ; pococm::commands [Collect / MPD_CTRL] command = ev_mpd_ctrl header = CONTROLLING THE SERVER [Collect / MPD_OUTPUT] command = ev_mpd_output header = HANDLING VOLUME & OUTPUT [Collect / MPD_INFO] command = ev_mpd_info header = RETRIEVING INFO FROM CURRENT STATE [Collect / MPD_SETTINGS] command = ev_mpd_settings header = ALTERING MPD SETTINGS [Collect / MPD_PLAYBACK] command = ev_mpd_playback header = CONTROLLING PLAYBACK ; pococm::collection [Collect / COLL_SONG] command = ev_coll_song header = RETRIEVING SONGS & DIRECTORIES [Collect / COLL_WHOLE] command = ev_coll_whole header = RETRIEVING THE WHOLE COLLECTION [Collect / COLL_PICK] command = ev_coll_pick header = PICKING A SONG [Collect / COLL_RELATIONS] command = ev_coll_relations header = SONGS, ALBUMS & ARTISTS RELATIONS ; pococm::playlist [Collect / PLAY_INFO] command = ev_play_info header = RETRIEVING INFORMATION [Collect / PLAY_ADDRM] command = ev_play_addrm header = ADDING / REMOVING SONGS [Collect / PLAY_ORDER] command = ev_play_order header = CHANGING PLAYLIST ORDER [Collect / PLAY_MGMT] command = ev_play_mgmt header = MANAGING PLAYLISTS [Leftovers] [Region / postlude] [Authors] [Legal] POE-Component-Client-MPD-2.000/META.json0000644000076400001440000005225312346054456016763 0ustar jquelinusers{ "abstract" : "full-blown poe-aware mpd client library", "author" : [ "Jerome Quelin" ], "dynamic_config" : 0, "generated_by" : "Dist::Zilla version 5.019, CPAN::Meta::Converter version 2.141520", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "POE-Component-Client-MPD", "prereqs" : { "build" : { "requires" : { "Module::Build" : "0.3601" } }, "configure" : { "requires" : { "Module::Build" : "0.3601" } }, "develop" : { "requires" : { "Pod::Coverage::TrustPod" : "0", "Test::Pod" : "1.41", "Test::Pod::Coverage" : "1.08", "version" : "0.9901" } }, "runtime" : { "requires" : { "Audio::MPD::Common::Item" : "0", "Audio::MPD::Common::Stats" : "0", "Audio::MPD::Common::Status" : "0", "Carp" : "0", "List::AllUtils" : "0", "Moose" : "0.92", "Moose::Util::TypeConstraints" : "0", "MooseX::Has::Sugar" : "0", "MooseX::POE" : "0", "MooseX::SemiAffordanceAccessor" : "0", "MooseX::Types::Moose" : "0", "POE" : "0", "POE::Component::Client::TCP" : "0", "Readonly" : "0", "Sub::Exporter" : "0", "Test::Corpus::Audio::MPD" : "1.120990", "perl" : "5.010", "strict" : "0", "warnings" : "0" } }, "test" : { "requires" : { "File::Spec" : "0", "IO::Handle" : "0", "IPC::Open3" : "0", "Test::More" : "0.88" } } }, "provides" : { "POE::Component::Client::MPD" : { "file" : "lib/POE/Component/Client/MPD.pm", "version" : "2.000" }, "POE::Component::Client::MPD::Collection" : { "file" : "lib/POE/Component/Client/MPD/Collection.pm", "version" : "2.000" }, "POE::Component::Client::MPD::Commands" : { "file" : "lib/POE/Component/Client/MPD/Commands.pm", "version" : "2.000" }, "POE::Component::Client::MPD::Connection" : { "file" : "lib/POE/Component/Client/MPD/Connection.pm", "version" : "2.000" }, "POE::Component::Client::MPD::Message" : { "file" : "lib/POE/Component/Client/MPD/Message.pm", "version" : "2.000" }, "POE::Component::Client::MPD::Playlist" : { "file" : "lib/POE/Component/Client/MPD/Playlist.pm", "version" : "2.000" }, "POE::Component::Client::MPD::Test" : { "file" : "lib/POE/Component/Client/MPD/Test.pm", "version" : "2.000" }, "POE::Component::Client::MPD::Types" : { "file" : "lib/POE/Component/Client/MPD/Types.pm", "version" : "2.000" } }, "release_status" : "stable", "resources" : { "bugtracker" : { "mailto" : "bug-poe-component-client-mpd at rt.cpan.org", "web" : "http://rt.cpan.org/Public/Dist/Display.html?Name=POE-Component-Client-MPD" }, "homepage" : "http://search.cpan.org/dist/POE-Component-Client-MPD/", "repository" : { "type" : "git", "url" : "git://github.com/jquelin/poe-component-client-mpd.git", "web" : "https://github.com/jquelin/poe-component-client-mpd" }, "x_MailingList" : "http://groups.google.com/group/audio-mpd" }, "version" : "2.000", "x_Dist_Zilla" : { "perl" : { "version" : "5.020000" }, "plugins" : [ { "class" : "Dist::Zilla::Plugin::MetaResources", "name" : "MetaResources", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::Prereqs", "config" : { "Dist::Zilla::Plugin::Prereqs" : { "phase" : "runtime", "type" : "requires" } }, "name" : "Prereqs", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::Git::NextVersion", "config" : { "Dist::Zilla::Plugin::Git::NextVersion" : { "first_version" : "0.001", "version_by_branch" : "0", "version_regexp" : "(?^:^v(.+)$)" }, "Dist::Zilla::Role::Git::Repo" : { "repo_root" : "." } }, "name" : "@Author::JQUELIN/Git::NextVersion", "version" : "2.022" }, { "class" : "Dist::Zilla::Plugin::GatherDir", "name" : "@Author::JQUELIN/GatherDir", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::Test::Compile", "config" : { "Dist::Zilla::Plugin::Test::Compile" : { "filename" : "t/00-compile.t", "module_finder" : [ ":InstallModules" ], "script_finder" : [ ":ExecFiles" ] } }, "name" : "@Author::JQUELIN/Test::Compile", "version" : "2.042" }, { "class" : "Dist::Zilla::Plugin::PodCoverageTests", "name" : "@Author::JQUELIN/PodCoverageTests", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::PodSyntaxTests", "name" : "@Author::JQUELIN/PodSyntaxTests", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::ReportVersions::Tiny", "name" : "@Author::JQUELIN/ReportVersions::Tiny", "version" : "1.10" }, { "class" : "Dist::Zilla::Plugin::PruneCruft", "name" : "@Author::JQUELIN/PruneCruft", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::PruneFiles", "name" : "@Author::JQUELIN/PruneFiles", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::ManifestSkip", "name" : "@Author::JQUELIN/ManifestSkip", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::AutoPrereqs", "name" : "@Author::JQUELIN/AutoPrereqs", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::ExtraTests", "name" : "@Author::JQUELIN/ExtraTests", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::NextRelease", "name" : "@Author::JQUELIN/NextRelease", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::PkgVersion", "name" : "@Author::JQUELIN/PkgVersion", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::PodWeaver", "config" : { "Dist::Zilla::Plugin::PodWeaver" : { "finder" : [ ":InstallModules", ":ExecFiles" ], "plugins" : [ { "class" : "Pod::Weaver::Plugin::EnsurePod5", "name" : "@CorePrep/EnsurePod5", "version" : "4.006" }, { "class" : "Pod::Weaver::Plugin::H1Nester", "name" : "@CorePrep/H1Nester", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Name", "name" : "Name", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Version", "name" : "Version", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Region", "name" : "prelude", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Generic", "name" : "SYNOPSIS", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Generic", "name" : "DESCRIPTION", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Generic", "name" : "OVERVIEW", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "ATTRIBUTES", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "METHODS", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "EVENTS", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "MPD_CTRL", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "MPD_OUTPUT", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "MPD_INFO", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "MPD_SETTINGS", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "MPD_PLAYBACK", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "COLL_SONG", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "COLL_WHOLE", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "COLL_PICK", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "COLL_RELATIONS", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "PLAY_INFO", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "PLAY_ADDRM", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "PLAY_ORDER", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Collect", "name" : "PLAY_MGMT", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Leftovers", "name" : "Leftovers", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Region", "name" : "postlude", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Authors", "name" : "Authors", "version" : "4.006" }, { "class" : "Pod::Weaver::Section::Legal", "name" : "Legal", "version" : "4.006" } ] } }, "name" : "@Author::JQUELIN/PodWeaver", "version" : "4.005" }, { "class" : "Dist::Zilla::Plugin::Prepender", "name" : "@Author::JQUELIN/Prepender", "version" : "1.112280" }, { "class" : "Dist::Zilla::Plugin::ExecDir", "name" : "@Author::JQUELIN/ExecDir", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::ShareDir", "name" : "@Author::JQUELIN/ShareDir", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::Bugtracker", "name" : "@Author::JQUELIN/Bugtracker", "version" : "1.111080" }, { "class" : "Dist::Zilla::Plugin::Homepage", "name" : "@Author::JQUELIN/Homepage", "version" : "1.101420" }, { "class" : "Dist::Zilla::Plugin::Repository", "name" : "@Author::JQUELIN/Repository", "version" : "0.20" }, { "class" : "Dist::Zilla::Plugin::MetaProvides::Package", "config" : { "Dist::Zilla::Plugin::MetaProvides::Package" : { "finder_objects" : [ { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : "@Author::JQUELIN/MetaProvides::Package/AUTOVIV/:InstallModulesPM", "version" : "5.019" } ] }, "Dist::Zilla::Role::MetaProvider::Provider" : { "inherit_missing" : "1", "inherit_version" : "1", "meta_noindex" : "1" } }, "name" : "@Author::JQUELIN/MetaProvides::Package", "version" : "2.000001" }, { "class" : "Dist::Zilla::Plugin::MetaConfig", "name" : "@Author::JQUELIN/MetaConfig", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::HelpWanted", "name" : "@Author::JQUELIN/HelpWanted", "version" : "0.3.1" }, { "class" : "Dist::Zilla::Plugin::License", "name" : "@Author::JQUELIN/License", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::Covenant", "name" : "@Author::JQUELIN/Covenant", "version" : "0.1.0" }, { "class" : "Dist::Zilla::Plugin::MetaYAML", "name" : "@Author::JQUELIN/MetaYAML", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::MetaJSON", "name" : "@Author::JQUELIN/MetaJSON", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::ModuleBuild", "config" : { "Dist::Zilla::Role::TestRunner" : { "default_jobs" : 1 } }, "name" : "@Author::JQUELIN/ModuleBuild", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::Readme", "name" : "@Author::JQUELIN/Readme", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::ReadmeAnyFromPod", "name" : "@Author::JQUELIN/ReadmeAnyFromPod", "version" : "0.141120" }, { "class" : "Dist::Zilla::Plugin::Manifest", "name" : "@Author::JQUELIN/Manifest", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::CheckChangeLog", "name" : "@Author::JQUELIN/CheckChangeLog", "version" : "0.01" }, { "class" : "Dist::Zilla::Plugin::TestRelease", "name" : "@Author::JQUELIN/TestRelease", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::Git::Check", "config" : { "Dist::Zilla::Plugin::Git::Check" : { "untracked_files" : "die" }, "Dist::Zilla::Role::Git::DirtyFiles" : { "allow_dirty" : [ "Changes", "dist.ini", "README.mkdn" ], "allow_dirty_match" : [], "changelog" : "Changes" }, "Dist::Zilla::Role::Git::Repo" : { "repo_root" : "." } }, "name" : "@Author::JQUELIN/Git::Check", "version" : "2.022" }, { "class" : "Dist::Zilla::Plugin::Git::Commit", "config" : { "Dist::Zilla::Plugin::Git::Commit" : { "add_files_in" : [], "commit_msg" : "v%v%n%n%c", "time_zone" : "local" }, "Dist::Zilla::Role::Git::DirtyFiles" : { "allow_dirty" : [ "Changes", "dist.ini", "README.mkdn" ], "allow_dirty_match" : [], "changelog" : "Changes" }, "Dist::Zilla::Role::Git::Repo" : { "repo_root" : "." } }, "name" : "@Author::JQUELIN/Git::Commit", "version" : "2.022" }, { "class" : "Dist::Zilla::Plugin::Git::Tag", "config" : { "Dist::Zilla::Plugin::Git::Tag" : { "branch" : null, "signed" : 0, "tag" : "v2.000", "tag_format" : "v%v", "tag_message" : "v%v", "time_zone" : "local" }, "Dist::Zilla::Role::Git::Repo" : { "repo_root" : "." } }, "name" : "@Author::JQUELIN/Git::Tag", "version" : "2.022" }, { "class" : "Dist::Zilla::Plugin::Git::Push", "config" : { "Dist::Zilla::Plugin::Git::Push" : { "push_to" : [ "origin" ], "remotes_must_exist" : 1 }, "Dist::Zilla::Role::Git::Repo" : { "repo_root" : "." } }, "name" : "@Author::JQUELIN/Git::Push", "version" : "2.022" }, { "class" : "Dist::Zilla::Plugin::UploadToCPAN", "name" : "@Author::JQUELIN/UploadToCPAN", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":InstallModules", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":IncModules", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":TestFiles", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":ExecFiles", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":ShareFiles", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":MainModule", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":AllFiles", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : ":NoFiles", "version" : "5.019" }, { "class" : "Dist::Zilla::Plugin::FinderCode", "name" : "@Author::JQUELIN/MetaProvides::Package/AUTOVIV/:InstallModulesPM", "version" : "5.019" } ], "zilla" : { "class" : "Dist::Zilla::Dist::Builder", "config" : { "is_trial" : "0" }, "version" : "5.019" } }, "x_author_pledge" : { "version" : 1 } } POE-Component-Client-MPD-2.000/Build.PL0000644000076400001440000000332112346054456016626 0ustar jquelinusers # This file was automatically generated by Dist::Zilla::Plugin::ModuleBuild v5.019. use strict; use warnings; use Module::Build 0.3601; my %module_build_args = ( "build_requires" => { "Module::Build" => "0.3601" }, "configure_requires" => { "Module::Build" => "0.3601" }, "dist_abstract" => "full-blown poe-aware mpd client library", "dist_author" => [ "Jerome Quelin" ], "dist_name" => "POE-Component-Client-MPD", "dist_version" => "2.000", "license" => "perl", "module_name" => "POE::Component::Client::MPD", "recommends" => {}, "recursive_test_files" => 1, "requires" => { "Audio::MPD::Common::Item" => 0, "Audio::MPD::Common::Stats" => 0, "Audio::MPD::Common::Status" => 0, "Carp" => 0, "List::AllUtils" => 0, "Moose" => "0.92", "Moose::Util::TypeConstraints" => 0, "MooseX::Has::Sugar" => 0, "MooseX::POE" => 0, "MooseX::SemiAffordanceAccessor" => 0, "MooseX::Types::Moose" => 0, "POE" => 0, "POE::Component::Client::TCP" => 0, "Readonly" => 0, "Sub::Exporter" => 0, "Test::Corpus::Audio::MPD" => "1.120990", "perl" => "5.010", "strict" => 0, "warnings" => 0 }, "script_files" => [], "test_requires" => { "File::Spec" => 0, "IO::Handle" => 0, "IPC::Open3" => 0, "Test::More" => "0.88" } ); my %fallback_build_requires = ( "File::Spec" => 0, "IO::Handle" => 0, "IPC::Open3" => 0, "Module::Build" => "0.3601", "Test::More" => "0.88" ); unless ( eval { Module::Build->VERSION(0.4004) } ) { delete $module_build_args{test_requires}; $module_build_args{build_requires} = \%fallback_build_requires; } my $build = Module::Build->new(%module_build_args); $build->create_build_script; POE-Component-Client-MPD-2.000/MANIFEST0000644000076400001440000000163312346054456016467 0ustar jquelinusers# This file was automatically generated by Dist::Zilla::Plugin::Manifest v5.019. AUTHOR_PLEDGE Build.PL Changes LICENSE MANIFEST META.json META.yml README TODO dist.ini examples/client.pl lib/POE/Component/Client/MPD.pm lib/POE/Component/Client/MPD/Collection.pm lib/POE/Component/Client/MPD/Commands.pm lib/POE/Component/Client/MPD/Connection.pm lib/POE/Component/Client/MPD/Message.pm lib/POE/Component/Client/MPD/Playlist.pm lib/POE/Component/Client/MPD/Test.pm lib/POE/Component/Client/MPD/Types.pm t/00-compile.t t/000-report-versions-tiny.t t/20-conn-failed.t t/21-conn-non_mpd.t t/23-conn-dialog.t t/40-cmds-general.t t/40-cmds-kill.t t/41-cmds-output.t t/42-cmds-info.t t/43-cmds-settings.t t/44-cmds-playback.t t/50-pl-info.t t/51-pl-add_rm.t t/52-pl-change.t t/53-pl-manage.t t/60-coll-retrieve.t t/61-coll-whole.t t/62-coll-pick.t t/63-coll-relations.t t/release-pod-coverage.t t/release-pod-syntax.t weaver.ini POE-Component-Client-MPD-2.000/META.yml0000644000076400001440000003305612346054456016613 0ustar jquelinusers--- abstract: 'full-blown poe-aware mpd client library' author: - 'Jerome Quelin' build_requires: File::Spec: '0' IO::Handle: '0' IPC::Open3: '0' Module::Build: '0.3601' Test::More: '0.88' configure_requires: Module::Build: '0.3601' dynamic_config: 0 generated_by: 'Dist::Zilla version 5.019, CPAN::Meta::Converter version 2.141520' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: POE-Component-Client-MPD provides: POE::Component::Client::MPD: file: lib/POE/Component/Client/MPD.pm version: '2.000' POE::Component::Client::MPD::Collection: file: lib/POE/Component/Client/MPD/Collection.pm version: '2.000' POE::Component::Client::MPD::Commands: file: lib/POE/Component/Client/MPD/Commands.pm version: '2.000' POE::Component::Client::MPD::Connection: file: lib/POE/Component/Client/MPD/Connection.pm version: '2.000' POE::Component::Client::MPD::Message: file: lib/POE/Component/Client/MPD/Message.pm version: '2.000' POE::Component::Client::MPD::Playlist: file: lib/POE/Component/Client/MPD/Playlist.pm version: '2.000' POE::Component::Client::MPD::Test: file: lib/POE/Component/Client/MPD/Test.pm version: '2.000' POE::Component::Client::MPD::Types: file: lib/POE/Component/Client/MPD/Types.pm version: '2.000' requires: Audio::MPD::Common::Item: '0' Audio::MPD::Common::Stats: '0' Audio::MPD::Common::Status: '0' Carp: '0' List::AllUtils: '0' Moose: '0.92' Moose::Util::TypeConstraints: '0' MooseX::Has::Sugar: '0' MooseX::POE: '0' MooseX::SemiAffordanceAccessor: '0' MooseX::Types::Moose: '0' POE: '0' POE::Component::Client::TCP: '0' Readonly: '0' Sub::Exporter: '0' Test::Corpus::Audio::MPD: '1.120990' perl: '5.010' strict: '0' warnings: '0' resources: MailingList: http://groups.google.com/group/audio-mpd bugtracker: http://rt.cpan.org/Public/Dist/Display.html?Name=POE-Component-Client-MPD homepage: http://search.cpan.org/dist/POE-Component-Client-MPD/ repository: git://github.com/jquelin/poe-component-client-mpd.git version: '2.000' x_Dist_Zilla: perl: version: '5.020000' plugins: - class: Dist::Zilla::Plugin::MetaResources name: MetaResources version: '5.019' - class: Dist::Zilla::Plugin::Prereqs config: Dist::Zilla::Plugin::Prereqs: phase: runtime type: requires name: Prereqs version: '5.019' - class: Dist::Zilla::Plugin::Git::NextVersion config: Dist::Zilla::Plugin::Git::NextVersion: first_version: '0.001' version_by_branch: '0' version_regexp: (?^:^v(.+)$) Dist::Zilla::Role::Git::Repo: repo_root: . name: '@Author::JQUELIN/Git::NextVersion' version: '2.022' - class: Dist::Zilla::Plugin::GatherDir name: '@Author::JQUELIN/GatherDir' version: '5.019' - class: Dist::Zilla::Plugin::Test::Compile config: Dist::Zilla::Plugin::Test::Compile: filename: t/00-compile.t module_finder: - ':InstallModules' script_finder: - ':ExecFiles' name: '@Author::JQUELIN/Test::Compile' version: '2.042' - class: Dist::Zilla::Plugin::PodCoverageTests name: '@Author::JQUELIN/PodCoverageTests' version: '5.019' - class: Dist::Zilla::Plugin::PodSyntaxTests name: '@Author::JQUELIN/PodSyntaxTests' version: '5.019' - class: Dist::Zilla::Plugin::ReportVersions::Tiny name: '@Author::JQUELIN/ReportVersions::Tiny' version: '1.10' - class: Dist::Zilla::Plugin::PruneCruft name: '@Author::JQUELIN/PruneCruft' version: '5.019' - class: Dist::Zilla::Plugin::PruneFiles name: '@Author::JQUELIN/PruneFiles' version: '5.019' - class: Dist::Zilla::Plugin::ManifestSkip name: '@Author::JQUELIN/ManifestSkip' version: '5.019' - class: Dist::Zilla::Plugin::AutoPrereqs name: '@Author::JQUELIN/AutoPrereqs' version: '5.019' - class: Dist::Zilla::Plugin::ExtraTests name: '@Author::JQUELIN/ExtraTests' version: '5.019' - class: Dist::Zilla::Plugin::NextRelease name: '@Author::JQUELIN/NextRelease' version: '5.019' - class: Dist::Zilla::Plugin::PkgVersion name: '@Author::JQUELIN/PkgVersion' version: '5.019' - class: Dist::Zilla::Plugin::PodWeaver config: Dist::Zilla::Plugin::PodWeaver: finder: - ':InstallModules' - ':ExecFiles' plugins: - class: Pod::Weaver::Plugin::EnsurePod5 name: '@CorePrep/EnsurePod5' version: '4.006' - class: Pod::Weaver::Plugin::H1Nester name: '@CorePrep/H1Nester' version: '4.006' - class: Pod::Weaver::Section::Name name: Name version: '4.006' - class: Pod::Weaver::Section::Version name: Version version: '4.006' - class: Pod::Weaver::Section::Region name: prelude version: '4.006' - class: Pod::Weaver::Section::Generic name: SYNOPSIS version: '4.006' - class: Pod::Weaver::Section::Generic name: DESCRIPTION version: '4.006' - class: Pod::Weaver::Section::Generic name: OVERVIEW version: '4.006' - class: Pod::Weaver::Section::Collect name: ATTRIBUTES version: '4.006' - class: Pod::Weaver::Section::Collect name: METHODS version: '4.006' - class: Pod::Weaver::Section::Collect name: EVENTS version: '4.006' - class: Pod::Weaver::Section::Collect name: MPD_CTRL version: '4.006' - class: Pod::Weaver::Section::Collect name: MPD_OUTPUT version: '4.006' - class: Pod::Weaver::Section::Collect name: MPD_INFO version: '4.006' - class: Pod::Weaver::Section::Collect name: MPD_SETTINGS version: '4.006' - class: Pod::Weaver::Section::Collect name: MPD_PLAYBACK version: '4.006' - class: Pod::Weaver::Section::Collect name: COLL_SONG version: '4.006' - class: Pod::Weaver::Section::Collect name: COLL_WHOLE version: '4.006' - class: Pod::Weaver::Section::Collect name: COLL_PICK version: '4.006' - class: Pod::Weaver::Section::Collect name: COLL_RELATIONS version: '4.006' - class: Pod::Weaver::Section::Collect name: PLAY_INFO version: '4.006' - class: Pod::Weaver::Section::Collect name: PLAY_ADDRM version: '4.006' - class: Pod::Weaver::Section::Collect name: PLAY_ORDER version: '4.006' - class: Pod::Weaver::Section::Collect name: PLAY_MGMT version: '4.006' - class: Pod::Weaver::Section::Leftovers name: Leftovers version: '4.006' - class: Pod::Weaver::Section::Region name: postlude version: '4.006' - class: Pod::Weaver::Section::Authors name: Authors version: '4.006' - class: Pod::Weaver::Section::Legal name: Legal version: '4.006' name: '@Author::JQUELIN/PodWeaver' version: '4.005' - class: Dist::Zilla::Plugin::Prepender name: '@Author::JQUELIN/Prepender' version: '1.112280' - class: Dist::Zilla::Plugin::ExecDir name: '@Author::JQUELIN/ExecDir' version: '5.019' - class: Dist::Zilla::Plugin::ShareDir name: '@Author::JQUELIN/ShareDir' version: '5.019' - class: Dist::Zilla::Plugin::Bugtracker name: '@Author::JQUELIN/Bugtracker' version: '1.111080' - class: Dist::Zilla::Plugin::Homepage name: '@Author::JQUELIN/Homepage' version: '1.101420' - class: Dist::Zilla::Plugin::Repository name: '@Author::JQUELIN/Repository' version: '0.20' - class: Dist::Zilla::Plugin::MetaProvides::Package config: Dist::Zilla::Plugin::MetaProvides::Package: finder_objects: - class: Dist::Zilla::Plugin::FinderCode name: '@Author::JQUELIN/MetaProvides::Package/AUTOVIV/:InstallModulesPM' version: '5.019' Dist::Zilla::Role::MetaProvider::Provider: inherit_missing: '1' inherit_version: '1' meta_noindex: '1' name: '@Author::JQUELIN/MetaProvides::Package' version: '2.000001' - class: Dist::Zilla::Plugin::MetaConfig name: '@Author::JQUELIN/MetaConfig' version: '5.019' - class: Dist::Zilla::Plugin::HelpWanted name: '@Author::JQUELIN/HelpWanted' version: 0.3.1 - class: Dist::Zilla::Plugin::License name: '@Author::JQUELIN/License' version: '5.019' - class: Dist::Zilla::Plugin::Covenant name: '@Author::JQUELIN/Covenant' version: 0.1.0 - class: Dist::Zilla::Plugin::MetaYAML name: '@Author::JQUELIN/MetaYAML' version: '5.019' - class: Dist::Zilla::Plugin::MetaJSON name: '@Author::JQUELIN/MetaJSON' version: '5.019' - class: Dist::Zilla::Plugin::ModuleBuild config: Dist::Zilla::Role::TestRunner: default_jobs: 1 name: '@Author::JQUELIN/ModuleBuild' version: '5.019' - class: Dist::Zilla::Plugin::Readme name: '@Author::JQUELIN/Readme' version: '5.019' - class: Dist::Zilla::Plugin::ReadmeAnyFromPod name: '@Author::JQUELIN/ReadmeAnyFromPod' version: '0.141120' - class: Dist::Zilla::Plugin::Manifest name: '@Author::JQUELIN/Manifest' version: '5.019' - class: Dist::Zilla::Plugin::CheckChangeLog name: '@Author::JQUELIN/CheckChangeLog' version: '0.01' - class: Dist::Zilla::Plugin::TestRelease name: '@Author::JQUELIN/TestRelease' version: '5.019' - class: Dist::Zilla::Plugin::Git::Check config: Dist::Zilla::Plugin::Git::Check: untracked_files: die Dist::Zilla::Role::Git::DirtyFiles: allow_dirty: - Changes - dist.ini - README.mkdn allow_dirty_match: [] changelog: Changes Dist::Zilla::Role::Git::Repo: repo_root: . name: '@Author::JQUELIN/Git::Check' version: '2.022' - class: Dist::Zilla::Plugin::Git::Commit config: Dist::Zilla::Plugin::Git::Commit: add_files_in: [] commit_msg: v%v%n%n%c time_zone: local Dist::Zilla::Role::Git::DirtyFiles: allow_dirty: - Changes - dist.ini - README.mkdn allow_dirty_match: [] changelog: Changes Dist::Zilla::Role::Git::Repo: repo_root: . name: '@Author::JQUELIN/Git::Commit' version: '2.022' - class: Dist::Zilla::Plugin::Git::Tag config: Dist::Zilla::Plugin::Git::Tag: branch: ~ signed: 0 tag: v2.000 tag_format: v%v tag_message: v%v time_zone: local Dist::Zilla::Role::Git::Repo: repo_root: . name: '@Author::JQUELIN/Git::Tag' version: '2.022' - class: Dist::Zilla::Plugin::Git::Push config: Dist::Zilla::Plugin::Git::Push: push_to: - origin remotes_must_exist: 1 Dist::Zilla::Role::Git::Repo: repo_root: . name: '@Author::JQUELIN/Git::Push' version: '2.022' - class: Dist::Zilla::Plugin::UploadToCPAN name: '@Author::JQUELIN/UploadToCPAN' version: '5.019' - class: Dist::Zilla::Plugin::FinderCode name: ':InstallModules' version: '5.019' - class: Dist::Zilla::Plugin::FinderCode name: ':IncModules' version: '5.019' - class: Dist::Zilla::Plugin::FinderCode name: ':TestFiles' version: '5.019' - class: Dist::Zilla::Plugin::FinderCode name: ':ExecFiles' version: '5.019' - class: Dist::Zilla::Plugin::FinderCode name: ':ShareFiles' version: '5.019' - class: Dist::Zilla::Plugin::FinderCode name: ':MainModule' version: '5.019' - class: Dist::Zilla::Plugin::FinderCode name: ':AllFiles' version: '5.019' - class: Dist::Zilla::Plugin::FinderCode name: ':NoFiles' version: '5.019' - class: Dist::Zilla::Plugin::FinderCode name: '@Author::JQUELIN/MetaProvides::Package/AUTOVIV/:InstallModulesPM' version: '5.019' zilla: class: Dist::Zilla::Dist::Builder config: is_trial: '0' version: '5.019' x_author_pledge: version: 1 POE-Component-Client-MPD-2.000/dist.ini0000644000076400001440000000053312346054456017000 0ustar jquelinusersname = POE-Component-Client-MPD author = Jerome Quelin license = Perl_5 copyright_holder = Jerome Quelin copyright_year = 2007 ; -- static meta-information [MetaResources] x_MailingList = http://groups.google.com/group/audio-mpd [Prereqs] Test::Corpus::Audio::MPD = 1.120990 ; used for tests, conditional compilation [@Author::JQUELIN] POE-Component-Client-MPD-2.000/LICENSE0000644000076400001440000004366012346054456016351 0ustar jquelinusersThis software is copyright (c) 2007 by Jerome Quelin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Terms of the Perl programming language system itself a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" --- The GNU General Public License, Version 1, February 1989 --- This software is Copyright (c) 2007 by Jerome Quelin. This is free software, licensed under: The GNU General Public License, Version 1, February 1989 GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of a such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this General Public License. d) You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying the Program (or any work based on the Program) you indicate your acceptance of this license to do so, and all its terms and conditions. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. 7. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the license, you may choose any version ever published by the Free Software Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to humanity, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19xx name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! --- The Artistic License 1.0 --- This software is Copyright (c) 2007 by Jerome Quelin. This is free software, licensed under: The Artistic License 1.0 The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: - "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. - "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. - "Copyright Holder" is whoever is named in the copyright or copyrights for the package. - "You" is you, if you're thinking about copying or distributing this Package. - "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) - "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End POE-Component-Client-MPD-2.000/Changes0000644000076400001440000001415512346054456016634 0ustar jquelinusersRevision history for POE-Component-Client-MPD 2.000 2014-06-11 15:26:59+02:00 Europe/Paris - adapt to new moose (rt#90686) - fix build failures (rt#93635) 1.121670 2012-06-15 16:58:43 Europe/Paris - fix rt#76145 - multiple test failures 1.100430 2010-02-12 11:04:43 Europe/Paris - WARNING: no more makefile.pl supplied, only a build.pl - support for mpd password (alex bramley) - make pococm:conn:send() retry if not connected (alex bramley) - auto-generated event mpd_connect_error_fatal renamed to mpd_connect_error - doc update 1.093390 2009-12-05 20:21:01 Europe/Paris - fix #52457 - missing test dependency (test::corpus::audio::mpd) 1.093320 2009-11-28 10:30:47 Europe/Paris - pococm is now stable, moving to 1.yydddn version scheme - moosified pococm - warning: if no alias specified, pococm will use 'mpd' alias - using Test::Corpus::Audio::MPD for tests ** 0.9.6 Sun Nov 8 09:50:18 CET 2009 - skipping test compile 0.9.5 Mon Nov 2 17:10:07 CET 2009 - adding missing require 0.9.4 Wed Oct 14 16:58:19 2009 - mpd_disconnected now sent to listening peer (torsten schwinn) - sending disconnect event even if no auto-reconnect - migrated to dist::zilla (transparent for end user) 0.9.3 Mon Sep 28 17:28:06 2009 - reorder inheritance to work around exporter bug - wrote some doc on events fired by pococm 0.9.2 Sun Mar 22 18:26:37 CET 2009 -rt #44456 - changing test to todo (depends on mpd's compilation flags) 0.9.1 Tue Jan 6 17:31:56 CET 2009 - updated to match mpd 0.14 behaviour 0.9.0 Wed Aug 13 10:33:12 CEST 2008 - api simplification: . all events sent to same session . all events do get an answer . some status events are fired - internals simplification: . using plain subs / methods if it doesn't imply latency penality poe-wide, instead of message passing . removed old, rotting code - doc overhaul - warning: perl 5.10 needed ** 0.8.1 Mon Nov 26 12:47:19 CET 2007 - kwalitee/cpants release 0.8.0 Mon Aug 6 16:48:44 CEST 2007 - new internal design, with a hub (pococ-mpd) and a connection (pococm-conn) as well as 3 public interfaces: pococm-commands, pococm-playlist, pococm-collection - tests ported to new design - this is the beginning, some things will change ** 0.7.1 Tue Jun 5 17:58:30 CEST 2007 - merged t/40-collection.t to t/61-coll-whole.t 0.7.0 Thu May 31 16:35:25 CEST 2007 - using common classes outsourced in audio::mpd::common, namely: item*, stats, status and time. ** 0.6.3 Thu May 31 12:52:07 CEST 2007 - new events handled: coll.albums_by_artist, coll.songs_by_artist, coll.songs_by_artist_partial, coll.songs_from_album, coll.songs_from_album_partial, coll.songs_with_title, coll.songs_with_title_partial - all collection relationship events implemented (with tests) 0.6.2 Thu May 31 11:22:38 CEST 2007 - new events handled: coll.song, coll.songs_with_filename_partial - all events to pick songs implemented (with tests) 0.6.1 Thu May 31 11:02:25 CEST 2007 - new events handled: coll.all_albums, coll.all_artists, coll.all_titles - all events to retrieve the whole collection implemented (with tests) 0.6.0 Mon May 28 13:51:54 CEST 2007 - new events handled: coll.all_items, coll.all_items_simple, coll.items_in_dir - all songs & directories retrieval in collection implemented (with tests) ** 0.5.3 Mon May 28 11:14:45 CEST 2007 - new events handled: pl.load, pl.save, pl.rm - all playlist file management implemented (with tests) 0.5.2 Sun May 27 16:12:51 CEST 2007 - changing license to perl - new events handled: pl.shuffle, pl.swap, pl.swapid, pl.move, pl.moveid - all playlist changing order implemented (with tests) 0.5.1 Tue May 22 19:20:55 CEST 2007 - new events handled: pl.deleteid, pl.crop - all playlist insertion / removal implemented (with tests) 0.5.0 Tue May 22 18:16:01 CEST 2007 - new events handled: pl.as_items, pl.items_changed_since - all playlist info retrieval implemented (with tests) ** 0.4.2 Mon May 21 18:39:07 CEST 2007 - new events handled: . urlhandlers . volume . repeat, random, fade . song, songid - which means that all general commands are now handled! (except password of course) 0.4.1 Sun May 20 12:21:08 CEST 2007 - possibility to add transform to whole data instead of having to use post-callbacks - new events handled: kill, version - improved non-regression test suite 0.4.0 Sun May 13 18:19:07 CEST 2007 - possibility to use pre-events - new events handled: . updatedb, seek, seekid . pl.add, pl.delete, pl.clear ** 0.3.1 Sun May 13 14:55:42 CEST 2007 - new events handled: . current, status . play, playid, pause, stop, next, prev 0.3.0 Sun May 13 14:03:50 CEST 2007 - pococm now supports post callbacks, for post-treatments - new helper classes: pococm-time, pococm-status, pococm-stats - new event handled: stats ** 0.2.0 Sun May 13 12:30:58 CEST 2007 - new module handling general commands: pococm-commands - new events handled: . output_enable . output_disable - serious pod cleaning - improved test framework ** 0.1.2 Sat May 12 19:30:11 CEST 2007 - pococm-conn implements all cookings ($AS_ITEMS, $AS_KV) - pococm-conn now spawns an error if: . connection can't be made . remote server isn't mpd - added tests for pococm-conn - new item available: pococmi-playlist 0.1.1 Sat May 12 13:53:55 CEST 2007 - pococm-request renamed in pococm-message - messages now use dot (.) instead of colon (:) - splitted ServerInput in pococm-conn - pococm-conn implements $STRIP_FIRST cooking 0.1.0 Thu May 10 20:53:30 CEST 2007 - new helper class: pococm-request - migrated api to use it to pass data around ** 0.0.3 Thu May 10 19:11:56 CEST 2007 - added test framework taken from audio::mpd - updated this framework to be poe-aware - first functional test: coll:all_files 0.0.2 Wed May 9 18:14:12 CEST 2007 - missing prereq readonly - tests for pococm-item 0.0.1 Tue May 8 18:00:57 CEST 2007 - first version based on audio::mpd, ported to poe. - connection to mpd done by pococ-tcp. - first commands implemented: coll:all_files, pl:add, pl:delete. - test client available: bin/client.pl - almost no tests. :-( POE-Component-Client-MPD-2.000/README0000644000076400001440000000060512346054456016214 0ustar jquelinusers This archive contains the distribution POE-Component-Client-MPD, version 2.000: full-blown poe-aware mpd client library This software is copyright (c) 2007 by Jerome Quelin. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. This README file was generated by Dist::Zilla::Plugin::Readme v5.019. POE-Component-Client-MPD-2.000/TODO0000644000076400001440000000034312346054456016023 0ustar jquelinusers- keep 3 pococm-conn, one for each of pococm-gen, pococm-coll and pococm-pl. this way, long operations in pococm-coll will not forbids small & fast commands (such as status) to be sent in time... - $COLLECTION -> all_songs