]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - config/mpfire/perl/Audio/MPD.pm
suricata: Change midstream policy to "pass-flow"
[people/pmueller/ipfire-2.x.git] / config / mpfire / perl / Audio / MPD.pm
CommitLineData
83d20a45
CS
1#
2# This file is part of Audio::MPD
3# Copyright (c) 2007 Jerome Quelin, all rights reserved.
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the same terms as Perl itself.
7#
8#
9
10package Audio::MPD;
11
12use warnings;
13use strict;
14
15use Audio::MPD::Collection;
16use Audio::MPD::Common::Item;
17use Audio::MPD::Common::Stats;
18use Audio::MPD::Common::Status;
19use Audio::MPD::Playlist;
20use Encode;
21use IO::Socket;
22use Readonly;
23
24
25use base qw[ Class::Accessor::Fast Exporter ];
26__PACKAGE__->mk_accessors(
27 qw[ _conntype _host _password _port _socket
28 collection playlist version ] );
29
30
31our $VERSION = '0.19.1';
32
3e460753
CS
33Readonly our $REUSE => 0;
34Readonly our $ONCE => 1;
83d20a45
CS
35
36our @EXPORT = qw[ $REUSE $ONCE ];
37
38
39#--
40# Constructor
41
42#
43# my $mpd = Audio::MPD->new( [%opts] )
44#
45# This is the constructor for Audio::MPD. One can specify the following
46# options:
47# - hostname => $hostname : defaults to environment var MPD_HOST, then to 'localhost'
48# - port => $port : defaults to env var MPD_PORT, then to 6600
49# - password => $password : defaults to env var MPD_PASSWORD, then to ''
50# - conntype => $type : how the connection to mpd server is handled. it can be
51# either $REUSE: reuse the same connection
52# or $ONCE: open a new connection per command (default)
3e460753 53#
83d20a45
CS
54sub new {
55 my ($class, %opts) = @_;
56
57 # use mpd defaults.
58 my ($default_password, $default_host) = split( '@', $ENV{MPD_HOST} )
59 if exists $ENV{MPD_HOST} && $ENV{MPD_HOST} =~ /@/;
60 my $host = $opts{host} || $default_host || $ENV{MPD_HOST} || 'localhost';
61 my $port = $opts{port} || $ENV{MPD_PORT} || '6600';
62 my $password = $opts{password} || $ENV{MPD_PASSWORD} || $default_password || '';
63
64 # create & bless the object.
65 my $self = {
66 _host => $host,
67 _port => $port,
68 _password => $password,
3e460753 69 _conntype => exists $opts{conntype} ? $opts{conntype} : $REUSE,
83d20a45
CS
70 };
71 bless $self, $class;
72
73 # create the connection if conntype is set to $REUSE
74 $self->_connect_to_mpd_server if $self->_conntype == $REUSE;
75
76
77 # create the helper objects and store them.
78 $self->collection( Audio::MPD::Collection->new($self) );
79 $self->playlist ( Audio::MPD::Playlist->new($self) );
80
81 # try to issue a ping to test connection - this can die.
82 $self->ping;
83
84 return $self;
85}
86
87
88#--
89# Private methods
90
91
92#
93# $mpd->_connect_to_mpd_server;
94#
95# This method connects to the mpd server. It can die on several conditions:
96# - if the server cannot be reached,
97# - if it's not an mpd server,
98# - or if the password is incorrect,
99#
100sub _connect_to_mpd_server {
101 my ($self) = @_;
102
103 # try to connect to mpd.
104 my $socket = IO::Socket::INET->new(
105 PeerAddr => $self->_host,
106 PeerPort => $self->_port,
107 )
108 or die "Could not create socket: $!\n";
109
110 # parse version information.
111 my $line = $socket->getline;
112 chomp $line;
113 die "Not a mpd server - welcome string was: [$line]\n"
114 if $line !~ /^OK MPD (.+)$/;
115 $self->version($1);
116
117 # send password.
118 if ( $self->_password ) {
119 $socket->print( 'password ' . encode('utf-8', $self->_password) . "\n" );
120 $line = $socket->getline;
121 die $line if $line =~ s/^ACK //;
122 }
123
124 # save socket
125 $self->_socket($socket);
126}
127
128
129#
130# my @result = $mpd->_send_command( $command );
131#
132# This method is central to the module. It is responsible for interacting with
133# mpd by sending the $command and reading output - that will be returned as an
134# array of chomped lines (status line will not be returned).
135#
136# This method can die on several conditions:
137# - if the server cannot be reached,
138# - if it's not an mpd server,
139# - if the password is incorrect,
140# - or if the command is an invalid mpd command.
141# In the latter case, the mpd error message will be returned.
142#
143sub _send_command {
144 my ($self, $command) = @_;
145
146 $self->_connect_to_mpd_server if $self->_conntype == $ONCE;
147 my $socket = $self->_socket;
148
149 # ok, now we're connected - let's issue the command.
150 $socket->print( encode('utf-8', $command) );
151 my @output;
152 while (defined ( my $line = $socket->getline ) ) {
153 chomp $line;
154 die $line if $line =~ s/^ACK //; # oops - error.
155 last if $line =~ /^OK/; # end of output.
156 push @output, decode('utf-8', $line);
157 }
158
159 # close the socket.
160 $socket->close if $self->_conntype == $ONCE;
161
162 return @output;
163}
164
165
166#
167# my @items = $mpd->_cooked_command_as_items( $command );
168#
169# Lots of Audio::MPD methods are using _send_command() and then parse the
170# output as a collection of AMC::Item. This method is meant to factorize
171# this code, and will parse the raw output of _send_command() in a cooked
172# list of items.
173#
174sub _cooked_command_as_items {
175 my ($self, $command) = @_;
176
177 my @lines = $self->_send_command($command);
178 my (@items, %param);
179
180 # parse lines in reverse order since "file:" or "directory:" lines
181 # come first. therefore, let's first store every other parameter,
182 # and the last line will trigger the object creation.
183 # of course, since we want to preserve the playlist order, this means
184 # that we're going to unshift the objects instead of push.
185 foreach my $line (reverse @lines) {
186 my ($k,$v) = split /:\s/, $line, 2;
187 $param{$k} = $v;
188 next unless $k eq 'file' || $k eq 'directory' || $k eq 'playlist'; # last param of item
189 unshift @items, Audio::MPD::Common::Item->new(%param);
190 %param = ();
191 }
192
193 return @items;
194}
195
196
197sub _cooked_command_as_filename {
198 my ($self, $command) = @_;
199
200 my @lines = $self->_send_command($command);
201 my (@items, %param);
202
203 # parse lines in reverse order since "file:" or "directory:" lines
204 # come first. therefore, let's first store every other parameter,
205 # and the last line will trigger the object creation.
206 # of course, since we want to preserve the playlist order, this means
207 # that we're going to unshift the objects instead of push.
208 foreach my $line (@lines) {
209 my ($k,$v) = split /:\s/, $line, 2;
210 if ( $k eq 'file'){$param{$k} = $v;}
211 unshift @items, $param{'file'};
212 %param = ();
213 }
214
215 return @items;
216}
217
218#
219# my %hash = $mpd->_cooked_command_as_kv( $command );
220#
221# Lots of Audio::MPD methods are using _send_command() and then parse the
222# output to get a list of key / value (with the colon ":" acting as separator).
223# This method is meant to factorize this code, and will parse the raw output
224# of _send_command() in a cooked hash.
225#
226sub _cooked_command_as_kv {
227 my ($self, $command) = @_;
228 my %hash =
229 map { split(/:\s/, $_, 2) }
230 $self->_send_command($command);
231 return %hash;
232}
233
234#
235# my @list = $mpd->_cooked_command_strip_first_field( $command );
236#
237# Lots of Audio::MPD methods are using _send_command() and then parse the
238# output to remove the first field (with the colon ":" acting as separator).
239# This method is meant to factorize this code, and will parse the raw output
240# of _send_command() in a cooked list of strings.
241#
242sub _cooked_command_strip_first_field {
243 my ($self, $command) = @_;
244
245 my @list =
246 map { ( split(/:\s+/, $_, 2) )[1] }
247 $self->_send_command($command);
248 return @list;
249}
250
251
252#--
253# Public methods
254
255# -- MPD interaction: general commands
256
257#
258# $mpd->ping;
259#
260# Sends a ping command to the mpd server.
261#
262sub ping {
263 my ($self) = @_;
264 $self->_send_command( "ping\n" );
265}
266
267
268#
269# my $version = $mpd->version;
270#
271# Return version of MPD server's connected.
272#
273# sub version {} # implemented as an accessor.
274#
275
276
277#
278# $mpd->kill;
279#
280# Send a message to the MPD server telling it to shut down.
281#
282sub kill {
283 my ($self) = @_;
284 $self->_send_command("kill\n");
285}
286
287
288#
289# $mpd->password( [$password] )
290#
291# Change password used to communicate with MPD server to $password.
292# Empty string is assumed if $password is not supplied.
293#
294sub password {
295 my ($self, $passwd) = @_;
296 $passwd ||= '';
297 $self->_password($passwd);
298 $self->ping; # ping sends a command, and thus the password is sent
299}
300
301
302#
303# $mpd->updatedb( [$path] );
304#
305# Force mpd to rescan its collection. If $path (relative to MPD's music
306# directory) is supplied, MPD will only scan it - otherwise, MPD will rescan
307# its whole collection.
308#
309sub updatedb {
310 my ($self, $path) = @_;
311 $path ||= '';
312 $self->_send_command("update $path\n");
313}
314
315
316#
317# my @handlers = $mpd->urlhandlers;
318#
319# Return an array of supported URL schemes.
320#
321sub urlhandlers {
322 my ($self) = @_;
323 return $self->_cooked_command_strip_first_field("urlhandlers\n");
324}
325
326
327# -- MPD interaction: handling volume & output
328
329#
330# $mpd->volume( [+][-]$volume );
331#
332# Sets the audio output volume percentage to absolute $volume.
333# If $volume is prefixed by '+' or '-' then the volume is changed relatively
334# by that value.
335#
336sub volume {
337 my ($self, $volume) = @_;
338
339 if ($volume =~ /^(-|\+)(\d+)/ ) {
340 my $current = $self->status->volume;
341 $volume = $1 eq '+' ? $current + $2 : $current - $2;
342 }
343 $self->_send_command("setvol $volume\n");
344}
345
346
347#
348# $mpd->output_enable( $output );
349#
350# Enable the specified audio output. $output is the ID of the audio output.
351#
352sub output_enable {
353 my ($self, $output) = @_;
354 $self->_send_command("enableoutput $output\n");
355}
356
357
358#
359# $mpd->output_disable( $output );
360#
361# Disable the specified audio output. $output is the ID of the audio output.
362#
363sub output_disable {
364 my ($self, $output) = @_;
365 $self->_send_command("disableoutput $output\n");
366}
367
368
369
370# -- MPD interaction: retrieving info from current state
371
372#
373# $mpd->stats;
374#
375# Return an AMC::Stats object with the current statistics of MPD.
376#
377sub stats {
378 my ($self) = @_;
379 my %kv = $self->_cooked_command_as_kv( "stats\n" );
380 return Audio::MPD::Common::Stats->new(\%kv);
381}
382
383
384#
385# my $status = $mpd->status;
386#
387# Return an AMC::Status object with various information on current
388# MPD server settings. Check the embedded pod for more information on the
389# available accessors.
390#
391sub status {
392 my ($self) = @_;
393 my %kv = $self->_cooked_command_as_kv( "status\n" );
394 my $status = Audio::MPD::Common::Status->new( \%kv );
395 return $status;
396}
397
398
399#
400# my $song = $mpd->current;
401#
402# Return an AMC::Item::Song representing the song currently playing.
403#
404sub current {
405 my ($self) = @_;
406 my ($item) = $self->_cooked_command_as_items("currentsong\n");
407 return $item;
408}
409
410
411#
412# my $song = $mpd->song( [$song] )
413#
414# Return an AMC::Item::Song representing the song number $song.
415# If $song is not supplied, returns the current song.
416#
417sub song {
418 my ($self, $song) = @_;
419 return $self->current unless defined $song;
420 my ($item) = $self->_cooked_command_as_items("playlistinfo $song\n");
421 return $item;
422}
423
424
425#
426# my $song = $mpd->songid( [$songid] )
427#
428# Return an AMC::Item::Song representing the song with id $songid.
429# If $songid is not supplied, returns the current song.
430#
431sub songid {
432 my ($self, $songid) = @_;
433 return $self->current unless defined $songid;
434 my ($item) = $self->_cooked_command_as_items("playlistid $songid\n");
435 return $item;
436}
437
438
439# -- MPD interaction: altering settings
440
441#
442# $mpd->repeat( [$repeat] );
443#
444# Set the repeat mode to $repeat (1 or 0). If $repeat is not specified then
445# the repeat mode is toggled.
446#
447sub repeat {
448 my ($self, $mode) = @_;
449
450 $mode = not $self->status->repeat
451 unless defined $mode; # toggle if no param
452 $mode = $mode ? 1 : 0; # force integer
453 $self->_send_command("repeat $mode\n");
454}
455
456
457#
458# $mpd->random( [$random] );
459#
460# Set the random mode to $random (1 or 0). If $random is not specified then
461# the random mode is toggled.
462#
463sub random {
464 my ($self, $mode) = @_;
465
466 $mode = not $self->status->random
467 unless defined $mode; # toggle if no param
468 $mode = $mode ? 1 : 0; # force integer
469 $self->_send_command("random $mode\n");
470}
471
472
473#
474# $mpd->fade( [$seconds] );
475#
476# Enable crossfading and set the duration of crossfade between songs. If
477# $seconds is not specified or $seconds is 0, then crossfading is disabled.
478#
479sub fade {
480 my ($self, $value) = @_;
481 $value ||= 0;
482 $self->_send_command("crossfade $value\n");
483}
484
485
486# -- MPD interaction: controlling playback
487
488#
489# $mpd->play( [$song] );
490#
491# Begin playing playlist at song number $song. If no argument supplied,
492# resume playing.
493#
494sub play {
495 my ($self, $number) = @_;
496 $number = '' unless defined $number;
497 $self->_send_command("play $number\n");
498}
499
500#
501# $mpd->playid( [$songid] );
502#
503# Begin playing playlist at song ID $songid. If no argument supplied,
504# resume playing.
505#
506sub playid {
507 my ($self, $number) = @_;
508 $number ||= '';
509 $self->_send_command("playid $number\n");
510}
511
512
513#
514# $mpd->pause( [$sate] );
515#
516# Pause playback. If $state is 0 then the current track is unpaused, if
517# $state is 1 then the current track is paused.
518#
519# Note that if $state is not given, pause state will be toggled.
520#
521sub pause {
522 my ($self, $state) = @_;
523 $state ||= ''; # default is to toggle
524 $self->_send_command("pause $state\n");
525}
526
527
528#
529# $mpd->stop;
530#
531# Stop playback.
532#
533sub stop {
534 my ($self) = @_;
535 $self->_send_command("stop\n");
536}
537
538
539#
540# $mpd->next;
541#
542# Play next song in playlist.
543#
544sub next {
545 my ($self) = @_;
546 $self->_send_command("next\n");
547}
548
549#
550# $mpd->prev;
551#
552# Play previous song in playlist.
553#
554sub prev {
555 my($self) = shift;
556 $self->_send_command("previous\n");
557}
558
559
560#
561# $mpd->seek( $time, [$song] );
562#
563# Seek to $time seconds in song number $song. If $song number is not specified
564# then the perl module will try and seek to $time in the current song.
565#
566sub seek {
567 my ($self, $time, $song) = @_;
568 $time ||= 0; $time = int $time;
569 $song = $self->status->song if not defined $song; # seek in current song
570 $self->_send_command( "seek $song $time\n" );
571}
572
573
574#
575# $mpd->seekid( $time, [$songid] );
576#
577# Seek to $time seconds in song ID $songid. If $songid number is not specified
578# then the perl module will try and seek to $time in the current song.
579#
580sub seekid {
581 my ($self, $time, $song) = @_;
582 $time ||= 0; $time = int $time;
583 $song = $self->status->songid if not defined $song; # seek in current song
584 $self->_send_command( "seekid $song $time\n" );
585}
586
587
5881;
589
590
591
592__END__
593
594=pod
595
596=head1 NAME
597
598Audio::MPD - class to talk to MPD (Music Player Daemon) servers
599
600
601=head1 SYNOPSIS
602
603 use Audio::MPD;
604
605 my $mpd = Audio::MPD->new();
606 $mpd->play();
607 sleep 10;
608 $mpd->next();
609
610
611=head1 DESCRIPTION
612
613Audio::MPD gives a clear object-oriented interface for talking to and
614controlling MPD (Music Player Daemon) servers. A connection to the MPD
615server is established as soon as a new Audio::MPD object is created.
616
617Note that the module will by default connect to mpd before sending any
618command, and will disconnect after the command has been issued. This scheme
619is far from optimal, but allows us not to care about timeout disconnections.
620
621B</!\> Note that Audio::MPD is using high-level, blocking sockets. This
622means that if the mpd server is slow, or hangs for whatever reason, or
623even crash abruptly, the program will be hung forever in this sub. The
624POE::Component::Client::MPD module is way safer - you're advised to use
625it instead of Audio::MPD. Or you can try to set C<conntype> to C<$REUSE>
626(see Audio::MPD constructor for more details), but you would be then on
627your own to deal with disconnections.
628
629
630=head1 METHODS
631
632=head2 Constructor
633
634=over 4
635
636=item new( [%opts] )
637
638This is the constructor for Audio::MPD. One can specify the following
639options:
640
641=over 4
642
643=item hostname => C<$hostname>
644
645defaults to environment var MPD_HOST, then to 'localhost'. Note that
646MPD_HOST can be of the form password@host.
647
648=item port => C<$port>
649
650defaults to environment var MPD_PORT, then to 6600.
651
652=item password => $password
653
654defaults to environment var MPD_PASSWORD, then to ''.
655
656=item conntype => $type
657
658change how the connection to mpd server is handled. It can be either
659C<$REUSE> to reuse the same connection or C<$ONCE> to open a new
660connection per command (default)
661
662=back
663
664
665=back
666
667
668=head2 Controlling the server
669
670=over 4
671
672=item $mpd->ping()
673
674Sends a ping command to the mpd server.
675
676
677=item $mpd->version()
678
679Return the version number for the server we are connected to.
680
681
682=item $mpd->kill()
683
684Send a message to the MPD server telling it to shut down.
685
686
687=item $mpd->password( [$password] )
688
689Change password used to communicate with MPD server to $password.
690Empty string is assumed if $password is not supplied.
691
692
693=item $mpd->updatedb( [$path] )
694
695Force mpd to recan its collection. If $path (relative to MPD's music directory)
696is supplied, MPD will only scan it - otherwise, MPD will rescan its whole
697collection.
698
699
700=item $mpd->urlhandlers()
701
702Return an array of supported URL schemes.
703
704
705=back
706
707
708=head2 Handling volume & output
709
710=over 4
711
712=item $mpd->volume( [+][-]$volume )
713
714Sets the audio output volume percentage to absolute $volume.
715If $volume is prefixed by '+' or '-' then the volume is changed relatively
716by that value.
717
718
719=item $mpd->output_enable( $output )
720
721Enable the specified audio output. $output is the ID of the audio output.
722
723
724=item $mpd->output_disable( $output )
725
726Disable the specified audio output. $output is the ID of the audio output.
727
728=back
729
730
731=head2 Retrieving info from current state
732
733=over 4
734
735=item $mpd->stats()
736
737Return an C<Audio::MPD::Common::Stats> object with the current statistics
738of MPD. See the associated pod for more information.
739
740
741=item $mpd->status()
742
743Return an C<Audio::MPD::Common::Status> object with various information on
744current MPD server settings. Check the embedded pod for more information on
745the available accessors.
746
747
748=item $mpd->current()
749
750Return an C<Audio::MPD::Common::Item::Song> representing the song currently
751playing.
752
753
754=item $mpd->song( [$song] )
755
756Return an C<Audio::MPD::Common::Item::Song> representing the song number
757C<$song>. If C<$song> is not supplied, returns the current song.
758
759
760=item $mpd->songid( [$songid] )
761
762Return an C<Audio::MPD::Common::Item::Song> representing the song with id
763C<$songid>. If C<$songid> is not supplied, returns the current song.
764
765=back
766
767
768=head2 Altering MPD settings
769
770=over 4
771
772=item $mpd->repeat( [$repeat] )
773
774Set the repeat mode to $repeat (1 or 0). If $repeat is not specified then
775the repeat mode is toggled.
776
777
778=item $mpd->random( [$random] )
779
780Set the random mode to $random (1 or 0). If $random is not specified then
781the random mode is toggled.
782
783
784=item $mpd->fade( [$seconds] )
785
786Enable crossfading and set the duration of crossfade between songs.
787If $seconds is not specified or $seconds is 0, then crossfading is disabled.
788
789=back
790
791
792=head2 Controlling playback
793
794=over 4
795
796=item $mpd->play( [$song] )
797
798Begin playing playlist at song number $song. If no argument supplied,
799resume playing.
800
801
802=item $mpd->playid( [$songid] )
803
804Begin playing playlist at song ID $songid. If no argument supplied,
805resume playing.
806
807
808=item $mpd->pause( [$state] )
809
810Pause playback. If C<$state> is 0 then the current track is unpaused,
811if $state is 1 then the current track is paused.
812
813Note that if C<$state> is not given, pause state will be toggled.
814
815
816=item $mpd->stop()
817
818Stop playback.
819
820
821=item $mpd->next()
822
823Play next song in playlist.
824
825
826=item $mpd->prev()
827
828Play previous song in playlist.
829
830
831=item $mpd->seek( $time, [$song])
832
833Seek to $time seconds in song number $song. If $song number is not specified
834then the perl module will try and seek to $time in the current song.
835
836
837=item $mpd->seekid( $time, $songid )
838
839Seek to $time seconds in song ID $songid. If $song number is not specified
840then the perl module will try and seek to $time in the current song.
841
842=back
843
844
845=head2 Searching the collection
846
847To search the collection, use the C<collection()> accessor, returning the
848associated C<Audio::MPD::Collection> object. You will then be able to call:
849
850 $mpd->collection->random_song();
851
852See C<Audio::MPD::Collection> documentation for more details on available
853methods.
854
855
856=head2 Handling the playlist
857
858To update the playlist, use the C<playlist()> accessor, returning the
859associated C<Audio::MPD::Playlist> object. You will then be able to call:
860
861 $mpd->playlist->clear;
862
863See C<Audio::MPD::Playlist> documentation for more details on available
864methods.
865
866
867=head1 SEE ALSO
868
869You can find more information on the mpd project on its homepage at
870L<http://www.musicpd.org>, or its wiki L<http://mpd.wikia.com>.
871
872Regarding this Perl module, you can report bugs on CPAN via
873L<http://rt.cpan.org/Public/Bug/Report.html?Queue=Audio-MPD>.
874
875Audio::MPD development takes place on <audio-mpd@googlegroups.com>: feel free
876to join us. (use L<http://groups.google.com/group/audio-mpd> to sign in). Our
877subversion repository is located at L<https://svn.musicpd.org>.
878
879
880=head1 AUTHOR
881
882Jerome Quelin, C<< <jquelin at cpan.org> >>
883
884Original code by Tue Abrahamsen C<< <tue.abrahamsen at gmail.com> >>,
885documented by Nicholas J. Humfrey C<< <njh at aelius.com> >>.
886
887
888=head1 COPYRIGHT & LICENSE
889
890Copyright (c) 2005 Tue Abrahamsen, all rights reserved.
891Copyright (c) 2006 Nicolas J. Humfrey, all rights reserved.
892Copyright (c) 2007 Jerome Quelin, all rights reserved.
893
894This program is free software; you can redistribute it and/or modify
895it under the same terms as Perl itself.
896
897=cut