All pastes #587509 Raw Edit

v0.1.0-final (Stand Alone)

public text v1 · immutable
#587509 ·published 2007-06-24 17:14 UTC
rendered paste body
#!/usr/bin/perl -w

use LWP::Simple;         # start! I wouldn't copy
use HTML::TreeBuilder;   # anything seen in here,
use HTML::Entities;      # it's for your own good
use DBI;
use DBD::SQLite;
use strict;



 ###                     ###
 #####D#O#N#E###############
  #                       #
   # main hash and array #
  #                       #
 ###########################
 ###                     ###


my %things = (
  'help'   => sub { print curti(), " - Commands: create, parse, find, time, exit, report\n" },
  'find'   => \&sql_finder,
  'parse'  => \&sql_writer,
  'create' => \&sql_create,
  'time'   => sub { print curti(), " There you go.\n" },
  'report' => sub {
    my @rofl = split(/\s+/,shift);
    hash_report() and return if $rofl[0] =~ /hash/i;
    get_meta('reset',$rofl[1]) and return if $rofl[0] =~ /reset/i;
    meta_report() and return if $rofl[0] =~ /meta/i;
    print curti(), " Usage: report [ hash | meta | reset [ hh:mm:ss ] ]\n";
  }
);
my @fields = (
  'number',
  'series',    # why is @fields out here?
  'season',    # well billy, I just don't
  'station',   # know~! :) :P ;) xD <3 :3
  'company',
  'airtime',
  'eta',       # it's only used once, may
  'eps',       # as well ditch it soon :)
  'links'
);



 ###                      ###
 #####D#O#N#E################
  #                        #
   # heart of the progrum #
  #                        #
 ############################
 ###                      ###


my $subjex = intro();
while($subjex !~ /exit/io){
  foreach my $regex (sort keys %things) {
    if($subjex =~ /^\s*($regex)(?:\s*(.*))?/i) {
      $things{$1}->($2);
    }
  }
  print curti(), " > ";
  chomp($subjex = <STDIN>);
}



 ###                    ###
 #####D#O#N#E##############
  #                      #
   # spiffy subroutines #
  #                      #
 ##########################
 ###                    ###


   #D#O#N#E# # # # # # # # #
   # stuff for anidb links #
   # # # # # # # # # # # # #

sub anidb_link {  # makes pretty URLs
  my $url = shift;
  return '-' if !$url;
  $url = 'http://anidb.info/a' . $url;
  return $url;
}

sub anidb_id {  # return AIDs
  my $url = shift;
  $url =~ s/^http.*aid.(\d+)$/$1/i;
  return $url;
}


   #D#O#N#E# # # # # # #
   # sql stuff... ugh! #
   # # # # # # # # # # #

sub build_hash {
  my %showtime = {};
  my $dbh = DBI->connect(
    'dbi:SQLite:dbname=mahou.db',undef,undef,
    { RaiseError => 1, AutoCommit => 0 }
  );

  eval {
    # build hash from mahou_data...
    # someone should code this. ;-)
  };
  if($@) {
    print curti(), " Build hash: Database error.\n";
  }
  $dbh->disconnect;
  return 0;
}

sub check_meta {
  my $pop = pop; my @delta = parti($pop);
  print curti(), " \u$_[0]: Check meta: Checking: @delta\n";

  # first: same hour & no more than thirty minutes
  # second: one hour & no less than thirty minutes
  if (($delta[0] == 0 and $delta[1] <  30 and $delta[1] >= 0 ) or
      ($delta[0] == 1 and $delta[1] < -30 and $delta[1] <= 0 )) {

    print curti(), " \u$_[0]: Check meta: Miss!\n";
    return @{[ 0,$_[1],++$_[2],$pop ]};
  } else {

    print curti(),  " \u$_[0]: Check meta: Hit!\n";
    return @{[ 1,++$_[1],$_[2],curti() ]};
  }

  return curti(), " \u$_[0]: Check meta: Erroneous check: Replace coder.\n";
}

