| 243 | | # NOTE: ideally a grabber could be instructed to fetch partial data through --channel, --starttime & --endtime |
| 244 | | # we don't have that for now so instead whenever there is missing data, ALL 7 days for all channels will be collected |
| 245 | | # FIXME FUTURE: call grabbers just with what we want... |
| 246 | | $comm .= " --days $days" if ($days); |
| 247 | | $comm .= " --offset $opt->{offset}" if ($opt->{offset}); |
| | 244 | # Category 1 grabbers (i.e. slow ones) are requested to only fetch the timeslice |
| | 245 | # that we need. Category 2 grabbers are requested to get everything, since there's |
| | 246 | # very little cost in grabbing that extra data, and we can use it in the reconciler |
| | 247 | # to verify that everything looks OK. |
| | 248 | if ($components->{$grabber}->{config}->{category} == 1) |
| | 249 | { |
| | 250 | print "CAT1 grabber: grabbing timeslice.\n"; |
| | 251 | if ($timeslice->{start} != 1) |
| | 252 | { |
| | 253 | $comm .= " " . |
| | 254 | $components->{$grabber}->{config}->{option_offset} . |
| | 255 | " " . |
| | 256 | ($timeslice->{start} - 1); |
| | 257 | } |
| | 258 | |
| | 259 | my $n = $timeslice->{stop}; |
| | 260 | if ($timeslice->{start} != 1 |
| | 261 | and |
| | 262 | !$components->{$grabber}->{config}->{option_offset_eats_days}) |
| | 263 | { |
| | 264 | $n -= $timeslice->{start}; |
| | 265 | } |
| | 266 | $comm .= " " . |
| | 267 | $components->{$grabber}->{config}->{option_days} . |
| | 268 | " " . |
| | 269 | $n; |
| | 270 | |
| | 271 | # Write a temporary channels file specifying only the channels we want |
| | 272 | my $tmpchans; |
| | 273 | foreach (@{$timeslice->{chans}}) |
| | 274 | { |
| | 275 | $tmpchans->{$_} = $channels->{$_}; |
| | 276 | } |
| | 277 | my $tmpcf = "$CWD/channels.conf.tmp"; |
| | 278 | write_file($tmpcf, 'temporary channels', [ $tmpchans ], [ 'channels' ]); |
| | 279 | $comm .= " --channels_file $tmpcf"; |
| | 280 | } |
| | 281 | else |
| | 282 | { |
| | 283 | $comm .= " --days $days" if ($days); |
| | 284 | $comm .= " --offset $opt->{offset}" if ($opt->{offset}); |
| | 285 | $comm .= " --channels_file $channels_file"; |
| | 286 | } |
| 333 | | delete $gscore->{$_}; |
| 334 | | print "Selected $_.\n" if ($debug); |
| 335 | | return $_; |
| 336 | | } |
| 337 | | $c += $gscore->{$_}; |
| | 383 | delete $gscore->{$grabber}; |
| | 384 | print "Selected $grabber.\n" if ($debug); |
| | 385 | if ($grabber =~ /(.*) \[cache\]/) |
| | 386 | { |
| | 387 | return $1; |
| | 388 | } |
| | 389 | else |
| | 390 | { |
| | 391 | if ($components->{$grabber}->{config}->{category} == 2) |
| | 392 | { |
| | 393 | # We might want to run C1 grabbers multiple times |
| | 394 | # to grab various timeslices, but not C2 grabbers, |
| | 395 | # which should get everything at once. |
| | 396 | delete $gscore->{$grabber}; |
| | 397 | } |
| | 398 | return $grabber; |
| | 399 | } |
| | 400 | } |
| | 401 | $c += $gscore->{$grabber}; |
| 356 | | my ($ch, $day) = split(/:/); |
| 357 | | my $result = (can_support_channel($grabber, $ch) |
| 358 | | and |
| 359 | | can_support_day($grabber, $day)); |
| 360 | | $hits += $result; |
| 361 | | # print "$grabber vs $ch:$day: " . ($result ? "OK" : "no") . "\n"; |
| 362 | | } |
| 363 | | $niceness = $components->{$grabber}->{config}->{niceness}; |
| 364 | | unless ($niceness) |
| | 440 | $hits = find_cache_hits($1, $missing); |
| | 441 | $cat = 2; |
| | 442 | $dq = $components->{$1}->{config}->{quality}; |
| | 443 | } |
| | 444 | else |
| 366 | | print "WARNING: Grabber $grabber has no niceness support " . |
| 367 | | "specified in config.\n"; |
| 368 | | $niceness = 5; |
| 369 | | } |
| 370 | | $granularity = $components->{$grabber}->{config}->{granularity}; |
| 371 | | unless (defined $granularity) |
| 372 | | { |
| 373 | | print "WARNING: Grabber $grabber has no granularity support " . |
| 374 | | "specified in config.\n"; |
| 375 | | $granularity = ''; |
| 376 | | } |
| 377 | | # TODO: use granularity more intelligently ('c' vs 'd') -- Max. |
| 378 | | $granularity = length ($granularity); |
| 379 | | my $total_channeldays = $days * scalar (keys %$channels); |
| 380 | | $granularity *= int((($total_channeldays - 1 ) / scalar(@$missing))/2); |
| 381 | | |
| 382 | | $score = $hits * ($niceness + $granularity); |
| 383 | | print "Grabber $grabber can fill $hits empty slots with $niceness niceness and $granularity granularity: scoring $score pts.\n"; |
| | 446 | my $key = $missing; |
| | 447 | if ($components->{$grabber}->{config}->{category} == 1) |
| | 448 | { |
| | 449 | $key = $missing_slice; |
| | 450 | } |
| | 451 | foreach my $day (sort keys %$key) |
| | 452 | { |
| | 453 | my $val = supports_day($grabber, $day); |
| | 454 | next unless ($val); |
| | 455 | print "Day $day:"; |
| | 456 | foreach my $ch (@{$key->{$day}}) |
| | 457 | { |
| | 458 | if (supports_channel($grabber, $ch)) |
| | 459 | { |
| | 460 | print " $ch"; |
| | 461 | $hits += $val; |
| | 462 | } |
| | 463 | } |
| | 464 | print "\n"; |
| | 465 | $hits = 1 if ($hits > 0 and $hits < 1); |
| | 466 | |
| | 467 | $cat = $components->{$grabber}->{config}->{category}; |
| | 468 | unless ($cat) |
| | 469 | { |
| | 470 | print "WARNING: Grabber $grabber has no category support ". |
| | 471 | "in config.\n"; |
| | 472 | $cat = 1; |
| | 473 | } |
| | 474 | |
| | 475 | $dq = $components->{$grabber}->{config}->{quality}; |
| | 476 | unless ($dq) |
| | 477 | { |
| | 478 | print "WARNING: Grabber $grabber has no quality support ". |
| | 479 | "in config.\n"; |
| | 480 | $dq = 1; |
| | 481 | } |
| | 482 | } |
| | 483 | } |
| | 484 | $mult = 1; |
| | 485 | $mult++ if ($cat == 2); |
| | 486 | $mult *= 2 ** ($dq-1); |
| | 487 | |
| | 488 | $score = int($hits * $mult); |
| | 489 | print "Grabber $grabber can fill $hits slots with multiplier $mult (cat: $cat, dq: $dq): scoring $score pts.\n"; |
| 455 | | push (@missing, "$ch:$i"); |
| 456 | | } |
| 457 | | } |
| 458 | | |
| 459 | | } |
| 460 | | |
| 461 | | print "Need data for @missing.\n" if ($debug); |
| 462 | | return \@missing; |
| 463 | | } |
| 464 | | |
| | 562 | push @{$missing->{$day}}, $ch; |
| | 563 | } |
| | 564 | } |
| | 565 | |
| | 566 | } |
| | 567 | |
| | 568 | foreach my $day (keys %$missing) |
| | 569 | { |
| | 570 | $missing->{$day} = [ sort @{$missing->{$day}} ]; |
| | 571 | } |
| | 572 | |
| | 573 | if ($debug) |
| | 574 | { |
| | 575 | print "Need data for days " . join(", ", sort keys %$missing) . ".\n"; |
| | 576 | } |
| | 577 | return $missing; |
| | 578 | } |
| | 579 | |
| | 580 | sub calculate_best_timeslice |
| | 581 | { |
| | 582 | my $missing = shift; |
| | 583 | |
| | 584 | my ($overlap, $a); |
| | 585 | $timeslice = { 'chandays' => 0 }; |
| | 586 | foreach my $day (1 .. $days) |
| | 587 | { |
| | 588 | consider_slice($day, $day, @{$missing->{$day}}); |
| | 589 | $overlap = $missing->{$day}; |
| | 590 | foreach my $nextday (($day + 1) .. $days) |
| | 591 | { |
| | 592 | last unless ($missing->{$nextday}); |
| | 593 | $a = Algorithm::Diff::LCS($overlap, $missing->{$nextday}); |
| | 594 | # print "Overlap: " . Dumper($a); |
| | 595 | last unless ($a and @{$a}); |
| | 596 | consider_slice($day, $nextday, @{$a}); |
| | 597 | $overlap = $a; |
| | 598 | } |
| | 599 | } |
| | 600 | } |
| | 601 | |
| | 602 | sub consider_slice |
| | 603 | { |
| | 604 | my ($startday, $stopday, @chans) = @_; |
| | 605 | |
| | 606 | my $challenger = ($stopday - $startday + 1) * scalar(@chans); |
| | 607 | return unless ($challenger > $timeslice->{chandays}); |
| | 608 | |
| | 609 | # We have a winner! |
| | 610 | $timeslice->{start} = $startday; |
| | 611 | $timeslice->{stop} = $stopday; |
| | 612 | $timeslice->{chans} = [ @chans ]; |
| | 613 | $timeslice->{chandays} = $challenger; |
| | 614 | } |
| | 615 | |
| | 616 | sub create_missing_slice |
| | 617 | { |
| | 618 | my $ret; |
| | 619 | |
| | 620 | foreach my $day ($timeslice->{start} .. $timeslice->{stop}) |
| | 621 | { |
| | 622 | $ret->{$day} = [ @{$timeslice->{chans}} ]; |
| | 623 | } |
| | 624 | return $ret; |
| | 625 | } |
| 1262 | | open(CHAN, ">$channels_file") or die "cannot write to $channels_file: $!"; |
| 1263 | | print CHAN Data::Dumper->Dump([$channels], ["channels"]); |
| 1264 | | close CHAN; |
| 1265 | | print "Updated channels file $channels_file.\n" if ($debug); |
| | 1420 | write_file($channels_file, 'channels', [ $channels ], [ 'channels' ]); |
| | 1421 | } |
| | 1422 | |
| | 1423 | sub write_file |
| | 1424 | { |
| | 1425 | my ($fn, $name, $vars, $varnames) = @_; |
| | 1426 | open (FN, ">$fn") or die "Can't write to $name file $fn: $!"; |
| | 1427 | print FN Data::Dumper->Dump($vars, $varnames); |
| | 1428 | close FN; |
| | 1429 | print "Wrote $name file $fn.\n" if ($debug); |