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; ### ### ########################### # # # main hash and array # # # ########################### ### ### my %things = ( 'help' => sub { print curti(), " - Commands: parse, find, time, exit\n" }, 'find' => \&sql_finder, 'parse' => \&sql_writer, 'report' => \&super_report, 'time' => sub { print curti(), "\n" } ); my @fields = ( 'number', 'series', 'season', 'station', 'company', # why is @fields out here? 'airtime', # well billy, I just don't 'eta', # know~! :) :P ;) xD <3 :3 'eps', 'links' ); ### ### ############################ # # # 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 = ); } ### ### ######################## # # # core subroutines # # # ######################## ### ### # # # # # # # # # # # # # # 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; } # # # # # # # # # # # # 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 the showtime hash from pk info of mahou_data (anime title) # code this ;-) }; if($@) { print curti(), " Database error.\n"; } $dbh->disconnect; } sub check_meta { print curti(), " Checking meta...\n"; my @delta = parti(shift); # first: hour is same, minutes > 15 # second: hour is + 1, minutes < 45 if ($delta[0] == 0 and $delta[1] > 15) { print curti(), " Hit!\n"; return 1; } elsif ($delta[0] == 1 and $delta[1] < 45) { print curti(), " Hit!\n"; return 1; } print curti(), " Miss!\n"; return 0; } sub get_meta { my $dbh = DBI->connect( 'dbi:SQLite:dbname=mahou.db',undef,undef, { RaiseError => 1, AutoCommit => 0 } ); my $hit; eval { # get meta from db my @meta = $dbh->selectrow_array('SELECT * from meta_data'); # delete old meta, replace with new $dbh->do('DELETE FROM meta_data'); my $sth = $dbh->prepare('INSERT INTO meta_data values(?,?,?)'); $hit = check_meta($meta[2]); $hit ? ++$meta[0] : ++$meta[1]; $meta[2] = curti(); $sth->execute(@meta); $dbh->commit; }; if($@) { print curti(), " Metatable error.\n"; $dbh->rollback; } print curti(), " Meta check complete.\n"; $dbh->disconnect; return $hit; } # # # # # # # # # # # # # # # # # # # core sql search/writer thingies # # # # # # # # # # # # # # # # # # # sub sql_finder { # set need stuff, check metadata my ($hit,$search,@data) = (get_meta(),shift,()); # got a hit? PARSE IT! if ($hit) { # this was the best line, left it for awesomeness # $dbh->disconnect; # ugh, sqlite sql_writer(); } # connect to db, finally my $dbh = DBI->connect( 'dbi:SQLite:dbname=mahou.db',undef,undef, { RaiseError => 1, AutoCommit => 0 } ); eval { # 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(@data) { print curti(), " Data:\n"; print " $_\n" foreach @data; } print curti(), " Search done.\n"; }; if($@) { print curti(), " Search error.\n"; } $dbh->disconnect; } sub sql_writer { # grab hash from parser and connect to db my $hash = core_parse(); print curti(), " Starting write.\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 foreach my $anime (sort keys %{$hash}) { $sth->execute($anime,@{[ map { $hash->{$anime}{$_} } ('link','station','airtime','eta') ]}); } $dbh->commit; }; if($@) { $dbh->rollback; print curti(), " Error.\n"; } $dbh->disconnect; print curti(), " Database closed.\n"; } # # # # # # # # # # # # # # # # # 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(), " Starting parser.\n"; my ($html,%showtime) = (HTML::TreeBuilder->new_from_file("Showtime.htm"),{}); # first step: find time table my $table = $html->look_down( '_tag', 'table', 'bgcolor', '#bfa89b', sub { table_header_has($_[0], "ETA") }, sub { not table_header_has($_[0], "Starting") } ); # second step: find ACTUAL time table foreach my $anime ($table->look_down( '_tag', 'tr', 'align', undef, # skip first 'bgcolor', '#e9dfdb') ){ # first: get the name, for LINK: stays as hash; pc486! # second: get the ^^ 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 } (3,5,6); } $html->delete; return \%showtime; } # # # # # # # # # # # # # stuff for the idler # # # # # # # # # # # # # sub super_report { my %showtime = build_hash(); if (2 == 1) { 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 report function has yet to be implemented.\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'); } # # # # # # # # # # # # cutie subroutines # # # # # # # # # # # # sub parti { my @parti; push(@parti,shift); my @curti; push(@curti,curti()); map { @$_ = split(/:/,$_->[0]) } (\@parti,\@curti); my @delta = map { $curti[$_] - $parti[$_] } (0,1,2); return @delta; } # parses the 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!