sub get_meta {
  # create db if it doesn't exist
  sql_create() unless -e 'mahou.db';

  # hash of params for the check
  my %type = (
    'query'  =>
      { 'return' => 0, 'update' => 1, 'reset' => 0 },
    'report' =>
      { 'return' => 1, 'update' => 0, 'reset' => 0 },
    'reset'  =>
      { 'return' => 1, 'update' => 0, 'reset' => 1 }
  ); # this wasn't completely needed;
     # it's here for scalability? ^^;


  my $dbh = DBI->connect(
    'dbi:SQLite:dbname=mahou.db',undef,undef,
    { RaiseError => 1, AutoCommit => 0 }
  );

  # check who sent for us
  my ($from,%return) = (shift,{});
  print curti(), " \u$from: Get meta: Using method:";
  foreach my $lol (keys %{$type{$from}}) {
    print " $lol" if $type{$from}->{$lol};
  } print "\n";

  eval {
    if ($type{$from}->{'reset'}) {
      $dbh->do('DELETE FROM meta_data');
      $dbh->do("INSERT INTO meta_data VALUES(0,0,'@{[ $_[0] ? $_[0] : q(12:00:00) ]}')");
      $dbh->commit;
      $return{'new'} = $_[0] ? shift : '12:00:00';
    }

    # get meta from db
    my @old = $dbh->selectrow_array('SELECT * from meta_data');
    print curti(), " \u$from: Get meta: Data from table: @old\n";

    if ($type{$from}->{'update'}) {
      # check and get new meta
      my ($hit,@new) = check_meta($from,@old);
      print curti(), " \u$from: Get meta: Removing old meta, inserting new meta.\n";

      # delete old meta
      $dbh->do('DELETE FROM meta_data');

      # insert and commit
      $dbh->do("INSERT INTO meta_data values($new[0],$new[1],'$new[2]')");
      $dbh->commit;

      $return{'new'} = [ @new ];
      $return{'hit'} = $hit;
      print curti(), " \u$from: Get meta: Meta updated, new meta: @{$return{'new'}}\n";
    }
    $return{'old'} = [ @old ];
  };

  if($@) {
    print curti(), " \u$from: Get meta: Database error.\n";
    $dbh->rollback;
  }
  $dbh->disconnect;

  # only send back what we need
  return $type{$from}->{'reset'} ? $return{'new'} : \@{$return{'old'}}
    if $type{$from}->{'return'};
  return $return{'hit'};
}


   #D#O#N#E# # # # # # # # # # # # # #
   # core sql search/writer thingies #
   # # # # # # # # # # # # # # # # # #

sub sql_finder {
  # set need stuff, check metadata
  my $search = shift; my @data;
  sql_writer() if get_meta('query');

  # connect to db, finally
  my $dbh = DBI->connect(
    'dbi:SQLite:dbname=mahou.db',undef,undef,
    { RaiseError => 1, AutoCommit => 0 }
  );

  eval {
    print curti(), " Sql finder: Starting search...\n";

    # search, first checks for aid, then defaults to name
    if($search =~ /^(?:ID:)?(\d+)$/) {
      @data = $dbh->selectrow_array("SELECT * from mahou_data WHERE aid = $1");
    } else {
      $search = '%' . $search . '%';
      my $sth = $dbh->prepare('SELECT * from mahou_data WHERE name like ?');
      $sth->execute($search);
      @data = $sth->fetchrow_array;
    }
  };
  if($@) {
    print curti(), " Sql finder: Database error.\n";
  }
  $dbh->disconnect;

  if(@data) {
    print curti(), " Sql finder: Adjusting time from: $data[4]\n";
    $data[4] = fixti($data[4]);
    print curti(), " Query Data:\n";
    print "          $_\n" foreach @data;
  } else {
    print curti(), " Query Data: No results.\n";
  }
}

sub sql_writer {
  print curti(), " Sql writer: Getting hash...\n";

  # grab hash from parser and connect to db
  my $hash = core_parse();
  print curti(), " Sql writer: Connecting and preparing insert.\n";

  my $dbh = DBI->connect(
    'dbi:SQLite:dbname=mahou.db',undef,undef,
    { RaiseError => 1, AutoCommit => 0 }
  );

  eval {
    # clear table, prepare insert
    $dbh->do('DELETE FROM mahou_data');
    my $sth = $dbh->prepare('INSERT INTO mahou_data values(?,?,?,?,?)');

    # insert
    print curti(), " Sql writer: Inserting rows.\n";
    foreach my $anime (sort keys %{$hash}) {
      $sth->execute($anime,@{[ map { $hash->{$anime}{$_} } ('link','station','airtime','eta') ]});
    }
    $dbh->commit;
  };
  if($@) {
    $dbh->rollback;
    print curti(), " Sql writer: Database error.\n";
  }

  $dbh->disconnect;
  print curti(), " Sql writer: Database updated.\n";
}

sub sql_create {
  print curti(), " Please create database file (mahou.db).\n";
  exit 0;
}


   #D#O#N#E# # # # # # # # # # # #
   # download, parse and related #
   # # # # # # # # # # # # # # # #

sub table_header_has {
  my ($table, $str) = @_;
  return defined $table->look_down(
    '_tag', 'th',
    sub { $_[0]->as_text() eq $str }
  );
} # by pc486

sub core_parse {
  # build tree, get shit from it ^-^
  print curti(), " Core parse: Starting parser...\n";
  my ($html,%showtime) = (get("http://mahou.org/Showtime"),{});
  $html = HTML::TreeBuilder->new_from_content($html);

  # first step: find time table
  print curti(), " Core parse: Searching for table...\n";
  my $table = $html->look_down(
    '_tag', 'table',
    'bgcolor', '#bfa89b',
    sub { table_header_has($_[0], "ETA") },
    sub { not table_header_has($_[0], "Starting") }
  ); # by pc486

  # second step: find ACTUAL time table
  print curti(), " Core parse: Constructing hash...\n";
  foreach my $anime ($table->look_down(
    '_tag', 'tr',
    'align', undef, # skip first <tr>
    'bgcolor', '#e9dfdb')
  ){

    # first: get the name, for LINK: stays as hash; pc486!
    # second: get the ^<RIGHT>^ link (which is kinda good)
    my $name = $anime->look_down('_tag', 'a', 'name', qr/\d+/)->parent();
    my $link = $name->parent()->look_down('_tag', 'a', 'href', qr/anidb/);

    # starts the hash (with an aid), then populates it with map
    $showtime{$name->as_text}->{'link'} = $link ? anidb_id($link->{'href'}) : undef;
    map { $showtime{$name->as_text}->{$fields[$_]} =
      @{[ $anime->look_down('_tag', 'td') ]}[$_]->as_text } qw(3 5 6);

  }

  $html->delete;
  print curti(), " Core parse: Returning hash to parent...\n";
  return \%showtime;
}


   #D#O#N#E# # # # # # # #
   # stuff for the idler #
   # # # # # # # # # # # #

