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!