2 # This program is free software; you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation; either version 2 of the License, or
5 # (at your option) any later version.
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
12 # You should have received a copy of the GNU General Public License
13 # along with this program; if not, write to the Free Software
14 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 package POE
::Component
::Client
::MPD
;
23 use List
::MoreUtils qw
[ firstidx
];
25 use POE
::Component
::Client
::MPD
::Collection
;
26 use POE
::Component
::Client
::MPD
::Commands
;
27 use POE
::Component
::Client
::MPD
::Connection
;
28 use POE
::Component
::Client
::MPD
::Message
;
29 use POE
::Component
::Client
::MPD
::Playlist
;
30 use base qw
[ Class
::Accessor
::Fast
];
31 __PACKAGE__
->mk_accessors( qw
[ _host _password _port _version
] );
34 our $VERSION = '0.4.1';
38 # my $id = spawn( \%params )
40 # This method will create a POE session responsible for communicating
41 # with mpd. It will return the poe id of the session newly created.
43 # You can tune the pococm by passing some arguments as a hash reference,
44 # where the hash keys are:
45 # - host: the hostname of the mpd server. If none given, defaults to
46 # MPD_HOST env var. If this var isn't set, defaults to localhost.
47 # - port: the port of the mpd server. If none given, defaults to
48 # MPD_PORT env var. If this var isn't set, defaults to 6600.
49 # - password: the password to sent to mpd to authenticate the client.
50 # If none given, defaults to C<MPD_PASSWORD> env var. If this var
51 # isn't set, defaults to empty string.
52 # - alias: an optional string to alias the newly created POE session.
55 my ($type, $args) = @_;
57 my $collection = POE
::Component
::Client
::MPD
::Collection
->new;
58 my $commands = POE
::Component
::Client
::MPD
::Commands
->new;
59 my $playlist = POE
::Component
::Client
::MPD
::Playlist
->new;
61 my $session = POE
::Session
->create(
65 '_start' => \
&_onpriv_start
,
66 '_send' => \
&_onpriv_send
,
68 '_mpd_data' => \
&_onprot_mpd_data
,
69 '_mpd_error' => \
&_onprot_mpd_error
,
70 '_mpd_version' => \
&_onprot_mpd_version
,
72 'disconnect' => \
&_onpub_disconnect
,
75 $commands => { # general purpose commands
76 # -- MPD interaction: general commands
77 'version' => '_onpub_version',
78 'kill' => '_onpub_kill',
79 # # 'password' => '_onpub_password',
80 'updatedb' => '_onpub_updatedb',
81 'urlhandlers' => '_onpub_urlhandlers',
82 # -- MPD interaction: handling volume & output
83 'volume' => '_onpub_volume',
84 '_volume_status' => '_onpriv_volume_status',
85 'output_enable' => '_onpub_output_enable',
86 'output_disable' => '_onpub_output_disable',
87 # -- MPD interaction: retrieving info from current state
88 'stats' => '_onpub_stats',
89 'status' => '_onpub_status',
90 'current' => '_onpub_current',
91 'song' => '_onpub_song',
92 'songid' => '_onpub_songid',
93 # -- MPD interaction: altering settings
94 'repeat' => '_onpub_repeat',
95 '_repeat_status' => '_onpriv_repeat_status',
98 # -- MPD interaction: controlling playback
99 'play' => '_onpub_play',
100 'playid' => '_onpub_playid',
101 'pause' => '_onpub_pause',
102 'stop' => '_onpub_stop',
103 'next' => '_onpub_next',
104 'prev' => '_onpub_prev',
105 'seek' => '_onpub_seek',
106 '_seek_need_current' => '_onpriv_seek_need_current',
107 'seekid' => '_onpub_seekid',
108 '_seekid_need_current' => '_onpriv_seek_need_current',
110 $collection => { # collection related commands
111 # -- Collection: retrieving songs & directories
115 # -- Collection: retrieving the whole collection
120 'coll.all_files' => '_onpub_all_files',
121 # -- Collection: picking songs
123 # # songs_with_filename_partial
124 # -- Collection: songs, albums & artists relations
127 # # songs_by_artist_partial
129 # # songs_from_album_partial
131 # # songs_with_title_partial
133 $playlist => { # playlist related commands
134 # -- Playlist: retrieving information
136 # # items_changed_since
137 # -- Playlist: adding / removing songs
138 'pl.add' => '_onpub_add',
139 'pl.delete' => '_onpub_delete',
141 'pl.clear' => '_onpub_clear',
143 # -- Playlist: changing playlist order
149 # -- Playlist: managing playlists
165 # event: disconnect()
167 # Request the pococm to be shutdown. Leave mpd running.
169 sub _onpub_disconnect
{
170 my ($k,$h) = @_[KERNEL
, HEAP
];
171 $k->alias_remove( $h->{alias
} ) if defined $h->{alias
}; # refcount--
172 $k->post( $h->{_socket
}, 'disconnect' ); # pococm-conn
180 # Event: _mpd_data( $msg )
182 # Received when mpd finished to send back some data.
184 sub _onprot_mpd_data
{
185 my ($k, $h, $msg) = @_[KERNEL
, HEAP
, ARG0
];
189 # transform data if needed.
190 my $transform = $msg->_transform;
191 last TRANSFORM
unless defined $msg->_transform;
193 $transform == $AS_SCALAR and do {
194 my $data = $msg->data->[0];
198 $transform == $AS_STATS and do {
199 my %stats = @
{ $msg->data };
200 my $stats = POE
::Component
::Client
::MPD
::Stats
->new( \
%stats );
204 $transform == $AS_STATUS and do {
205 my %status = @
{ $msg->data };
206 my $status = POE
::Component
::Client
::MPD
::Status
->new( \
%status );
213 # check for post-callback.
214 # need to be before pre-callback, since a pre-event may need to have
216 if ( defined $msg->_post ) {
217 $k->yield( $msg->_post, $msg ); # need a post-treatment...
218 $msg->_post( undef ); # remove postback.
222 # check for pre-callback.
223 my $preidx = firstidx
{ $msg->_request eq $_->_pre_event } @
{ $h->{pre_messages
} };
224 if ( $preidx != -1 ) {
225 my $pre = splice @
{ $h->{pre_messages
} }, $preidx, 1;
226 $k->yield( $pre->_pre_from, $pre, $msg ); # call post pre-event
227 $pre->_pre_from ( undef ); # remove pre-callback
228 $pre->_pre_event( undef ); # remove pre-event
232 return if $msg->_answer == $DISCARD;
235 $k->post( $msg->_from, 'mpd_result', $msg );
238 sub _onprot_mpd_error
{
241 $_[KERNEL
]->post( $msg->_from, 'mpd_error', $msg );
246 # Event: _mpd_version( $vers )
248 # Event received during connection, when mpd server sends its version.
249 # Store it for later usage if needed.
251 sub _onprot_mpd_version
{
252 $_[HEAP
]->{version
} = $_[ARG0
];
260 # Event: _start( \%params )
262 # Called when the poe session gets initialized. Receive a reference
263 # to %params, same as spawn() received.
266 my ($h, $args) = @_[HEAP
, ARG0
];
268 # set up connection details.
269 $args = {} unless defined $args;
271 host
=> $ENV{MPD_HOST
} || 'localhost',
272 port
=> $ENV{MPD_PORT
} || '6600',
273 password
=> $ENV{MPD_PASSWORD
} || '',
274 %$args, # overwrite previous defaults
275 id
=> $_[SESSION
]->ID, # required for connection
278 # set an alias (for easier communication) if requested.
279 $h->{alias
} = delete $params{alias
};
280 $_[KERNEL
]->alias_set($h->{alias
}) if defined $h->{alias
};
282 $h->{password
} = delete $params{password
};
283 $h->{_socket
} = POE
::Component
::Client
::MPD
::Connection
->spawn(\
%params);
284 $h->{pre_messages
} = [];
293 # received when the poe::component::client::tcp is (re-)connected to the
297 my ($self, $k) = @_[OBJECT, KERNEL];
298 $k->post($_[HEAP]{_socket}, 'send', 'status' );
299 # send password information
309 # event: _send( $msg )
311 # Event received to request message sending over tcp to mpd server.
312 # $msg is a pococm-message partially filled.
315 my ($k, $h, $msg) = @_[KERNEL
, HEAP
, ARG0
];
316 if ( defined $msg->_pre_event ) {
317 $k->yield( $msg->_pre_event ); # fire wanted pre-event
318 push @
{ $h->{pre_messages
} }, $msg; # store message
321 $k->post( $_[HEAP
]->{_socket
}, 'send', $msg );
333 POE::Component::Client::MPD - a full-blown mpd client library
338 use POE qw[ Component::Client::MPD ];
339 POE::Component::Client::MPD->spawn( {
342 password => 's3kr3t', # mpd password
343 alias => 'mpd', # poe alias
347 $_[KERNEL]->post( 'mpd', 'next' );
352 POCOCM gives a clear message-passing interface (sitting on top of POE)
353 for talking to and controlling MPD (Music Player Daemon) servers. A
354 connection to the MPD server is established as soon as a new POCOCM
357 Commands are then sent to the server as messages are passed.
360 =head1 PUBLIC PACKAGE METHODS
362 =head2 spawn( \%params )
364 This method will create a POE session responsible for communicating with mpd.
365 It will return the poe id of the session newly created.
367 You can tune the pococm by passing some arguments as a hash reference, where
374 The hostname of the mpd server. If none given, defaults to C<MPD_HOST>
375 environment variable. If this var isn't set, defaults to C<localhost>.
380 The port of the mpd server. If none given, defaults to C<MPD_PORT>
381 environment variable. If this var isn't set, defaults to C<6600>.
386 The password to sent to mpd to authenticate the client. If none given, defaults
387 to C<MPD_PASSWORD> environment variable. If this var isn't set, defaults to C<>.
392 An optional string to alias the newly created POE session.
400 For a list of public events that you can send to a POCOCM session, check:
406 C<POCOCM::Commands> for general commands
410 C<POCOCM::Playlist> for playlist-related commands
414 C<POCOCM::Collection> for collection-related commands
421 Please report any bugs or feature requests to C<bug-poe-component-client-mpd at
422 rt.cpan.org>, or through the web interface at
423 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=POE-Component-Client-MPD>.
424 I will be notified, and then you'll automatically be notified of progress on
425 your bug as I make changes.
430 You can find more information on the mpd project on its homepage at
431 L<http://www.musicpd.org>, or its wiki L<http://mpd.wikia.com>.
433 C<POE::Component::Client::MPD development> takes place on C<< <audio-mpd
434 at googlegroups.com> >>: feel free to join us. (use
435 L<http://groups.google.com/group/audio-mpd> to sign in). Our subversion
436 repository is located at L<https://svn.musicpd.org>.
439 You can also look for information on this module at:
443 =item * AnnoCPAN: Annotated CPAN documentation
445 L<http://annocpan.org/dist/POE-Component-Client-MPD>
449 L<http://cpanratings.perl.org/d/POE-Component-Client-MPD>
451 =item * RT: CPAN's request tracker
453 L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=POE-Component-Client-MPD>
460 Jerome Quelin, C<< <jquelin at cpan.org> >>
463 =head1 COPYRIGHT & LICENSE
465 Copyright 2007 Jerome Quelin, all rights reserved.
467 This program is free software; you can redistribute it and/or modify
468 it under the terms of the GNU General Public License as published by
469 the Free Software Foundation; either version 2 of the License, or
470 (at your option) any later version.
472 This program is distributed in the hope that it will be useful,
473 but WITHOUT ANY WARRANTY; without even the implied warranty of
474 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
475 GNU General Public License for more details.
477 You should have received a copy of the GNU General Public License
478 along with this program; if not, write to the Free Software
479 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA