File Coverage

blib/lib/Roku/RCP.pm
Criterion Covered Total %
statement 15 146 10.2
branch 0 70 0.0
condition 0 39 0.0
subroutine 5 20 25.0
pod 9 13 69.2
total 29 288 10.0


line stmt bran cond sub pod time code
1             # Roku::RCP.pm
2             #
3             # Copyright (c) 2007 Robert J Powers . All rights reserved.
4             # This program is free software; you can redistribute it and/or modify it
5             # under the same terms as Perl itself.
6              
7             package Roku::RCP;
8              
9 1     1   44571 use strict;
  1         4  
  1         210  
10              
11 1     1   2115 use Net::Cmd;
  1         11618  
  1         463  
12 1     1   2545 use IO::Socket::INET;
  1         30289  
  1         8  
13 1     1   618 use vars qw(@ISA $VERSION);
  1         2  
  1         981  
14              
15             $VERSION = '0.08';
16             @ISA = qw(Net::Cmd IO::Socket::INET);
17              
18             our %MetaData = ('TransactionInitiated' => 1, #Start of results
19             'ListResultSize' => 1,
20             'ListResultEnd' => 2, #End of results
21             'TransactionComplete' => 2,
22             );
23             sub new
24             {
25 0     0 1   my $self = shift;
26 0   0       my $class = ref($self) || $self;
27 0           my ($host, %args);
28 0 0         $host = shift if (scalar(@_) % 2);
29 0           %args = @_;
30              
31 0 0         $args{Host} = $host if $host;
32 0 0         $args{Timeout} = 60 unless defined $args{Timeout};
33              
34 0 0         return undef unless $args{Host};
35              
36 0   0       $self = $class->SUPER::new(PeerAddr => $args{Host},
37             PeerPort => $args{Port} || '5555',
38             Proto => 'tcp',
39             Timeout => $args{Timeout});
40            
41 0 0         return undef unless defined $self;
42 0           $self->debug($args{Debug});
43 0           ${*$self}{'_RawResults'} = $args{RawResults};
  0            
44              
45 0           $self->autoflush(1);
46              
47 0 0         if (!$self->response("ready")) {
48 0           $self->close();
49 0           return undef;
50             }
51              
52             ### if ($args{AutoRPC} && !$self->command('rcp')->response("ready")) {
53              
54 0           return bless $self, $class;
55             }
56              
57             sub unRaw
58             {
59 0     0 0   my $self = shift;
60 0           my $raw = ${*$self}{'_RawResults'};
  0            
61 0           ${*$self}{'_RawResults'} = 0;
  0            
62 0           return $raw;
63             }
64              
65             sub ServerConnectByName
66             {
67 0     0 1   my ($self, $name) = @_;
68 0           my (@servers, $i, $raw);
69 0 0         return undef unless $name;
70 0           $self->ServerDisconnect();
71              
72 0           $raw = $self->unRaw();
73 0           @servers = $self->ListServers();
74 0           ${*$self}{'_RawResults'} = $raw;
  0            
75            
76 0           foreach $i (0..$#servers) {
77 0 0         if ($servers[$i] =~ m/$name/i) {
78 0           $self->myLog("Attempting to connect to $servers[$i]: $i");
79 0           return ($self->ServerConnect($i));
80 0           return undef;
81             }
82             }
83 0           $self->myLog("No matching server found for $name");
84 0           return undef;
85             }
86              
87             sub PlayPlaylist
88             {
89 0     0 0   my ($self, $name) = @_;
90 0           my $raw = $self->unRaw();
91 0           my @plists = $self->ListPlaylists();
92 0           my $i;
93 0           ${*$self}{'_RawResults'} = $raw;
  0            
94 0           foreach $i (0..$#plists) {
95 0 0         if ($plists[$i] =~ m/$name/i) {
96 0           $self->myLog("Attempting to queue and play $plists[$i]: $i");
97 0           $self->SetListResultType("partial");
98 0           $self->ListPlaylistSongs($i);
99 0           return $self->QueueAndPlay(0);
100             }
101             }
102 0           $self->myLog("No matching playlist found for $name");
103 0           return undef;
104             }
105              
106             sub Standby
107             {
108 0     0 1   my $self = shift;
109 0           return $self->IrDispatchCommand('CK_POWER_OFF');
110             }
111              
112             sub PlayArtist
113             {
114 0     0 1   my ($self, $name) = @_;
115              
116 0           $self->myLog("Attempting to queue and play artist $name");
117 0 0         $self->SetListResultType("partial") or return undef;
118 0 0         $self->SetBrowseFilterArtist($name) or return undef;
119 0 0         $self->ListSongs() or return undef;
120 0           return $self->QueueAndPlay(0);
121             }
122              
123             sub PlayAlbum
124             {
125 0     0 1   my ($self, $name) = @_;
126              
127 0           $self->myLog("Attempting to queue and play album $name");
128 0 0         $self->SetListResultType("partial") or return undef;
129 0 0         $self->SetBrowseFilterAlbum($name) or return undef;
130 0 0         $self->ListSongs() or return undef;
131 0           return $self->QueueAndPlay(0);
132             }
133              
134             sub PlaySong
135             {
136 0     0 1   my ($self, $name) = @_;
137              
138 0           $self->myLog("Attempting to queue and play song $name");
139 0 0         $self->SetListResultType("partial") or return undef;
140 0 0         $self->SearchSongs($name) or return undef;
141 0           return $self->QueueAndPlay(0);
142             }
143              
144             sub InsertSong
145             {
146 0     0 1   my ($self, $name, $position) = @_;
147 0 0         $position = 1 unless defined $position;
148              
149 0           $self->myLog("Attempting to search for songs matching $name and insert them into Queue at position $position");
150 0 0         $self->SearchSongs($name) or return undef;
151 0           return $self->NowPlayingInsert("all", $position);
152             }
153              
154             sub AUTOLOAD
155             {
156 0     0     my $self = shift;
157 0           my $rcp_cmd;
158 1     1   6 use vars qw($AUTOLOAD);
  1         2  
  1         754  
159 0 0         if ($AUTOLOAD =~ m/::([^:]+)$/o) {
160 0           $rcp_cmd = $1;
161 0           $self->myLog("Issuing: $AUTOLOAD @_");
162 0           return $self->command($rcp_cmd,@_)->response(undef, $AUTOLOAD);
163             }
164 0           return undef;
165             }
166              
167             sub Quit
168             {
169 0     0 1   my $self = shift;
170 0           $self->command("exit");
171 0           $self->close;
172             }
173              
174             sub DESTROY
175             {
176 0     0     my $self = shift;
177              
178 0 0         $self->Quit if (defined fileno($self));
179             }
180              
181             sub isMeta
182             {
183 0     0 0   my ($self, $line) = @_;
184 0 0         return 0 unless $line;
185 0 0         return 0 unless $line =~ m/^(\S+)/o;
186 0           $line = $1;
187 0 0         return 1 if $MetaData{$line};
188 0           return 0;
189             }
190              
191             sub myLog
192             {
193 0     0 0   my $self = shift;
194 0 0         return unless ($self->debug);
195 0           $self->debug_print(0, join("\n", @_) . "\n");
196             }
197              
198             sub response
199             {
200 0     0 1   my $self = shift;
201 0           my $prompt = shift;
202 0   0       my $cmd = shift || "";
203 0           my (@result, $line, $async, $nResults);
204              
205 0           $self->timeout(0.65);
206 0           $async = 0;
207              
208 0           while (1) {
209 0           $line = $self->getline();
210 0           $line =~ s/[\r\n]//og;
211              
212 0 0         if (index($line, "TransactionInitiated") >= 0) {
213 0           $async = 1;
214 0           $self->myLog("Setting async to true");
215             }
216              
217 0 0 0       if (!$line && ${*$self}{'net_cmd_partial'}) {
  0            
218 0           $line = ${*$self}{'net_cmd_partial'};
  0            
219 0           ${*$self}{'net_cmd_partial'} = "";
  0            
220             }
221 0 0         $nResults = $1 if ($line =~ m/ListResultSize (\d+)/o);
222              
223 0 0 0       $self->myLog("Disconnected"), return undef if (!$line && !defined(fileno($self)));
224 0           $line =~ s/^[^:]+: //om;
225 0 0 0       push @result, $line if ($line && (${*$self}{'_RawResults'} || !$self->isMeta($line)));
      0        
226             #$self->debug_print(0, "From wire: $line\n") if ($self->debug);
227 0 0 0       last if ((!defined $line && !$async && scalar @result) ||
      0        
      0        
      0        
      0        
228             ($prompt && index($line, $prompt) >= 0) ||
229             (index($line, "TransactionComplete") == 0));
230             }
231              
232 0           $self->myLog("For cmd $cmd: got: ", @result);
233              
234 0 0 0       if (defined $nResults && $nResults == 0) {
235 0           $self->myLog("Got back empty list");
236 0           return undef;
237             }
238              
239 0 0 0       if (index($result[$#result], "Error") < 0 &&
240             index($result[$#result], "UnknownCommand") < 0) {
241             #index($result[$#result], $prompt) >= 0 ||
242             # index($result[$#result], "TransactionComplete") >= 0) {
243 0 0         push @result, "OK" unless scalar @result;
244 0           $self->myLog("For cmd $cmd: returning: ", @result);
245 0 0         return wantarray ? @result : join("\n", @result);
246             }
247 0           $self->myLog("Returning undef because of result: $result[$#result]");
248 0           return undef;
249             }
250              
251             1;
252              
253             __END__