Perl Generation of .ics iCalendar File for FIFA World Cup 2010 Schedule
The code to generate the .ics iCalendar file is reproduced below. I can't make any guarantees as to whether it will compile on your rig; it has been tested on my openSUSE 11.2 box running Perl v5.10.0. In addition, you will need to install various cpan packages - these are clearly identified at the top of the listing in the use statements.
It's not my intention to provide line-by-line analysis in this instance due to the length of the code, but if there's anything you are unsure about, feel free to register on the site and leave a comment.
#!/usr/bin/perl
# routine to parse the FIFA World Cup 2010 fixtures list and create iCalendar file
# Copyright www.badzilla.co.uk
# Licence GPL. This program may be distributed as per the terms of GPL and all credits
# must be retained
#
# If you find this script useful, please consider a donation to help me fund my web presence
# and encourage me to develop more products to be placed under the terms of GPL
# To donate, go to http://www.badzilla.co.uk and click on the donation button
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
use warnings;
use strict;
use Data::ICal;
use Data::ICal::Entry::Event;
use Date::ICal;
use DateTime;
use Date::Calc qw(Add_Delta_DHMS);
use Time::HiRes;
my $splash = "Downloaded from http://www.badzilla.co.uk\n\n";
my $categories = "http://www.badzilla.co.uk;Sport;Football;FIFA World Cup 2010";
my $fixturedate = "";
my $round = "";
my $location = "";
my $team1 = "";
my $team2 = "";
my %events = ();
# main loop to process the individual scraped lines
while (<>) {
chomp($_);
# if the line contains a date it is a new fixture
if (/^(\w+) (\d{1,2}), 2010 @ (\d{2}):(\d{2})/) {
$fixturedate = sprintf("%02d,%02d,%02d,%02d", $1 eq "June" ? 6 : 7, $2, $3, $4);
# undefine the fixture information
undef $location;
undef $round;
undef $team1;
undef $team2;
} else {
if (!$round) {
$round = $_;
} elsif (!$location) {
s/at //;
$location = $_;
} elsif (!$team1) {
$team1 = $_;
} elsif (!$team2) {
$team2 = $_;
# now we have all the fixture information, create hash
my $key = sprintf("%s,%s,%s", $fixturedate, $round, $location);
# and save into a hash
$events{$key} = $team1 . " v " . $team2;
}
}
}
# create datestamp information
my @stamp = localtime();
my $dstamp = sprintf("%d%02d%02dT%02d%02d%02dZ",
$stamp[5] + 1900,
$stamp[4] + 1,
$stamp[3],
$stamp[2],
$stamp[1],
$stamp[0]);
# get the timezone information.
my $tz = DateTime::TimeZone->new(name => 'Europe/London');
# now loop through each of the hashes which represent a fixture each and create
# the events.
my $calendar = Data::ICal->new();
my $count = 0;
for my $k (keys %events) {
# get the respective date and time components and fixture information
my ($startmonth, $startday, $starthour, $startmin, $round, $location) = split(/,/, $k);
# now calculate the date time start point
my $startyear = 2010;
my $dt = DateTime->new(
year => $startyear,
month => $startmonth,
day => $startday,
hour => $starthour,
minute => $startmin,
second => 0, nanosecond => 0, time_zone => 'UTC');
my $offset = $tz->offset_for_datetime($dt);
# got the offset for the timezone so now apply to starttime
my $startsec;
($startyear, $startmonth, $startday, $starthour, $startmin, $startsec) =
Add_Delta_DHMS($startyear, $startmonth, $startday, $starthour,
$startmin, 0, 0, 0, 0, -$offset);
# and add 2 hours for the end of the game
my ($endyear, $endmonth, $endday, $endhour, $endmin, $endsec)
= Add_Delta_DHMS(2010, $startmonth, $startday, $starthour, $startmin, 0, 0, 2, 0, 0);
# create the event
my $event = Data::ICal::Entry::Event->new();
# set the UID
my @tm = localtime();
my $uid = sprintf("%d%02d%02d%02d%02d%02d%s%02d\@badzilla.co.uk",
$tm[5] + 1900, $tm[4] + 1, $tm[3], $tm[2],
$tm[1], $tm[0], scalar(Time::HiRes::gettimeofday()), $count);
$event->add_properties(
uid => $uid,
summary => "FIFA World Cup 2010: $round: $events{$k}",
description => $splash . "South Africa FIFA World Cup 2010\n\n$round\n$events{$k}" ,
categories => $categories,
location => $location,
dtstamp => $dstamp,
dtstart => Date::ICal->new(
year => $startyear,
month => $startmonth,
day => $startday,
hour => $starthour,
min => $startmin,
sec => 0,
offset => "+0000")->ical,
dtend => Date::ICal->new(
year => $endyear,
month => $endmonth,
day => $endday,
hour => $endhour,
min => $endmin,
sec => 0,
offset => "+0000")->ical,
);
$calendar->add_entry($event);
$count++;
}
$calendar->add_properties(
calscale => 'GREGORIAN',
method => 'PUBLISH',
'X-WR-CALNAME' => 'FIFA World Cup 2010'
);
print $calendar->as_string;To execute this script, we are going to use the screenscraper shell script from the previous exercise - at the end we pipe the output of the screenscraped fixtures into this script (called wc2010) and then redirect the output to a file called WorldCup2010.ics which is of course our iCalendar file.
#!/bin/sh
# URL to screenscrape
wc2010http='http://soccernet.espn.go.com/world-cup/fixtures?cc=5739&ver=global'
# Screenscrape
wget -q -O - $wc2010http | sed -n '/June 11, 2010 @ 15:00UK/,/Table/p' | sed 's/<[^>]*>//g;s/^[ \t]*//;/^$/d' | awk '$0 !~ /Table/ && $0 !~ /Home/ && $0 !~ /nbsp/ {print}' | ./wc2010 > WorldCup2010.ics