[project @ 6182]
[poe-component-client-mpd.git] / lib / POE / Component / Client / MPD / Commands.pm
blob42c21a1df4a5322867c498767b5714782978cdf9
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::Commands;
20 use strict;
21 use warnings;
23 use POE;
24 use POE::Component::Client::MPD::Message;
25 use POE::Component::Client::MPD::Stats;
26 use POE::Component::Client::MPD::Status;
27 use base qw[ Class::Accessor::Fast ];
30 # -- MPD interaction: general commands
33 # event: version()
35 # Fires back an event with the version number.
37 sub _onpub_version {
38 my $msg = POE::Component::Client::MPD::Message->new( {
39 _from => $_[SENDER]->ID,
40 _request => $_[STATE],
41 _answer => $SEND,
42 data => $_[HEAP]->{version}
43 } );
44 $_[KERNEL]->yield( '_mpd_data', $msg );
49 # event: kill()
51 # Kill the mpd server, and request the pococm to be shutdown.
53 sub _onpub_kill {
54 my $msg = POE::Component::Client::MPD::Message->new( {
55 _from => $_[SENDER]->ID,
56 _request => $_[STATE],
57 _answer => $DISCARD,
58 _commands => [ 'kill' ],
59 _cooking => $RAW,
60 _post => 'disconnect', # shut down pococm behind us.
61 } );
62 $_[KERNEL]->yield( '_send', $msg );
67 # event: updatedb( [$path] )
69 # Force mpd to rescan its collection. If $path (relative to MPD's music
70 # directory) is supplied, MPD will only scan it - otherwise, MPD will rescan
71 # its whole collection.
73 sub _onpub_updatedb {
74 my $path = defined $_[ARG0] ? $_[ARG0] : '';
75 my $msg = POE::Component::Client::MPD::Message->new( {
76 _from => $_[SENDER]->ID,
77 _request => $_[STATE],
78 _answer => $DISCARD,
79 _commands => [ "update $path" ],
80 _cooking => $RAW,
81 } );
82 $_[KERNEL]->yield( '_send', $msg );
87 # event: urlhandlers()
89 # Return an array of supported URL schemes.
91 sub _onpub_urlhandlers {
92 my $msg = POE::Component::Client::MPD::Message->new( {
93 _from => $_[SENDER]->ID,
94 _request => $_[STATE],
95 _answer => $SEND,
96 _commands => [ 'urlhandlers' ],
97 _cooking => $STRIP_FIRST,
98 } );
99 $_[KERNEL]->yield( '_send', $msg );
103 # -- MPD interaction: handling volume & output
106 # event: volume( $volume )
108 # Sets the audio output volume percentage to absolute $volume.
109 # If $volume is prefixed by '+' or '-' then the volume is changed relatively
110 # by that value.
112 sub _onpub_volume {
113 # create stub message.
114 my $msg = POE::Component::Client::MPD::Message->new( {
115 _from => $_[SENDER]->ID,
116 _request => $_[STATE],
117 _answer => $DISCARD,
118 _cooking => $RAW,
119 } );
121 my $volume = $_[ARG0];
122 if ( $volume =~ /^(-|\+)(\d+)/ ) {
123 $msg->_pre_from( '_volume_status' );
124 $msg->_pre_event( 'status' );
125 $msg->_pre_data( $volume );
126 } else {
127 $msg->_commands( [ "setvol $volume" ] );
130 $_[KERNEL]->yield( '_send', $msg );
135 # event: _volume_status( $msg, $status )
137 # Use $status to get current volume, before sending real volume $msg.
139 sub _onpriv_volume_status {
140 my ($msg, $status) = @_[ARG0, ARG1];
141 my $curvol = $status->data->volume;
142 my $volume = $msg->_pre_data;
143 $volume =~ /^(-|\+)(\d+)/;
144 $volume = $1 eq '+' ? $curvol + $2 : $curvol - $2;
145 $msg->_commands( [ "setvol $volume" ] );
146 $_[KERNEL]->yield( '_send', $msg );
151 # event: output_enable( $output )
153 # Enable the specified audio output. $output is the ID of the audio output.
155 sub _onpub_output_enable {
156 my $output = $_[ARG0];
157 my $msg = POE::Component::Client::MPD::Message->new( {
158 _from => $_[SENDER]->ID,
159 _request => $_[STATE],
160 _answer => $DISCARD,
161 _commands => [ "enableoutput $output" ],
162 _cooking => $RAW,
163 } );
164 $_[KERNEL]->yield( '_send', $msg );
169 # event: output_disable( $output )
171 # Disable the specified audio output. $output is the ID of the audio output.
173 sub _onpub_output_disable {
174 my $output = $_[ARG0];
175 my $msg = POE::Component::Client::MPD::Message->new( {
176 _from => $_[SENDER]->ID,
177 _request => $_[STATE],
178 _answer => $DISCARD,
179 _commands => [ "disableoutput $output" ],
180 _cooking => $RAW,
181 } );
182 $_[KERNEL]->yield( '_send', $msg );
186 # -- MPD interaction: retrieving info from current state
189 # event: stats()
191 # Return a hash with the current statistics of MPD.
193 sub _onpub_stats {
194 my $msg = POE::Component::Client::MPD::Message->new( {
195 _from => $_[SENDER]->ID,
196 _request => $_[STATE],
197 _answer => $SEND,
198 _commands => [ 'stats' ],
199 _cooking => $AS_KV,
200 _transform => $AS_STATS,
201 } );
202 $_[KERNEL]->yield( '_send', $msg );
207 # event: status()
209 # Return a hash with the current status of MPD.
211 sub _onpub_status {
212 my $msg = POE::Component::Client::MPD::Message->new( {
213 _from => $_[SENDER]->ID,
214 _request => $_[STATE],
215 _answer => $SEND,
216 _commands => [ 'status' ],
217 _cooking => $AS_KV,
218 _transform => $AS_STATUS,
219 } );
220 $_[KERNEL]->yield( '_send', $msg );
225 # event: current()
227 # Return a POCOCM::Item::Song representing the song currently playing.
229 sub _onpub_current {
230 my $msg = POE::Component::Client::MPD::Message->new( {
231 _from => $_[SENDER]->ID,
232 _request => $_[STATE],
233 _answer => $SEND,
234 _commands => [ 'currentsong' ],
235 _cooking => $AS_ITEMS,
236 _transform => $AS_SCALAR,
237 } );
238 $_[KERNEL]->yield( '_send', $msg );
243 # event: song( [$song] )
245 # Return a POCOCM::Item::Song representing the song number $song.
246 # If $song is not supplied, returns the current song.
248 sub _onpub_song {
249 my ($k,$song) = @_[KERNEL, ARG0];
251 my $msg = POE::Component::Client::MPD::Message->new( {
252 _from => $_[SENDER]->ID,
253 _request => $_[STATE],
254 _answer => $SEND,
255 _commands => [ defined $song ? "playlistinfo $song" : 'currentsong' ],
256 _cooking => $AS_ITEMS,
257 _transform => $AS_SCALAR,
258 } );
259 $_[KERNEL]->yield( '_send', $msg );
263 # -- MPD interaction: altering settings
264 # -- MPD interaction: controlling playback
267 # event: play( [$song] )
269 # Begin playing playlist at song number $song. If no argument supplied,
270 # resume playing.
272 sub _onpub_play {
273 my $number = defined $_[ARG0] ? $_[ARG0] : '';
274 my $msg = POE::Component::Client::MPD::Message->new( {
275 _from => $_[SENDER]->ID,
276 _request => $_[STATE],
277 _answer => $DISCARD,
278 _commands => [ "play $number" ],
279 _cooking => $RAW,
280 } );
281 $_[KERNEL]->yield( '_send', $msg );
286 # event: playid( [$song] )
288 # Begin playing playlist at song ID $song. If no argument supplied,
289 # resume playing.
291 sub _onpub_playid {
292 my $number = defined $_[ARG0] ? $_[ARG0] : '';
293 my $msg = POE::Component::Client::MPD::Message->new( {
294 _from => $_[SENDER]->ID,
295 _request => $_[STATE],
296 _answer => $DISCARD,
297 _commands => [ "playid $number" ],
298 _cooking => $RAW,
299 } );
300 $_[KERNEL]->yield( '_send', $msg );
305 # event: pause( [$sate] )
307 # Pause playback. If $state is 0 then the current track is unpaused, if
308 # $state is 1 then the current track is paused.
310 # Note that if $state is not given, pause state will be toggled.
312 sub _onpub_pause {
313 my $state = defined $_[ARG0] ? $_[ARG0] : '';
314 my $msg = POE::Component::Client::MPD::Message->new( {
315 _from => $_[SENDER]->ID,
316 _request => $_[STATE],
317 _answer => $DISCARD,
318 _commands => [ "pause $state" ],
319 _cooking => $RAW,
320 } );
321 $_[KERNEL]->yield( '_send', $msg );
326 # event: stop()
328 # Stop playback
330 sub _onpub_stop {
331 my $msg = POE::Component::Client::MPD::Message->new( {
332 _from => $_[SENDER]->ID,
333 _request => $_[STATE],
334 _answer => $DISCARD,
335 _commands => [ 'stop' ],
336 _cooking => $RAW,
337 } );
338 $_[KERNEL]->yield( '_send', $msg );
343 # event: next()
345 # Play next song in playlist.
347 sub _onpub_next {
348 my $msg = POE::Component::Client::MPD::Message->new( {
349 _from => $_[SENDER]->ID,
350 _request => $_[STATE],
351 _answer => $DISCARD,
352 _commands => [ 'next' ],
353 _cooking => $RAW,
354 } );
355 $_[KERNEL]->yield( '_send', $msg );
360 # event: prev()
362 # Play previous song in playlist.
364 sub _onpub_prev {
365 my $msg = POE::Component::Client::MPD::Message->new( {
366 _from => $_[SENDER]->ID,
367 _request => $_[STATE],
368 _answer => $DISCARD,
369 _commands => [ 'previous' ],
370 _cooking => $RAW,
371 } );
372 $_[KERNEL]->yield( '_send', $msg );
377 # event: seek( $time, [$song] )
379 # Seek to $time seconds in song number $song. If $song number is not specified
380 # then the perl module will try and seek to $time in the current song.
382 sub _onpub_seek {
383 my ($time, $song) = @_[ARG0, ARG1];
384 $time ||= 0; $time = int $time;
385 my $msg = POE::Component::Client::MPD::Message->new( {
386 _from => $_[SENDER]->ID,
387 _request => $_[STATE],
388 _answer => $DISCARD,
389 _cooking => $RAW,
390 } );
392 if ( defined $song ) {
393 $msg->_commands( [ "seek $song $time" ] );
394 } else {
395 $msg->_pre_from( '_seek_need_current' );
396 $msg->_pre_event( 'status' );
397 $msg->_pre_data( $time );
399 $_[KERNEL]->yield( '_send', $msg );
404 # event: _seek_need_current( $msg, $current )
406 # Use $current to get current song, before sending real seek $msg.
408 sub _onpriv_seek_need_current {
409 my ($msg, $current) = @_[ARG0, ARG1];
410 my $song = $current->data->song;
411 my $time = $msg->_pre_data;
412 $msg->_commands( [ "seek $song $time" ] );
413 $_[KERNEL]->yield( '_send', $msg );
418 # event: seekid( $time, [$songid] )
420 # Seek to $time seconds in song ID $songid. If $songid number is not specified
421 # then the perl module will try and seek to $time in the current song.
423 sub _onpub_seekid {
424 my ($time, $song) = @_[ARG0, ARG1];
425 $time ||= 0; $time = int $time;
426 my $msg = POE::Component::Client::MPD::Message->new( {
427 _from => $_[SENDER]->ID,
428 _request => $_[STATE],
429 _answer => $DISCARD,
430 _cooking => $RAW,
431 } );
433 if ( defined $song ) {
434 $msg->_commands( [ "seekid $song $time" ] );
435 } else {
436 $msg->_pre_from( '_seekid_need_current' );
437 $msg->_pre_event( 'status' );
438 $msg->_pre_data( $time );
440 $_[KERNEL]->yield( '_send', $msg );
445 # event: _seekid_need_current( $msg, $current )
447 # Use $current to get current song, before sending real seekid $msg.
449 sub _onpriv_seekid_need_current {
450 my ($msg, $current) = @_[ARG0, ARG1];
451 my $song = $current->data->song;
452 my $time = $msg->_pre_data;
453 $msg->_commands( [ "seekid $song $time" ] );
454 $_[KERNEL]->yield( '_send', $msg );
460 __END__
462 =head1 NAME
464 POE::Component::Client::MPD::Commands - module handling basic commands
467 =head1 DESCRIPTION
469 C<POCOCM::Commands> is responsible for handling general purpose commands.
470 To achieve those commands, send the corresponding event to the POCOCM
471 session you created: it will be responsible for dispatching the event
472 where it is needed.
475 =head1 PUBLIC EVENTS
477 The following is a list of general purpose events accepted by POCOCM.
480 =head2 General commands
482 =head2 Handling volume & output
484 =head2 Retrieving info from current state
486 =head2 Altering settings
488 =head2 Controlling playback
491 =head1 SEE ALSO
493 For all related information (bug reporting, mailing-list, pointers to
494 MPD and POE, etc.), refer to C<POE::Component::Client::MPD>'s pod,
495 section C<SEE ALSO>
498 =head1 AUTHOR
500 Jerome Quelin, C<< <jquelin at cpan.org> >>
503 =head1 COPYRIGHT & LICENSE
505 Copyright 2007 Jerome Quelin, all rights reserved.
507 This program is free software; you can redistribute it and/or modify
508 it under the terms of the GNU General Public License as published by
509 the Free Software Foundation; either version 2 of the License, or
510 (at your option) any later version.
512 This program is distributed in the hope that it will be useful,
513 but WITHOUT ANY WARRANTY; without even the implied warranty of
514 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
515 GNU General Public License for more details.
517 You should have received a copy of the GNU General Public License
518 along with this program; if not, write to the Free Software
519 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
521 =cut