1# OnTV by Stefan'tommie' Tomanek 2 3use strict; 4use vars qw($VERSION %IRSSI); 5$VERSION = "20050226"; 6%IRSSI = ( 7 authors => "Stefan 'tommie' Tomanek", 8 contact => "stefan\@pico.ruhr.de", 9 name => "OnTV", 10 description => "turns irssi into a tv program guide", 11 license => "GPLv2", 12 modules => "Data::Dumper POSIX LWP::Simple HTML::Entities Text::Wrap", 13 changed => "$VERSION", 14 commands => "ontv" 15); 16 17use Irssi 20020324; 18use Data::Dumper; 19use POSIX; 20use LWP::Simple; 21use HTML::Entities; 22use Text::Wrap; 23 24use vars qw($forked @comp); 25 26sub show_help() { 27 my $help=$IRSSI{name}." ".$VERSION." 28/ontv (current) 29 List the current tv program 30/ontv search <query> 31 Query the program guide for a show 32/ontv next 33 Show what'S next on TV 34/ontv tonight 35 List tonight's program 36/ontv watching <station> 37 Display what's on <station> 38"; 39 my $text = ''; 40 foreach (split(/\n/, $help)) { 41 $_ =~ s/^\/(.*)$/%9\/$1%9/; 42 $text .= $_."\n"; 43 } 44 print CLIENTCRAP &draw_box($IRSSI{name}." help", $text, "help", 1) ; 45} 46 47sub draw_box ($$$$) { 48 my ($title, $text, $footer, $colour) = @_; 49 my $box = ''; 50 $box .= '%R,--[%n%9%U'.$title.'%U%9%R]%n'."\n"; 51 foreach (split(/\n/, $text)) { 52 $box .= '%R|%n '.$_."\n"; 53 } 54 $box .= '%R`--<%n'.$footer.'%R>->%n'; 55 $box =~ s/%.//g unless $colour; 56 return $box; 57} 58 59sub get_prog ($) { 60 my ($what) = @_; 61 my $url = 'http://www.tvmovie.de/tv-programm/jetzt.html?nocache=true'; 62 $url = 'http://www.tvmovie.de/tv-programm/gleich.html?nocache=true' if ($what == 0); 63 $url = 'http://www.tvmovie.de/tv-programm/2015.html' if ($what == 2); 64 my $data = get($url); 65 my $programs = []; 66 my %program; 67 foreach (split /\n/, $data) { 68 #print $_; 69 if (/class="linkgrau">(.*?)<\/a><\/font><\/td>/) { 70 $program{station} = $1; 71 decode_entities($program{station}); 72 } 73 #if (/<a href="http:\/\/www.tvmovie.de\/tv-programm\/sendung.html\?SendungID=(\d+)" class="linkblack"><b>(.*?)<\/b><\/a>/) { 74 if (/<a href="http:\/\/www.tvmovie.de\/tv-programm\/sendung.html\?SendungID=(\d+)" class="linkblack"><b>(.*?)<\/b>/) { 75 $program{id} = $1; 76 $program{title} = $2; 77 decode_entities($program{title}); 78 } 79 if (/<FONT face="Verdana, Arial, Helvetica, sans-serif" size="1" color="#757575"><br>(.*?)<\/font><\/font><\/td>/) { 80 $program{comment} = decode_entities($1); 81 } 82 if (/color='#ee0000'>(.*?)<\/font><\/td>/) { 83 $program{type} = decode_entities($1); 84 } 85 if (/color="white"><b>([A-Z]{2})<\/b><\/font><\/td>/) { 86 $program{day} = $1; 87 } 88 if (/size="1">(\d{2}\.\d{2}) <\/font><\/td>/) { 89 $program{begin} = $1; 90 decode_entities($program{begin}); 91 } 92 if (/size="1">bis (\d{2}\.\d{2})<\/font><\/td>/) { 93 $program{end} = $1; 94 decode_entities($program{end}); 95 my %data = %program; 96 push @$programs, \%data; 97 %program = (); 98 } 99 } 100 return $programs; 101} 102 103sub search_prog ($) { 104 my ($query) = @_; 105 encode_entities($query); 106 my $url = 'http://fernsehen.tvmovie.de/finder?finder=swsendung&tag=alle&sw_sendung='.$query; 107 my $data = get($url); 108 return( parse_search($data) ); 109} 110 111sub parse_search ($) { 112 my ($data) = @_; 113 my $programs = []; 114 my %program; 115 foreach (split /\n/, $data) { 116 if (/color="white"><b>([A-Z]{2})<\/b> <\/font><\/td>$/) { 117 $program{day} = $1; 118 decode_entities($program{day}); 119 } 120 if (/size="1">(\d{2}:\d{2})<\/font><\/td>$/) { 121 $program{begin} = $1; 122 decode_entities($program{begin}); 123 } elsif (/class="linkgrau">(.*?)<\/a><\/font><\/td>$/) { 124 $program{station} = $1; 125 decode_entities($program{station}); 126 } elsif (/<a href="http:\/\/www.tvmovie.de\/tv-programm\/sendung\.html\?SendungID=(\d+)" class="linkblack"><b>(.*?)<\/b><\/a><\/font>(?:<FONT face="Verdana, Arial, Helvetica, sans-serif" size="1" color="#757575"><br>(.*?)<\/font>)?/) { 127 $program{id} = $1; 128 $program{title} = $2; 129 $program{comment} = $3; 130 decode_entities($program{title}); 131 decode_entities($program{comment}); 132 #} elsif (/{ \t]*<td valign="top" align="left">$/) { 133 my %data = %program; 134 push @$programs, \%data; 135 } 136 } 137 return $programs; 138} 139 140sub get_info ($) { 141 my ($id) = @_; 142 my $data = get('http://www.tvmovie.de/tv-programm/sendung.html?SendungID='.$id); 143 my %info; 144 foreach (split(/\n/, $data)) { 145 #print; 146 if (/size="3"><b>(.*?)<\/b><br><\/font>$/) { 147 $info{title} = decode_entities($1); 148 } elsif (/color="#FFFFFF"><b> (\d+\.\d+\.\d+) \|/) { 149 $info{date} = decode_entities($1); 150 } elsif (/size="1"><b>(.*?)<\/b><br><br><\/font>$/) { 151 $info{comment} = decode_entities($1); 152 } elsif (/class="uppercase"><b>(.*?)<\/b> <\/font>/) { 153 $info{type} = decode_entities($1); 154 } elsif (/<FONT face="Verdana, Arial, Helvetica, sans-serif" size="1">(.*?)<br><br><\/font>/) { 155 $info{desc} = decode_entities($1); 156 } elsif (/\[Sender: (.*?)\] \[Beginn: (.*?)\] \[Dauer: (.*?) Min\.\] \[Ende: (.*?)\] \[SV: (.*?)\]/) { 157 $info{station} = decode_entities($1); 158 $info{begin} = decode_entities($2); 159 $info{end} = decode_entities($4); 160 $info{showview} = decode_entities($5); 161 } 162 } 163 my $stat = $info{station}; 164 $info{desc} =~ s/$stat$//; 165 #$info{desc} =~ s/<br><br>$//; 166 $info{desc} =~ s/<br>/\n/g; 167 return \%info; 168} 169 170sub bg_fetch ($$) { 171 my ($op, $query) = @_; 172 my ($rh, $wh); 173 pipe($rh, $wh); 174 if ($forked) { 175 print CLIENTCRAP "%R>>%n Please wait until your earlier request has been finished."; 176 return; 177 } 178 my $pid = fork(); 179 $forked = 1; 180 if ($pid > 0) { 181 print CLIENTCRAP "%R>>%n Please wait..."; 182 close $wh; 183 Irssi::pidwait_add($pid); 184 my $pipetag; 185 my @args = ($rh, \$pipetag, $op, $query); 186 $pipetag = Irssi::input_add(fileno($rh), INPUT_READ, \&pipe_input, \@args); 187 } else { 188 my $result = {}; 189 my @program; 190 my $stations = Irssi::settings_get_str('ontv_stations'); 191 eval { 192 if ($op eq 'current') { 193 @program = @{ get_prog(1) }; 194 foreach (@program) { 195 push @{ $result->{program} }, $_ if ($_->{station} =~ /^($stations)$/); 196 } 197 } elsif ($op eq 'next') { 198 @program = @{ get_prog(0) }; 199 foreach (@program) { 200 push @{ $result->{program} }, $_ if ($_->{station} =~ /^($stations)$/); 201 } 202 } elsif ($op eq 'tonight') { 203 @program = @{ get_prog(2) }; 204 foreach (@program) { 205 push @{ $result->{program} }, $_ if ($_->{station} =~ /^($stations)$/); 206 } 207 } elsif ($op eq 'search') { 208 @program = @{ search_prog($query) }; 209 foreach (@program) { 210 push @{ $result->{program} }, $_ if ($_->{station} =~ /^($stations)$/); 211 } 212 } elsif ($op eq 'watching') { 213 @program = @{ get_prog(1) }; 214 foreach (@program) { 215 next unless ($_->{station} =~ /^($query)$/); 216 push @{ $result->{program} }, $_; 217 print $_->{id}; 218 $result->{info} = get_info($_->{id}); 219 } 220 } elsif ($op eq 'info') { 221 $result->{info} = get_info($query); 222 } 223 my $dumper = Data::Dumper->new([$result]); 224 $dumper->Purity(1)->Deepcopy(1)->Indent(0); 225 print($wh $dumper->Dump); 226 }; 227 close $wh; 228 POSIX::_exit(1); 229 } 230} 231 232sub pipe_input ($) { 233 my ($rh, $pipetag, $op, $args) = @{$_[0]}; 234 $forked = 0; 235 Irssi::input_remove($$pipetag); 236 my $text; 237 $text .= $_ foreach <$rh>; 238 no strict 'vars'; 239 my $incoming = eval("$text"); 240 return unless ($incoming->{program} || $incoming->{info}); 241 print_prog($incoming->{program}, 'current') if ($op eq 'current'); 242 print_prog($incoming->{program}, 'next') if ($op eq 'next'); 243 print_prog($incoming->{program}, 'tonight') if ($op eq 'tonight'); 244 print_prog($incoming->{program}, 'query: "'.$args.'"') if ($op eq 'search'); 245 print_prog($incoming->{program}, 'current: "'.$args.'"') if ($op eq 'watching'); 246 print_info($incoming->{info}) if $incoming->{info}; 247} 248 249sub print_info ($) { 250 my ($info) = @_; 251 my $text; 252 $text .= '%9'.$info->{title}.'%9'."\n"; 253 $text .= $info->{date}.': '.$info->{begin}."-".$info->{end}."\n"; 254 $text .= 'Showview: '.$info->{showview}."\n\n"; 255 $text .= $info->{comment}."\n\n"; 256 $text .= $info->{desc}; 257 my $col = int( Irssi::active_win()->{width}*(2/3) ); 258 $Text::Wrap::columns = $col; 259 my $article = wrap("", "", $text); 260 print CLIENTCRAP &draw_box('OnTV', $article, $info->{title}, 1); 261} 262 263sub print_prog ($$) { 264 my ($program, $query) = @_; 265 @comp = @$program; 266 my $text; 267 foreach (@$program) { 268 $text .= "%9".$_->{station}."%9:"; 269 $text .= " %U".$_->{title}."%U"; 270 $text .= " [".$_->{type}."]"if $_->{type}; 271 $text .= " (".$_->{id}.")\n"; 272 $text .= " >".$_->{comment}."<\n" if $_->{comment}; 273 $text .= " time: "; 274 $text .= $_->{day}.", "; 275 $text .= $_->{begin}; 276 $text .= "-".$_->{end} if $_->{end}; 277 $text .= "\n"; 278 #$text .= "\n"; 279 } 280 print CLIENTCRAP &draw_box('OnTV', $text, $query, 1); 281} 282 283sub sig_complete_word ($$$$$) { 284 my ($list, $window, $word, $linestart, $want_space) = @_; 285 return unless $linestart =~ /^.ontv (info)/; 286 foreach (@comp) { 287 push @$list, $_->{id} if ($_->{id} =~ /^(\Q$word\E.*)?$/); 288 push @$list, $_->{station} if ($_->{station} =~ /^(\Q$word\E.*)?$/); 289 push @$list, $_->{title} if ($_->{title} =~ /^(\Q$word\E.*)?$/); 290 } 291 Irssi::signal_stop(); 292} 293 294 295sub cmd_ontv ($$$) { 296 my ($args, $server, $witem) = @_; 297 my @arg = split(/ /, $args); 298 if (scalar(@arg) == 0 || $arg[0] eq 'current') { 299 bg_fetch('current', ''); 300 } elsif ($arg[0] eq 'next') { 301 bg_fetch('next', ''); 302 } elsif ($arg[0] eq 'tonight') { 303 bg_fetch('tonight', ''); 304 } elsif ($arg[0] eq 'search') { 305 shift @arg; 306 bg_fetch('search', join(' ', @arg)) 307 } elsif ($arg[0] eq 'watching' && defined $arg[1]) { 308 shift @arg; 309 bg_fetch('watching', join(' ', @arg)); 310 } elsif ($arg[0] eq 'info' && defined $arg[1]) { 311 shift @arg; 312 my $query = join(' ', @arg); 313 unless ($query =~ /^\d+$/) { 314 foreach (@comp) { 315 if ($_->{title} eq $query || $_->{station} eq $query) { 316 $query = $_->{id}; 317 last; 318 } 319 } 320 } 321 bg_fetch('info', $query); 322 } elsif ($arg[0] eq 'help') { 323 show_help(); 324 } 325} 326 327Irssi::settings_add_str($IRSSI{name}, 'ontv_stations', '.*' ); 328 329Irssi::command_bind('ontv' => \&cmd_ontv); 330 331Irssi::signal_add_first('complete word', \&sig_complete_word); 332 333foreach my $cmd ('search', 'current', 'next', 'tonight', 'watching', 'help', 'info') { 334 Irssi::command_bind('ontv '.$cmd => 335 sub { cmd_ontv("$cmd ".$_[0], $_[1], $_[2]); } ); 336} 337 338 339print CLIENTCRAP '%B>>%n '.$IRSSI{name}.' '.$VERSION.' loaded: /ontv help for help'; 340