sub meta_report {
  print curti(), " Meta report: Initializing...\n";
  my $meta = get_meta('report');
  print curti(), " Mahou Meta Report:\n",
    "              re-parse hits   -> @{[ $meta->[0] ]}\n",
    "              re-parse misses -> @{[ $meta->[1] ]}\n",
    "              time since last -> @{[ cheti(parti($meta->[2])) ]}\n";

}

sub intro {
  print ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::\n",
        ":::::::::                                                     :::::::::\n",
        ":::::::::      Welcome to the Mahou.org/Showtime parser!      :::::::::\n",
        ":::::::::                                                     :::::::::\n",
        ":::::::::         `Being dumb since 1823!`                    :::::::::\n",
        ":::::::::               `Or something.`             :::::::::::::::::::\n",
        ":::::::::                                           ::By: Dean_Kreger::\n",
        ":::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::\n";
  return('help');
}

 # I may do this if I get bored...
sub hash_report {
  my %showtime = {};
  my $lol = build_hash(); # returns zero
  if ($lol) {
    foreach my $anime (sort keys %showtime) {
      print "$anime <-<+>-> ", anidb_link($showtime{$anime}->{'link'}),
            "\n  Station -> ", $showtime{$anime}->{'station'},
            "\n  Airtime -> ", $showtime{$anime}->{'airtime'},
            "\n  ETA     -> ", $showtime{$anime}->{'eta'}, "\n\n";
    }
  }
  print curti(), " The hash report function has yet to be implemented.\n";
}


   #D#O#N#E# # # # # # # # # # # # #
   # cute time related subroutines #
   # # # # # # # # # # # # # # # # #

sub fixti {
  my @parti = (0,parti(@{get_meta('report')}->[2]));
  print curti(), " Fixti: \@parti: @parti\n";
  return shift unless $parti[2];
  my %fixti = (map { $_ => 0 - shift @parti } qw(d h m s));
  print curti(), " Fixti: \%fixti:"; print " $fixti{$_}" foreach sort keys %fixti; print "\n";
  map { $fixti{chop($_)} += $_ } @{[ split(/\s+/,shift) ]};
  ($fixti{'d'},$fixti{'h'},$fixti{'m'},$fixti{'s'}) = # better way to do this?
    fucti($fixti{'d'},$fixti{'h'},$fixti{'m'},$fixti{'s'});
  return "@{[ map { qq($fixti{$_}$_) } qw(d h m)]}";
} # fixes the time... DEAN'S WAY!

sub cheti {
  my $conti = shift;
  return "update already! it's been like a day or more" if $conti < 0;
  return "more than five hours... I think..." if $conti > 5;
  return "like... more than an hour, at least" if $conti > 1;
  return "pretty much less than an hour" if $conti <= 1;
  return "erroneous check; please replace coder";
} # checks the time... DEAN'S WAY! ... Sorta...


sub parti {
  my @parti; push(@parti,shift);
  my @curti; push(@curti,curti());
  print curti(), " Parti: Doing: @curti - @parti\n";
  map { @$_ = split(/:/,$_->[0]) } (\@parti,\@curti);
  return @{[ map { $curti[$_] - $parti[$_] } qw(0 1 2) ]};
} # parses the time... DEAN'S WAY!

sub fucti {
  my @time = @_;
  print curti(), " Fixti: Fucti: Old \@time: @time\n";
  --$time[2] and $time[3] += 60 if $time[3] <  0;
  ++$time[2] and $time[3] -= 60 if $time[3] > 60;
  --$time[1] and $time[2] += 60 if $time[2] <  0;
  ++$time[1] and $time[2] -= 60 if $time[2] > 60;
  --$time[0] and $time[1] += 24 if $time[1] <  0;
  ++$time[0] and $time[1] -= 24 if $time[1] > 24;
                 $time[0] +=  7 if $time[0] <  0;
  print curti(), " Fixti: Fucti: New \@time: @time\n";
  pop @time; return @time;
} # fuck time... ... ... DEAN'S WAY!

sub curti {
  my @time = @{[ gmtime ]}[2,1,0];
  $time[0] = $time[0]-3 < 0 ? $time[0]+9 : $time[0]-3;
  return sprintf('%02d:%02d:%02d', @time);
} # gets the time... DEAN'S WAY!