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
;
15 use List
::MoreUtils qw
[ firstidx
];
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.6.0';
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.
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(
57 '_start' => \
&_onpriv_start
,
58 '_send' => \
&_onpriv_send
,
60 '_mpd_data' => \
&_onprot_mpd_data
,
61 '_mpd_error' => \
&_onprot_mpd_error
,
62 '_mpd_version' => \
&_onprot_mpd_version
,
64 'disconnect' => \
&_onpub_disconnect
,
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 'coll.all_items' => '_onpub_all_items',
106 'coll.all_items_simple' => '_onpub_all_items_simple',
107 'coll.items_in_dir' => '_onpub_items_in_dir',
108 # -- Collection: retrieving the whole collection
113 'coll.all_files' => '_onpub_all_files',
114 # -- Collection: picking songs
116 # # songs_with_filename_partial
117 # -- Collection: songs, albums & artists relations
120 # # songs_by_artist_partial
122 # # songs_from_album_partial
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',
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
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
];
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];
192 $transform == $AS_STATS and do {
193 my %stats = @
{ $msg->data };
194 my $stats = POE
::Component
::Client
::MPD
::Stats
->new( \
%stats );
198 $transform == $AS_STATUS and do {
199 my %status = @
{ $msg->data };
200 my $status = POE
::Component
::Client
::MPD
::Status
->new( \
%status );
207 # check for post-callback.
208 # need to be before pre-callback, since a pre-event may need to have
210 if ( defined $msg->_post ) {
211 $k->yield( $msg->_post, $msg ); # need a post-treatment...
212 $msg->_post( undef ); # remove postback.
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
226 return if $msg->_answer == $DISCARD;
229 $k->post( $msg->_from, 'mpd_result', $msg );
232 sub _onprot_mpd_error
{
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
];
254 # Event: _start( \%params )
256 # Called when the poe session gets initialized. Receive a reference
257 # to %params, same as spawn() received.
260 my ($h, $args) = @_[HEAP
, ARG0
];
262 # set up connection details.
263 $args = {} unless defined $args;
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
} = [];
287 # received when the poe::component::client::tcp is (re-)connected to the
291 my ($self, $k) = @_[OBJECT, KERNEL];
292 $k->post($_[HEAP]{_socket}, 'send', 'status' );
293 # send password information
303 # event: _send( $msg )
305 # Event received to request message sending over tcp to mpd server.
306 # $msg is a pococm-message partially filled.
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
315 $k->post( $_[HEAP
]->{_socket
}, 'send', $msg );
327 POE::Component::Client::MPD - a full-blown mpd client library
332 use POE qw[ Component::Client::MPD ];
333 POE::Component::Client::MPD->spawn( {
336 password => 's3kr3t', # mpd password
337 alias => 'mpd', # poe alias
341 $_[KERNEL]->post( 'mpd', 'next' );
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
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
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>.
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>.
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<>.
386 An optional string to alias the newly created POE session.
394 For a list of public events that you can send to a POCOCM session, check:
400 C<POCOCM::Commands> for general commands
404 C<POCOCM::Playlist> for playlist-related commands
408 C<POCOCM::Collection> for collection-related commands
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.
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:
437 =item * AnnoCPAN: Annotated CPAN documentation
439 L<http://annocpan.org/dist/POE-Component-Client-MPD>
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>
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.