File Coverage

blib/lib/Audio/Moosic.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Audio::Moosic;
2              
3 2     2   51893 use strict;
  2         4  
  2         73  
4 2     2   11 use warnings;
  2         4  
  2         68  
5 2     2   10 use vars qw( $VERSION );
  2         4  
  2         102  
6 2     2   914 use RPC::XML;
  0            
  0            
7             use RPC::XML::Client;
8              
9             $VERSION = '0.10';
10              
11             =head1 NAME
12              
13             Audio::Moosic - Moosic client library for Perl
14              
15             =head1 SYNOPSIS
16              
17             use Audio::Moosic;
18              
19             $moo = Audio::Moosic::Unix->new();
20              
21             $moosic->append('/home/me/somewhat.ogg');
22             $moosic->play;
23             print $moosic->current, "\n";
24             $moosic->pause;
25             ...
26              
27             =head1 DESCRIPTION
28              
29             Audio::Moosic acts as a client for the musical jukebox programm Moosic
30             (http://nanoo.org/~daniel/moosic/) by Daniel Pearson .
31              
32             Using Audio::Moosic you can connect to a moosic server either via an UNIX socket
33             or an INET socket.
34              
35             =head1 METHODS
36              
37             =head2 new
38              
39             $moo = Audio::Moosic::Unix->new();
40             $moo = Audio::Moosic::Unix->new('/tmp/moosic/socket');
41             $moo = Audio::Moosic::Inet->new('localhost', 8765);
42              
43             Constructor. Initializes the class and invokes the connect method. If you're
44             creating a Audio::Moosic::Unix object you can give the location of your moosic
45             socket as parameter. If not ~/.moosic/socket is used. If you're creating a
46             Audio::Moosic::Inet instance you need to pass host and port as arguments.
47              
48             You can't create an instance of Audio::Moosic itself. Use Unix or Inet subclass.
49              
50             If the object was able to connect to the moosic server a reference to the object
51             instance is returned. If the connection failed $@ is set and undef returned.
52              
53             =cut
54              
55             sub new {
56             my ($class, @args) = @_;
57             $class = ref($class) || $class;
58              
59             my $self = { __errors => [ ] };
60             bless $self, $class;
61              
62             unless( $self->connect(@args) ) {
63             $@ = "Can't connect to moosic server: $!";
64             return;
65             }
66              
67             return $self;
68             }
69              
70             =head2 connect
71              
72             $moo->connect('foobar.com', 9876);
73              
74             Connect to the moosic server. You normally don't need to run this method in your
75             moosic client.
76              
77             =cut
78              
79             sub connect {
80             require Carp;
81             Carp::croak('This method should never be called. Please create an instance'.
82             ' of Audio::Moosic::Inet or Audio::Moosic::Unix.');
83             }
84              
85             =head2 disconnect
86              
87             $moo->disconnect;
88              
89             Disconnect from the moosic daemon. No more calls will be sent to the server
90             after calling this method. You'll need to reconnect() first.
91              
92             =cut
93              
94             sub disconnect {
95             my $self = shift;
96             $self->{__connected} = 0;
97             delete $self->{__rpc_xml_client};
98             }
99              
100             =head2 reconnect
101              
102             $moo->reconnect;
103              
104             Disconnects from the server if you're connected and tries to reconnect.
105              
106             =cut
107              
108             sub reconnect {
109             my $self = shift;
110             $self->disconnect if $self->connected;
111             return $self->connect;
112             }
113              
114             =head2 connected
115              
116             $moo->reconnect unless $moo->connected;
117              
118             Check whether you're connected to the moosic server or not.
119              
120             =cut
121              
122             sub connected {
123             my $self = shift;
124             return $self->{__connected};
125             }
126              
127             =head2 client_config
128              
129             print $moo->client_config('location');
130             $conf = $moo->client_config();
131              
132             Reads the moosic clients config. If a $key argument is given it returns only the
133             value associated with that key, if not the whole config hash.
134              
135             Would it be a good idea to make the user able to edit the client_config here?
136             Suggestions or maybe patches are welcome.
137              
138             =cut
139              
140             sub client_config {
141             my ($self, $key) = @_;
142             if($key) {
143             return $self->{__client_config}{$key};
144             } else {
145             return $self->{__client_config};
146             }
147             }
148              
149             =head2 ping
150              
151             die unless $moo->ping;
152              
153             Checks if we're still connected. This method checks the connection explicitly by
154             calling the no_op server method. connected() only checks the value of the
155             'connected' object property.
156              
157             =cut
158              
159             sub ping {
160             my $self = shift;
161              
162             my $resp = $self->{__rpc_xml_client}->send_request('no_op');
163              
164             if( ref $resp ) {
165             $self->{__connected} = 1;
166             } else {
167             $self->{__connected} = 0;
168             }
169              
170             return $self->connected;
171             }
172              
173             =head2 error
174              
175             my $error = $moo->error;
176             $moo->error('Whaaa!');
177              
178             If an argument is given it adds the error string to the internal error array. If
179             called in scalar context it returns the last error occured. If you call error()
180             in list context the whole error array of the Audio::Moosic instance is returned.
181              
182             =cut
183              
184             sub error {
185             my ($self, $error) = @_;
186              
187             if($error) {
188             push(@{$self->{__errors}}, $error);
189             } else {
190             return wantarray ?
191             @{$self->{__errors}} :
192             @{$self->{__errors}}[@{$self->{__errors}} - 1];
193             }
194             }
195              
196             =head2 call
197              
198             $moo->call('foo');
199             $moo->call('bar', RPC::XML::int->new(3));
200              
201             This method calls a xml-rpc method on the moosic server. The first argument
202             should be the method name. The arguments of that method should follow behind.
203              
204             If the request to the moosic server could not be sent the Audio::Moosic instance
205             disconnects from the server and puts the error message into the internal error
206             array. Access it via error(). The object won't send any calls anymore if such an
207             error occured. You should try to reconnect.
208              
209             If the request could be sent, but returned an error the error message is added
210             to the error array accessable via error().
211              
212             If any error occured call() returns undef. If everything went fine the value of
213             the response is returned.
214              
215             Normally you don't need to call this method. It is only used by other moosic
216             methods to send their calls more easily. If a new moosic method is not supported
217             by this library yet you'll maybe need to use call() manually. Please notice me
218             if that happens so I'll add the new method.
219              
220             =cut
221              
222             sub call {
223             my ($self, $method, @args) = @_;
224             return unless $self->connected;
225             my $resp = $self->{__rpc_xml_client}->send_request($method, @args);
226              
227             unless( ref $resp ) {
228             my $error = qq/Lost connection to moosic server: "$resp"/;
229             if( my $function = (caller(1))[3]) { $error .= " in $function()"; }
230             $self->error($error);
231             $self->{__connected} = 0;
232             return;
233             }
234              
235             if( $resp->is_fault ) {
236             my $error = 'Error: '. $resp->code .': "'. $resp->string .'"';
237             if( my $function = (caller(1))[3]) { $error .= " in $function()"; }
238             $self->error($error);
239             return;
240             }
241              
242             return $resp->value;
243             }
244              
245             =head2 api_version
246              
247             @api = $moo->api_version;
248             $api = $moo->api_version;
249              
250             Return the moosic servers API version. If called in scalar context a version
251             string like '1.3' is returned. In list context the mayor and minor numbers of
252             the API version are returned.
253              
254             =cut
255              
256             sub api_version {
257             my $self = shift;
258             my $resp = $self->call('api_version') or return;
259             return wantarray ? @{$resp} : join('.', @{$resp});
260             }
261              
262             =head2 append
263              
264             $moo->append('/home/florian/whatever.ogg');
265             $moo->append('/home/florian/foo.ogg', '/home/florian/bar.mp3');
266              
267             Add songs to the moosic queue. The files to add should be the arguments for the
268             append method. append() returns 1 if there were no errors or something false if
269             there were some.
270              
271             =cut
272              
273             sub append {
274             my ($self, @items) = @_;
275             return $self->call('append', RPC::XML::array->new(
276             map { RPC::XML::base64->new($_) } @items
277             ));
278             }
279              
280             =head2 clear
281              
282             $moo->clear;
283              
284             Clears the moosic queue. Only the current song remains playing.
285              
286             =cut
287              
288             sub clear {
289             my $self = shift;
290             return $self->call('clear');
291             }
292              
293             =head2 crop
294              
295             $moo->crop(4);
296             $moo->crop(3, 4);
297              
298             Remove all playlist items that don't fall within a given range. If the range is
299             represented by one integer all items whose index is greater than or equal to the
300             value will be removed. Two intergers represent all items whose index is greater
301             than or equal to the value of first integer and less than the value of the
302             second integer.
303              
304             =cut
305              
306             sub crop {
307             my ($self, @range) = @_;
308             return $self->call('crop', RPC::XML::array->new(
309             map { RPC::XML::int->new($_) } @range
310             ));
311             }
312              
313             =head2 crop_list
314              
315             $moo->crop_list(1, 4, 3);
316              
317             Remove all queued items exept those referenced by a list of positions.
318              
319             =cut
320              
321             sub crop_list {
322             my ($self, @range) = @_;
323             return $self->call('crop_list', RPC::XML::array->new(
324             map { RPC::XML::int->new($_) } @range
325             ));
326             }
327              
328             =head2 current
329              
330             print $moo->current;
331              
332             Return the name of the current playing song.
333              
334             =cut
335              
336             sub current {
337             my $self = shift;
338             return $self->call('current');
339             }
340              
341             =head2 current_time
342              
343             print $moo->current_time;
344              
345             Return the amount of time the current song has been playing.
346              
347             =cut
348              
349             sub current_time {
350             my $self = shift;
351             return $self->call('current_time');
352             }
353              
354             =head2 cut
355              
356             $moo->cut(3);
357             $moo->cut(4, 10);
358              
359             Remove all queued items that fall within a given range. See crop() for details
360             on how that range should look like.
361              
362             =cut
363              
364             sub cut {
365             my ($self, @range) = @_;
366             return $self->call('cut', RPC::XML::array->new(
367             map { RPC::XML::int->new($_) } @range
368             ));
369             }
370              
371             =head2 cut_list
372              
373             $moo->cut_list(3, 7, 9);
374              
375             Remove all queued items referenced by list of positions.
376              
377             =cut
378              
379             sub cut_list {
380             my ($self, @range) = @_;
381             return $self->call('cut_list', RPC::XML::array->new(
382             map { RPC::XML::int->new($_) } @range
383             ));
384             }
385              
386             =head2 die
387              
388             $moo->die;
389              
390             Tell the server to terminate itself.
391              
392             =cut
393              
394             sub die {
395             my $self = shift;
396             ($self->call('die') and $self->disconnect) or return;
397             }
398              
399             =head2 filter
400              
401             $moo->filter('foo');
402             $moo->filter('bar', 4);
403             $moo->filter('moo', 7, 11);
404              
405             Remove all items that don't match the given regular expression. You may limit
406             this operation to a specific range which is described in crop().
407              
408             =cut
409              
410             sub filter {
411             my ($self, $regex, @range) = @_;
412             return $self->call('filter',
413             RPC::XML::base64->new($regex),
414             RPC::XML::array->new( map { RPC::XML::int->new($_) } @range )
415             );
416             }
417              
418             =head2 get_history_limit
419              
420             $limit = $moo->get_history_limit;
421              
422             Get the limit on the size of the history list stored in servers memory.
423              
424             =cut
425              
426             sub get_history_limit {
427             my $self = shift;
428             return $self->call('get_history_limit');
429             }
430              
431             =head2 getconfig
432              
433             @config = $moo->getconfig;
434              
435             Return a list of the server's filetype-player associations.
436              
437             =cut
438              
439             sub getconfig {
440             my ($self, $key) = @_;
441             my $resp = $self->call('getconfig');
442             return @{$resp};
443             #TODO support $key to read single config options
444             }
445              
446             =head2 halt_queue
447              
448             $moo->halt_queue;
449              
450             Stop any new songs from being played. Use run_queue() to reverse this state.
451              
452             =cut
453              
454             sub halt_queue {
455             my $self = shift;
456             return $self->call('halt_queue');
457             }
458              
459             =head2 haltqueue
460              
461             See halt_queue().
462              
463             =cut
464              
465             sub haltqueue {
466             my $self = shift;
467             $self->halt_queue;
468             }
469              
470             =head2 history
471              
472             %hist = $moo->history;
473              
474             Return a list of items that has been recently played. If a positive integer
475             argument is given than no more than number of items will be returned. Otherwise
476             the entire history is printed.
477              
478             history() returns an array of hashrefs like that:
479             @history = (
480             { title => 'foo', start => 123.45, stop => 543.21 },
481             { title => 'bar', start => 234.56, stop => 654.32 },
482             ...
483             );
484              
485             =cut
486              
487             sub history {
488             my ($self, $num) = @_;
489              
490             return map {
491             title => $_->[0],
492             start => $_->[1],
493             stop => $_->[2] }, @{$self->call('history',
494             RPC::XML::int->new( $num || 0 )) };
495             }
496              
497             =head2 indexed_list
498              
499             %list = $moo->indexed_list;
500             %list = $moo->indexed_list(1);
501             %list = $moo->indexed_list(2, 5);
502              
503             List the song queue's contents. If a range is specified, only the items that
504             fall within that range are listed.
505              
506             indexed_list() returns a hash like that:
507             %list = (
508             list => [ 'foo', 'bar', 'moo', ... ],
509             start => 4
510             );
511              
512             =cut
513              
514             sub indexed_list {
515             my ($self, @range) = @_;
516              
517             return $self->call('indexed_list', RPC::XML::array->new(
518             map { RPC::XML::int->new($_) } @range
519             ));
520             }
521              
522             =head2 insert
523              
524             $moo->insert(4, 'foo.ogg', 'bar.mp3');
525              
526             Insert items at a given position in the queue.
527              
528             =cut
529              
530             sub insert {
531             my $self = shift;
532             my $num = pop;
533             my @items = @_;
534              
535             return $self->call('insert',
536             RPC::XML::array->new( map { RPC::XML::base64->new($_) } @items ),
537             RPC::XML::int->new( $num )
538             );
539             }
540              
541             =head2 is_looping
542              
543             $moo->toggle_loop_mode if $moo->is_looping;
544              
545             Check whether the loop mode is on or not.
546              
547             =cut
548              
549             sub is_looping {
550             my $self = shift;
551             return $self->call('is_looping');
552             }
553              
554             =head2 is_paused
555              
556             $moo->toggle_pause if $moo->is_paused;
557              
558             Check whether the current song is paused or not.
559              
560             =cut
561              
562             sub is_paused {
563             my $self = shift;
564             return $self->call('is_paused');
565             }
566              
567             =head2 is_queue_running
568              
569             if($moo->is_queue_running) {
570             ...;
571             }
572              
573             Check whether the queue consumption (advancement) is activated.
574              
575             =cut
576              
577             sub is_queue_running {
578             my $self = shift;
579             return $self->call('is_queue_running');
580             }
581              
582             =head2 last_queue_update
583              
584             $time = $moo->last_queue_update
585              
586             Return the time at which the song queue was last modified.
587              
588             =cut
589              
590             sub last_queue_update {
591             my $self = shift;
592             return $self->call('last_queue_update');
593             }
594              
595             =head2 length
596              
597             $length = $moo->length
598              
599             Return the number of items in the song queue.
600              
601             =cut
602              
603             sub length {
604             my $self = shift;
605             return $self->call('length');
606             }
607              
608             =head2 list
609              
610             @list = $moo->list();
611             @list = $moo->list(2);
612             @list = $moo->list(4, 8);
613             $list_ref = $moo->list()
614              
615             List the song queue's contents. If a range is specified, only the items that
616             fall within that range are listed. Returns an array if called in list context
617             or an array reference if it's called in scalar context.
618              
619             =cut
620              
621             sub list {
622             my ($self, @range) = @_;
623              
624             my $list = $self->call('list', RPC::XML::array->new(
625             map { RPC::XML::int->new($_) } @range
626             ));
627              
628             return wantarray ?
629             @{$list} :
630             $list;
631             }
632              
633             =head2 move
634              
635             $moo->move(10, 4);
636             $moo->move(4, 7, 1);
637              
638             Move a range of items to a new position within the queue.
639              
640             =cut
641              
642             sub move {
643             my $self = shift;
644             my $num = pop;
645             my @range = @_;
646              
647             return $self->call('move',
648             RPC::XML::array->new( map { RPC::XML::int->new($_) } @range ),
649             RPC::XML::int->new( $num )
650             );
651             }
652              
653             =head2 move_list
654              
655             $moo->move(3, 5, 7, 11);
656              
657             Move the items referenced by a list of positions to a new position.
658              
659             =cut
660              
661             sub move_list {
662             my $self = shift;
663             my $num = pop;
664             my @range = @_;
665              
666             return $self->call('move_list',
667             RPC::XML::array->new( map { RPC::XML::int->new($_) } @range ),
668             RPC::XML::int->new( $num )
669             );
670             }
671              
672             =head2 next
673              
674             $moo->next;
675             $moo->next(5);
676              
677             Stop the current song (if any), and jumps ahead to a song that is currently in
678             the queue. The skipped songs are recorded in the history as if they had been
679             played. When called without arguments, this behaves very much like the skip()
680             method, except that it will have an effect even if nothing is currently playing.
681              
682             =cut
683              
684             sub next {
685             my ($self, $num) = @_;
686              
687             return $self->call('next', RPC::XML::int->new( $num || 1 ));
688             }
689              
690             =head2 no_op
691              
692             $moo->no_op
693              
694             Do nothing, successfully.
695              
696             =cut
697              
698             sub no_op {
699             my $self = shift;
700             return $self->call('no_op');
701             }
702              
703             =head2 pause
704              
705             $moo->pause;
706              
707             Pause the currently playing song.
708              
709             =cut
710              
711             sub pause {
712             my $self = shift;
713             return $self->call('pause');
714             }
715              
716             =head2 prepend
717              
718             $moo->prepend('foo.ogg', 'bar.mp3');
719              
720             Add items to the beginning of the queue.
721              
722             =cut
723              
724             sub prepend {
725             my ($self, @items) = @_;
726              
727             return $self->call('prepend', RPC::XML::array->new(
728             map { RPC::XML::base64->new($_) } @items
729             ));
730             }
731              
732             =head2 previous
733              
734             $moo->previous;
735             $moo->previous(3);
736              
737             Stops the current song (if any), removes the most recently played song from the
738             history, and puts these songs at the head of the queue. When loop mode is on,
739             the songs at the tail of the song queue are used instead of the most recently
740             played songs in the history.
741              
742             =cut
743              
744             sub previous {
745             my ($self, $num) = @_;
746              
747             return $self->call('previous', RPC::XML::int->new( $num || 1 ));
748             }
749              
750             =head2 putback
751              
752             $moo->putback;
753              
754             Place the currently playing song at the beginning of the queue.
755              
756             =cut
757              
758             sub putback {
759             my $self = shift;
760             return $self->call('putback');
761             }
762              
763             =head2 queue_length
764              
765             $length = $moo->queue_length;
766              
767             Return the number of items in the song queue.
768              
769             =cut
770              
771             sub queue_length {
772             my $self = shift;
773             return $self->call('queue_length');
774             }
775              
776             =head2 reconfigure
777              
778             $moo->reconfigure;
779              
780             Tell the server to reread its player configuration file.
781              
782             =cut
783              
784             sub reconfigure {
785             my $self = shift;
786             return $self->call('reconfigure');
787             }
788              
789             =head2 remove
790              
791             $moo->remove('regex');
792             $moo->remove('regex', 4);
793             $moo->remove('regex', 1, 3);
794              
795             Remove all items that match the given regular expression. You can limit this
796             operation by giving a range as described in crop() as last argument.
797              
798             =cut
799              
800             sub remove {
801             my ($self, $regex, @range) = @_;
802              
803             return $self->call('remove',
804             RPC::XML::base64->new( $regex ),
805             RPC::XML::array->new( map { RPC::XML::int->new($_) } @range )
806             );
807             }
808              
809             =head2 replace
810              
811             $moo->replace('foo.ogg', 'bar.mp3');
812              
813             Replace the contents of the queue with the given items. This is equivalent to
814             calling clear() and prepend() in succession, except that this operation is
815             atomic.
816              
817             =cut
818              
819             sub replace {
820             my ($self, @items) = @_;
821              
822             return $self->call('replace', RPC::XML::array->new(
823             map { RPC::XML::base64->new($_) } @items
824             ));
825             }
826              
827             =head2 reverse
828              
829             $moo->reverse;
830             $moo->reverse(2);
831             $moo->reverse(5, 7);
832              
833             Reverse the order of the items in the queue. You can limit this operation by
834             giving a range as described in crop() as last argument.
835              
836             =cut
837              
838             sub reverse {
839             my ($self, @range) = @_;
840              
841             return $self->call('reverse', RPC::XML::array->new(
842             map { RPC::XML::int->new($_) } @range
843             ));
844             }
845              
846             =head2 run_queue
847              
848             $moo->run_queue;
849              
850             Allows new songs to be played again after halt_queue() has been called.
851              
852             =cut
853              
854             sub run_queue {
855             my $self = shift;
856             return $self->call('run_queue');
857             }
858              
859             =head2 runqueue
860              
861             See run_queue().
862              
863             =cut
864              
865             sub runqueue {
866             my $self = shift;
867             return $self->run_queue;
868             }
869              
870             =head2 set_history_limit
871              
872             $moo->set_history_limit(44);
873              
874             Set the limit on the size of the history list stored in memory.
875              
876             =cut
877              
878             sub set_history_limit {
879             my ($self, $limit) = @_;
880              
881             return $self->call('set_history_limit', RPC::XML::int->new( $limit ));
882             }
883              
884             =head2 set_loop_mode
885              
886             $moo->set_loop_mode(0);
887             $moo->set_loop_mode(1);
888              
889             Turn loop mode on or off.
890              
891             =cut
892              
893             sub set_loop_mode {
894             my ($self, $mode) = @_;
895              
896             return $self->call('set_loop_mode', RPC::XML::boolean->new( $mode ));
897             }
898              
899             =head2 showconfig
900              
901             my $config = $moo->showconfig;
902             my %config = $moo->showconfig;
903              
904             Return the server's player configuration. If showconfig() is called in scalar
905             context a scalar containing the textual description of the configuration is
906             returned. If you call showconfig() in list context a hash which maps the
907             configuration regular expression to the player commands is returned.
908              
909             =cut
910              
911             sub showconfig {
912             my $self = shift;
913              
914             my $config = $self->call('showconfig');
915             return unless $config;
916             return $config unless wantarray;
917              
918             my @config;
919             foreach(split("\n", $config)) {
920             s/^\s+//;
921             chomp;
922             push(@config, $_);
923             }
924              
925             return @config;
926             }
927              
928             =head2 shuffle
929              
930             $moo->shuffle;
931             $moo->shuffle(2);
932             $moo->shuffle(4, 6);
933              
934             Rearrange the contents of the queue into a random order. You can limit this
935             operation by giving a range as described for crop() as last argument.
936              
937             =cut
938              
939             sub shuffle {
940             my ($self, @range) = @_;
941              
942             return $self->call('shuffle', RPC::XML::array->new(
943             map { RPC::XML::int->new($_) } @range
944             ));
945             }
946              
947             =head2 skip
948              
949             $moo->skip;
950              
951             Skips the rest of the current song to play the next song in the queue. This only
952             has an effect if there actually is a current song.
953              
954             =cut
955              
956             sub skip {
957             my $self = shift;
958             return $self->call('skip');
959             }
960              
961             =head2 sort
962              
963             $moo->sort;
964             $moo->sort(2);
965             $moo->sort(4, 6);
966              
967             Arrange the contents of the queue into sorted order.
968              
969             =cut
970              
971             sub sort {
972             my ($self, @range) = @_;
973              
974             return $self->call('sort', RPC::XML::array->new(
975             map { RPC::XML::int->new($_) } @range
976             ));
977             }
978              
979             =head2 stop
980              
981             $moo->stop;
982              
983             Stop playing the current song and stops new songs from playing. The current
984             song is returned to the head of the song queue and is not recorded in the
985             history list. If loop mode is on, the current song won't be placed at the end of
986             the song queue when it is stopped.
987              
988             =cut
989              
990             sub stop {
991             my $self = shift;
992             return $self->call('stop');
993             }
994              
995             =head2 sub
996              
997             $moo->sub('regex', 'substitition');
998             $moo->sub('regex', 'substitition', 2);
999             $moo->sub('regex', 'substitition', 1, 7);
1000              
1001             Perform a regular expression substitution on the items in the queue. You can
1002             limit this operation by giving a range as described for crop() as last argument.
1003              
1004             =cut
1005              
1006             sub sub {
1007             my ($self, $regex, $subst, @range) = @_;
1008              
1009             return $self->call('sub',
1010             RPC::XML::base64->new( $regex ),
1011             RPC::XML::base64->new( $subst ),
1012             RPC::XML::array->new( map { RPC::XML::int->new($_) } @range )
1013             );
1014             }
1015              
1016             =head2 sub_all
1017              
1018             $moo->sub_all('regex', 'substition');
1019             $moo->sub_all('regex', 'substition', 2);
1020             $moo->sub_all('regex', 'substition', 1, 7);
1021              
1022             Performs a global regular expression substitution on the items in the queue.
1023              
1024             =cut
1025              
1026             sub sub_all {
1027             my ($self, $regex, $subst, @range) = @_;
1028              
1029             return $self->call('sub_all',
1030             RPC::XML::base64->new( $regex ),
1031             RPC::XML::base64->new( $subst ),
1032             RPC::XML::array->new( map { RPC::XML::int->new($_) } @range )
1033             );
1034             }
1035              
1036             =head2 swap
1037              
1038             $moo->swap( [7, 10], [ 5 ] );
1039              
1040             Swap the items contained in one range with the items contained in the other
1041             range. The ranges for the swap() method needs to be passed as array references
1042             in contrast to other methods that use ranges.
1043              
1044             =cut
1045              
1046             sub swap {
1047             my ($self, $range1, $range2) = @_;
1048              
1049             return $self->call('swap',
1050             RPC::XML::array->new( map { RPC::XML::int->new($_) } @{$range1} ),
1051             RPC::XML::array->new( map { RPC::XML::int->new($_) } @{$range2} )
1052             );
1053             }
1054              
1055             =head2 listMethods
1056              
1057             @methods = $moo->listMethods;
1058              
1059             Return an array of all available XML-RPC methods on this server.
1060              
1061             =cut
1062              
1063             sub listMethods {
1064             my $self = shift;
1065             return $self->call('system.listMethods');
1066             }
1067              
1068             =head2 methodHelp
1069              
1070             $help = $moo->methodHelp('sub');
1071              
1072             Given the name of a method, return a help string.
1073              
1074             =cut
1075              
1076             sub methodHelp {
1077             my ($self, $method) = @_;
1078              
1079             return $self->call('syste.methodHelp',
1080             RPC::XML::string->new( $method )
1081             );
1082             }
1083              
1084             =head2 methodSignature
1085              
1086             $signature = $moo->methodSignature;
1087              
1088             Given the name of a method, return an array of legal signatures. Each signature
1089             is an array of scalars. The first item of each signature is the return type, and
1090             any others items are parameter types. =cut
1091              
1092             =cut
1093              
1094             sub methodSignature {
1095             my ($self, $method) = @_;
1096              
1097             return $self->call('system.methodSignature',
1098             RPC::XML::string->new( $method )
1099             );
1100             }
1101              
1102             =head2 multicall
1103              
1104             $moo->multicall(...);
1105              
1106             Process an array of calls, and return an array of results. This is not
1107             implemented yet.
1108              
1109             =cut
1110              
1111             sub multicall {
1112             my ($self, @cmds) = @_;
1113             require Carp;
1114             Carp::carp(__PACKAGE__."::multicall() isn't implemented yet."); #TODO
1115             }
1116              
1117             =head2 toggle_loop_mode
1118              
1119             $moo->toggle_loop_mode;
1120              
1121             Turn loop mode on if it is off, and turns it off if it is on.
1122              
1123             =cut
1124              
1125             sub toggle_loop_mode {
1126             my $self = shift;
1127             return $self->call('toggle_loop_mode');
1128             }
1129              
1130             =head2 toggle_pause
1131              
1132             $moo->toggle_pause;
1133              
1134             Pause the current song if it is playing, and unpauses if it is paused.
1135              
1136             =cut
1137              
1138             sub toggle_pause {
1139             my $self = shift;
1140             return $self->call('toggle_pause');
1141             }
1142              
1143             =head2 unpause
1144              
1145             $moo->unpause;
1146              
1147             Unpauses the current song.
1148              
1149             =cut
1150              
1151             sub unpause {
1152             my $self = shift;
1153             return $self->call('unpause');
1154             }
1155              
1156             =head2 version
1157              
1158             $version = $moo->version;
1159              
1160             Return the Moosic server's version string.
1161              
1162             =cut
1163              
1164             sub version {
1165             my $self = shift;
1166             return $self->call('version');
1167             }
1168              
1169             =head1 HELPER METHODS
1170              
1171             The following methods aren't methods defined by the moosic API but should be
1172             usefull when dealing with a moosic server.
1173              
1174             =head2 play
1175              
1176             $moo->play();
1177              
1178             Start playing. If the playback is paused it will be unpaused. If the queue is
1179             stopped it will be started.
1180              
1181             =cut
1182              
1183             sub play {
1184             my $self = shift;
1185              
1186             return $self->unpause() if $self->is_paused();
1187             return $self->run_queue();
1188             }
1189              
1190             =head2 can_play
1191              
1192             $moo->append( $song ) if $moo->can_play( $song );
1193              
1194             Takes a list of songs as argument and returns all items that can be played by
1195             the moosic daemon.
1196              
1197             =cut
1198              
1199             sub can_play {
1200             my $self = shift;
1201             my @can_play;
1202              
1203             my @config = $self->getconfig();
1204             for my $track ( @_ ) {
1205             for( @config ) {
1206             push @can_play, $track if $track =~ qr/$_->[0]/;
1207             }
1208             }
1209              
1210             return @can_play;
1211             }
1212              
1213             package Audio::Moosic::Inet;
1214              
1215             use strict;
1216             use warnings;
1217             use base qw( Audio::Moosic );
1218              
1219             sub connect {
1220             my ($self, $host, $port) = @_;
1221             return if $self->connected;
1222              
1223             my $location = "http://$host\:$port";
1224             $self->disconnect;
1225             $self->{__rpc_xml_client} = RPC::XML::Client->new($location);
1226              
1227             $self->ping or return;
1228             $self->{__client_config} = { location => $location };
1229             }
1230              
1231             package Audio::Moosic::Unix;
1232              
1233             use strict;
1234             use warnings;
1235             use base qw( Audio::Moosic );
1236              
1237              
1238             sub connect {
1239             _init();
1240              
1241             my ($self, $filename) = @_;
1242             return if $self->connected;
1243              
1244             $filename = ($ENV{HOME} || '/tmp') . '/.moosic/socket' unless $filename;
1245             my $location = "http://$filename";
1246             $self->disconnect;
1247             $self->{__rpc_xml_client} = RPC::XML::Client->new($location);
1248              
1249             $self->ping or return;
1250             $self->{__client_config} = { location => $location };
1251             }
1252              
1253             sub _init {
1254              
1255             unless( eval 'require LWP::Protocol::http::SocketUnix' ) {
1256             require Carp;
1257             Carp::croak('You need LWP::Protocol::http::SocketUnix to connect to a local'.
1258             " moosic server using a UNIX socket.\nPlease install it!");
1259             }
1260              
1261             LWP::Protocol::implementor( http => 'LWP::Protocol::http::SocketUnix' );
1262             }
1263              
1264             1;
1265              
1266             =head1 BUGS
1267              
1268             =over 4
1269              
1270             =item * check arguments more strictly
1271              
1272             expecially for constructors.
1273              
1274             =back
1275              
1276             If you find some others please report them to Florian Ragwitz
1277             Eflora@cpan.orgE
1278              
1279             =head1 TODO
1280              
1281             =over 4
1282              
1283             =item * implement system_multicall
1284              
1285             =item * improve client_config
1286              
1287             =item * maybe use autoloader to load subs on demand
1288              
1289             create the method arguments from methodSignature.
1290              
1291             =back
1292              
1293             =head1 SEE ALSO
1294              
1295             moosic(1), moosicd(1), http://nanoo.org/~daniel/moosic/
1296              
1297             =head1 AUTHOR
1298              
1299             Florian Ragwitz Erafl@debian.orgE
1300              
1301             =head1 COPYRIGHT AND LICENSE
1302              
1303             Copyright (C) 2004-2008 by Florian Ragwitz
1304              
1305             This library is free software; you can redistribute it and/or modify
1306             it under the same terms as Perl itself, either Perl version 5.8.4 or,
1307             at your option, any later version of Perl 5 you may have available.
1308              
1309             =cut