[project @ 6311]
[poe-component-client-mpd.git] / lib / POE / Component / Client / MPD.pm
blob4ffc7c09c352e5c243e0281948ad24889c0b7527
2 # This file is part of POE::Component::Client::MPD.
3 # Copyright (c) 2007 Jerome Quelin, all rights reserved.
5 # This program is free software; you can redistribute it and/or modify
6 # it under the same terms as Perl itself.
10 package POE::Component::Client::MPD;
12 use strict;
13 use warnings;
15 use List::MoreUtils qw[ firstidx ];
16 use POE;
17 use POE::Component::Client::MPD::Collection;
18 use POE::Component::Client::MPD::Commands;
19 use POE::Component::Client::MPD::Connection;
20 use POE::Component::Client::MPD::Message;
21 use POE::Component::Client::MPD::Playlist;
22 use base qw[ Class::Accessor::Fast ];
23 __PACKAGE__->mk_accessors( qw[ _host _password _port _version ] );
26 our $VERSION = '0.5.3';
30 # my $id = spawn( \%params )
32 # This method will create a POE session responsible for communicating
33 # with mpd. It will return the poe id of the session newly created.
35 # You can tune the pococm by passing some arguments as a hash reference,
36 # where the hash keys are:
37 # - host: the hostname of the mpd server. If none given, defaults to
38 # MPD_HOST env var. If this var isn't set, defaults to localhost.
39 # - port: the port of the mpd server. If none given, defaults to
40 # MPD_PORT env var. If this var isn't set, defaults to 6600.
41 # - password: the password to sent to mpd to authenticate the client.
42 # If none given, defaults to C<MPD_PASSWORD> env var. If this var
43 # isn't set, defaults to empty string.
44 # - alias: an optional string to alias the newly created POE session.
46 sub spawn {
47 my ($type, $args) = @_;
49 my $collection = POE::Component::Client::MPD::Collection->new;
50 my $commands = POE::Component::Client::MPD::Commands->new;
51 my $playlist = POE::Component::Client::MPD::Playlist->new;
53 my $session = POE::Session->create(
54 args => [ $args ],
55 inline_states => {
56 # private events
57 '_start' => \&_onpriv_start,
58 '_send' => \&_onpriv_send,
59 # protected events
60 '_mpd_data' => \&_onprot_mpd_data,
61 '_mpd_error' => \&_onprot_mpd_error,
62 '_mpd_version' => \&_onprot_mpd_version,
63 # public events
64 'disconnect' => \&_onpub_disconnect,
66 object_states => [
67 $commands => { # general purpose commands
68 # -- MPD interaction: general commands
69 'version' => '_onpub_version',
70 'kill' => '_onpub_kill',
71 # # 'password' => '_onpub_password',
72 'updatedb' => '_onpub_updatedb',
73 'urlhandlers' => '_onpub_urlhandlers',
74 # -- MPD interaction: handling volume & output
75 'volume' => '_onpub_volume',
76 '_volume_status' => '_onpriv_volume_status',
77 'output_enable' => '_onpub_output_enable',
78 'output_disable' => '_onpub_output_disable',
79 # -- MPD interaction: retrieving info from current state
80 'stats' => '_onpub_stats',
81 'status' => '_onpub_status',
82 'current' => '_onpub_current',
83 'song' => '_onpub_song',
84 'songid' => '_onpub_songid',
85 # -- MPD interaction: altering settings
86 'repeat' => '_onpub_repeat',
87 '_repeat_status' => '_onpriv_repeat_status',
88 'random' => '_onpub_random',
89 '_random_status' => '_onpriv_random_status',
90 'fade' => '_onpub_fade',
91 # -- MPD interaction: controlling playback
92 'play' => '_onpub_play',
93 'playid' => '_onpub_playid',
94 'pause' => '_onpub_pause',
95 'stop' => '_onpub_stop',
96 'next' => '_onpub_next',
97 'prev' => '_onpub_prev',
98 'seek' => '_onpub_seek',
99 '_seek_need_current' => '_onpriv_seek_need_current',
100 'seekid' => '_onpub_seekid',
101 '_seekid_need_current' => '_onpriv_seek_need_current',
103 $collection => { # collection related commands
104 # -- Collection: retrieving songs & directories
105 # # all_items
106 # # all_items_simple
107 # # items_in_dir
108 # -- Collection: retrieving the whole collection
109 # # all_songs
110 # # all_albums
111 # # all_artists
112 # # all_titles
113 'coll.all_files' => '_onpub_all_files',
114 # -- Collection: picking songs
115 # # song
116 # # songs_with_filename_partial
117 # -- Collection: songs, albums & artists relations
118 # # albums_by_artist
119 # # songs_by_artist
120 # # songs_by_artist_partial
121 # # songs_from_album
122 # # songs_from_album_partial
123 # # songs_with_title
124 # # songs_with_title_partial
126 $playlist => { # playlist related commands
127 # -- Playlist: retrieving information
128 'pl.as_items' => '_onpub_as_items',
129 'pl.items_changed_since' => '_onpub_items_changed_since',
130 # -- Playlist: adding / removing songs
131 'pl.add' => '_onpub_add',
132 'pl.delete' => '_onpub_delete',
133 'pl.deleteid' => '_onpub_deleteid',
134 'pl.clear' => '_onpub_clear',
135 'pl.crop' => '_onpub_crop',
136 '_crop_status' => '_onpriv_crop_status',
137 # -- Playlist: changing playlist order
138 'pl.shuffle' => '_onpub_shuffle',
139 'pl.swap' => '_onpub_swap',
140 'pl.swapid' => '_onpub_swapid',
141 'pl.move' => '_onpub_move',
142 'pl.moveid' => '_onpub_moveid',
143 # -- Playlist: managing playlists
144 'pl.load' => '_onpub_load',
145 'pl.save' => '_onpub_save',
146 'pl.rm' => '_onpub_rm',
151 return $session->ID;
156 # public events
159 # event: disconnect()
161 # Request the pococm to be shutdown. Leave mpd running.
163 sub _onpub_disconnect {
164 my ($k,$h) = @_[KERNEL, HEAP];
165 $k->alias_remove( $h->{alias} ) if defined $h->{alias}; # refcount--
166 $k->post( $h->{_socket}, 'disconnect' ); # pococm-conn
171 # protected events.
174 # Event: _mpd_data( $msg )
176 # Received when mpd finished to send back some data.
178 sub _onprot_mpd_data {
179 my ($k, $h, $msg) = @_[KERNEL, HEAP, ARG0];
181 TRANSFORM:
183 # transform data if needed.
184 my $transform = $msg->_transform;
185 last TRANSFORM unless defined $msg->_transform;
187 $transform == $AS_SCALAR and do {
188 my $data = $msg->data->[0];
189 $msg->data($data);
190 last TRANSFORM;
192 $transform == $AS_STATS and do {
193 my %stats = @{ $msg->data };
194 my $stats = POE::Component::Client::MPD::Stats->new( \%stats );
195 $msg->data($stats);
196 last TRANSFORM;
198 $transform == $AS_STATUS and do {
199 my %status = @{ $msg->data };
200 my $status = POE::Component::Client::MPD::Status->new( \%status );
201 $msg->data($status);
202 last TRANSFORM;
207 # check for post-callback.
208 # need to be before pre-callback, since a pre-event may need to have
209 # a post-callback.
210 if ( defined $msg->_post ) {
211 $k->yield( $msg->_post, $msg ); # need a post-treatment...
212 $msg->_post( undef ); # remove postback.
213 return;
216 # check for pre-callback.
217 my $preidx = firstidx { $msg->_request eq $_->_pre_event } @{ $h->{pre_messages} };
218 if ( $preidx != -1 ) {
219 my $pre = splice @{ $h->{pre_messages} }, $preidx, 1;
220 $k->yield( $pre->_pre_from, $pre, $msg ); # call post pre-event
221 $pre->_pre_from ( undef ); # remove pre-callback
222 $pre->_pre_event( undef ); # remove pre-event
223 return;
226 return if $msg->_answer == $DISCARD;
228 # send result.
229 $k->post( $msg->_from, 'mpd_result', $msg );
232 sub _onprot_mpd_error {
233 # send error.
234 my $msg = $_[ARG0];
235 $_[KERNEL]->post( $msg->_from, 'mpd_error', $msg );
240 # Event: _mpd_version( $vers )
242 # Event received during connection, when mpd server sends its version.
243 # Store it for later usage if needed.
245 sub _onprot_mpd_version {
246 $_[HEAP]->{version} = $_[ARG0];
251 # private events
254 # Event: _start( \%params )
256 # Called when the poe session gets initialized. Receive a reference
257 # to %params, same as spawn() received.
259 sub _onpriv_start {
260 my ($h, $args) = @_[HEAP, ARG0];
262 # set up connection details.
263 $args = {} unless defined $args;
264 my %params = (
265 host => $ENV{MPD_HOST} || 'localhost',
266 port => $ENV{MPD_PORT} || '6600',
267 password => $ENV{MPD_PASSWORD} || '',
268 %$args, # overwrite previous defaults
269 id => $_[SESSION]->ID, # required for connection
272 # set an alias (for easier communication) if requested.
273 $h->{alias} = delete $params{alias};
274 $_[KERNEL]->alias_set($h->{alias}) if defined $h->{alias};
276 $h->{password} = delete $params{password};
277 $h->{_socket} = POE::Component::Client::MPD::Connection->spawn(\%params);
278 $h->{pre_messages} = [];
282 =begin FIXME
285 # _connected()
287 # received when the poe::component::client::tcp is (re-)connected to the
288 # mpd server.
290 sub _connected {
291 my ($self, $k) = @_[OBJECT, KERNEL];
292 $k->post($_[HEAP]{_socket}, 'send', 'status' );
293 # send password information
296 =end FIXME
298 =cut
303 # event: _send( $msg )
305 # Event received to request message sending over tcp to mpd server.
306 # $msg is a pococm-message partially filled.
308 sub _onpriv_send {
309 my ($k, $h, $msg) = @_[KERNEL, HEAP, ARG0];
310 if ( defined $msg->_pre_event ) {
311 $k->yield( $msg->_pre_event ); # fire wanted pre-event
312 push @{ $h->{pre_messages} }, $msg; # store message
313 return;
315 $k->post( $_[HEAP]->{_socket}, 'send', $msg );
322 __END__
325 =head1 NAME
327 POE::Component::Client::MPD - a full-blown mpd client library
330 =head1 SYNOPSIS
332 use POE qw[ Component::Client::MPD ];
333 POE::Component::Client::MPD->spawn( {
334 host => 'localhost',
335 port => 6600,
336 password => 's3kr3t', # mpd password
337 alias => 'mpd', # poe alias
338 } );
340 # ... later on ...
341 $_[KERNEL]->post( 'mpd', 'next' );
344 =head1 DESCRIPTION
346 POCOCM gives a clear message-passing interface (sitting on top of POE)
347 for talking to and controlling MPD (Music Player Daemon) servers. A
348 connection to the MPD server is established as soon as a new POCOCM
349 object is created.
351 Commands are then sent to the server as messages are passed.
354 =head1 PUBLIC PACKAGE METHODS
356 =head2 spawn( \%params )
358 This method will create a POE session responsible for communicating with mpd.
359 It will return the poe id of the session newly created.
361 You can tune the pococm by passing some arguments as a hash reference, where
362 the hash keys are:
364 =over 4
366 =item * host
368 The hostname of the mpd server. If none given, defaults to C<MPD_HOST>
369 environment variable. If this var isn't set, defaults to C<localhost>.
372 =item * port
374 The port of the mpd server. If none given, defaults to C<MPD_PORT>
375 environment variable. If this var isn't set, defaults to C<6600>.
378 =item * password
380 The password to sent to mpd to authenticate the client. If none given, defaults
381 to C<MPD_PASSWORD> environment variable. If this var isn't set, defaults to C<>.
384 =item * alias
386 An optional string to alias the newly created POE session.
389 =back
392 =head1 PUBLIC EVENTS
394 For a list of public events that you can send to a POCOCM session, check:
396 =over 4
398 =item *
400 C<POCOCM::Commands> for general commands
402 =item *
404 C<POCOCM::Playlist> for playlist-related commands
406 =item *
408 C<POCOCM::Collection> for collection-related commands
410 =back
413 =head1 BUGS
415 Please report any bugs or feature requests to C<bug-poe-component-client-mpd at
416 rt.cpan.org>, or through the web interface at
417 L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=POE-Component-Client-MPD>.
418 I will be notified, and then you'll automatically be notified of progress on
419 your bug as I make changes.
422 =head1 SEE ALSO
424 You can find more information on the mpd project on its homepage at
425 L<http://www.musicpd.org>, or its wiki L<http://mpd.wikia.com>.
427 C<POE::Component::Client::MPD development> takes place on C<< <audio-mpd
428 at googlegroups.com> >>: feel free to join us. (use
429 L<http://groups.google.com/group/audio-mpd> to sign in). Our subversion
430 repository is located at L<https://svn.musicpd.org>.
433 You can also look for information on this module at:
435 =over 4
437 =item * AnnoCPAN: Annotated CPAN documentation
439 L<http://annocpan.org/dist/POE-Component-Client-MPD>
441 =item * CPAN Ratings
443 L<http://cpanratings.perl.org/d/POE-Component-Client-MPD>
445 =item * RT: CPAN's request tracker
447 L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=POE-Component-Client-MPD>
449 =back
452 =head1 AUTHOR
454 Jerome Quelin, C<< <jquelin at cpan.org> >>
457 =head1 COPYRIGHT & LICENSE
459 Copyright (c) 2007 Jerome Quelin, all rights reserved.
461 This program is free software; you can redistribute it and/or modify
462 it under the same terms as Perl itself.
464 =cut