Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/perl
- # funswap.pl
- # EDIT: modified by Calvin,
- # Changes include:
- # -changed $weekStart, starting date of semester (now works for 12s2)
- # -changed $OUTFILE, output file name to timetable12s2.ics
- # -changed $weekBeforeBreak
- #
- # written by Rowan Katekar ([email protected])
- # released under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
- # http://creativecommons.org/licenses/by-nc-sa/3.0/
- # USAGE SUGGESTION:
- # When importing into google calendar, create a special calendar just for this timetable.
- # That way, if something goes wrong you can delete the events from the calendar all at once, rather
- # than having to delete them one by one.
- # uses DateTime module - install from cpan using
- # sudo apt-get install libdatetime-perl
- # reads in UNSW timetable html file
- # outputs .ics file for importing into Outlook, Evolution, Google Calendar, ... etc.
- # assumes UNSW timetable html file is in the same folder as the perl script and called "timetable.html"
- ## Edited by William Pickering (@YodaDaCoda)
- ## * Changed from cat timetable.html (linux only file handling) to native perl file handling.
- ## Solves problems with things being printed to the terminal and generally not working
- ## properly on Windows.
- ## * Changed date logic
- ## Every single class was set to be on the next week from the previous class,
- ## leading to classes being held years into the future.
- # updated by Rowan Katekar again on 11-12-2011
- # * Changed dates to semester 1 2012 dates.
- # * Also changed the lecture name to the code of the subject
- # * Subject title is now part of the description
- use DateTime;
- # convert time of the format /(\d)?\d:\d\d[AP]M/ to a number from 0..23
- sub conv24($);
- # convert a weekday abbreviation to a number from 1-5
- sub dayToNumber($);
- # substitutes event values into iCal string & returns resultant string
- sub subInValues($$$$$);
- ## Gets the minutes of a specified time string.
- sub getMins($);
- # First day of semester (currently set to first day of semester for 2012 semester 1)
- $weekStart = DateTime->new( year=>2012, month=>7, day=>16, time_zone => 'Australia/Sydney' );
- # Last week before mid-semester break
- $weekBeforeBreak = 7;
- # destination of ical file
- $OUTFILE = "timetable12s2.ics";
- # file to read from
- $INFILE = "timetable.html";
- # crap to ignore
- @ignore = ("Teaching", "Status", "Enrolled", "Units", "Campus", "Activity", "Section",
- "Weeks", "Location", "Instructor", "bsdsSequence", "outerTable", "Key",
- "printBt", "Print", "onClick", "Site Map", "Site Feedback", "Privacy Statement",
- "Provider", "Copyright");
- ##open files for reading/writing
- open OUTFILE, ">", $OUTFILE or die $!;
- open INFILE, "<", $INFILE or die $!;
- # read in page
- @lines = <INFILE>;
- close INFILE;
- ##convert from array to one long string
- $page = join (' ', @lines);
- # split into sections based on subject
- @sections = split (/([A-Z]{4}[0-9]{4}\s-.*?)</, $page);
- shift @sections;
- # do for each subject
- foreach $section (@sections) {
- @useful = ();
- # print subject title
- if ($section =~ m/[A-Z]{4}[0-9]{4}\s-/) {
- $subject = $section;
- } else {
- # extract everything that's not in html tags
- @info = ($section =~ m/>([\w-:;,\s\(\)\&]*?[A-Z0-9]+[\w-:;,\s\)\&]*?)</g);
- foreach (@info) {
- push @useful, $_ if !(m/(data|row|table|sectionHeading)/ || m/^\s*\d+\s*$/);
- }
- # find times, classes, locations
- foreach (@useful) {
- $classes{$subject} .= "\n" if m/^Lecture|Tutorial|Laboratory$/;
- s/^\s*// && s/\s*$//;
- # ignore garbage
- if (!m/^[A-Z0-9]+$/ or m/Lecture|Tutorial|Laboratory|Mon|Tue|Wed|Thu|Fri/) {
- $garbage = 0;
- foreach $word (@ignore) {
- $garbage = 1 if ($_ =~ m/$word/);
- }
- $classes{$subject} .= "$_\n" if not $garbage;
- }
- }
- }
- }
- # go through classes for each subject
- foreach $subject (keys %classes) {
- @lines = split /\n/, $classes{$subject};
- $lesson = 0;
- for $i (0..$#lines) {
- # get day
- if ($lines[$i] =~ m/\b(Mon|Tue|Wed|Thu|Fri)\b/) {
- $classDays{$subject}[$lesson] = $1;
- $lesson++;
- }
- # get weeks
- if ($lines[$i] =~ m/^[\d,-]+$/) {
- while ($lines[$i] =~ m/(\d+-\d+)/) {
- $replacement = "";
- $numbers = $1;
- $numbers =~ m/(\d+)-(\d+)/;
- $from = $1;
- $to = $2;
- $replacement .= "$_," for ($from..$to);
- $replacement =~ s/,$//;
- $lines[$i] =~ s/$numbers/$replacement/;
- }
- $classWeeks{$subject}[$lesson - 1] = $lines[$i]; # hax
- $classLocation{$subject}[$lesson - 1] = $lines[$i + 1]; # get location
- }
- # get time
- $classTimes{$subject}[$lesson - 1] = $1 if ($lines[$i] =~ m/(\d+:\d+[AP]M - \d+:\d+[AP]M)/);
- # get class type (lecture/tute/lab)
- $classType = $1 if ($lines[$i] =~ m/(Lecture|Tutorial|Laboratory)/ or $lines[$i] =~ m/(.*\bof\b.*)/ );
- $classTypes{$subject}[$lesson] = $classType;
- }
- $classTypes{$subject}[$lesson] = ""; # moar hax
- }
- # ical 'header'
- $STARTCALENDAR = <<START;
- BEGIN:VCALENDAR
- PRODID:-//fun swap//hacked together perl//EN
- VERSION:2.0
- CALSCALE:GREGORIAN
- METHOD:PUBLISH
- START
- # *START*, *END*, *EVENT* etc. are substituted with actual class details later on
- $EVENTSTRING = <<EVENT;
- BEGIN:VEVENT
- DTSTART:*START*
- DTEND:*END*
- SUMMARY:*TITLE*
- LOCATION:*LOCATION*
- DESCRIPTION:*DESCRIPTION*
- SEQUENCE:0
- END:VEVENT
- EVENT
- # goes at the end of the produced file
- $ENDCALENDAR = "END:VCALENDAR";
- print OUTFILE $STARTCALENDAR;
- foreach $subject (keys %classes) {
- foreach $lesson (0..length($classTypes{$subject})) {
- if (defined $classDays{$subject}[$lesson]) {
- @weeksClassIsOn = split (/,/,$classWeeks{$subject}[$lesson]);
- # convert start and end times to 24h time
- @times = split (/ - /, $classTimes{$subject}[$lesson]);
- $startClassH = conv24($times[0]);
- $startClassM = getMins($times[0]);
- $endClassH = conv24($times[1]);
- $endClassM = getMins($times[0]);
- # format the title of the event as "[SUBJECT CODE] [Lecture|Tutorial|Laboratory]"
- $subject;
- @subjectCode = split(" - ", $subject);
- $subjectCode = @subjectCode[0];
- @subjectName = split(" - ", $subject);
- $subjectName = @subjectName[1];
- $subjectCode =~ s/^([A-Z]{4}[0-9]{4}).*$/$1/;
- $classType = $classTypes{$subject}[$lesson];
- $title = "$subjectCode $classType";
- $description = "$subjectName";
- # location of event
- $location = $classLocation{$subject}[$lesson];
- # add classes to calendar
- for $week (1..13) { #for each week in the timetable
- if ($week ~~ @weeksClassIsOn) { #if the class is on that week
- ##starting date
- $weekDate = $weekStart->clone();
- $weekDate->add( weeks => ($week -1) );
- # skip the week of mid-session break
- $weekDate->add( days => 7) if ($week > $weekBeforeBreak);
- $weekDate->add( days => dayToNumber($classDays{$subject}[$lesson]) - 1 );
- ##set the time the class starts
- $startTime = $weekDate->clone();
- $startTime->set_hour($startClassH);
- $startTime->set_minute($startClassM);
- ##set the time the class ends
- $endTime = $weekDate->clone();
- $endTime->set_hour($endClassH);
- $endTime->set_minute($endClassM);
- ##DateTime hackery pary one...
- ##Time part of the DateTime stamp needs to be formatted in Zulu time for compatibility with google calendar.
- ##If at least the time part is not in Zulu, all events show up as being one hour in duration.
- ##Convert time to UTC...
- $startTime->set_time_zone('UTC');
- $endTime->set_time_zone('UTC');
- # convert DateTime formatting to iCal formatting
- $startTime =~ s/[^0-9A-Z]//g;
- $endTime =~ s/[^0-9A-Z]//g;
- ##DateTime hackery part 2...
- ##Append Z for Zulu timezone to the times
- $startTime = $startTime."Z";
- $endTime = $endTime."Z";
- # substitute values into iCal event string
- $icalEvent = subInValues($title, $location, $startTime, $endTime, $description);
- ## append to file
- print OUTFILE $icalEvent;
- }
- }
- }
- }
- }
- ## append the final line to the file... and we're done
- print OUTFILE $ENDCALENDAR;
- close OUTFILE;
- ##return the minutes of a given time
- sub getMins($) {
- my $mins = $_[0];
- $mins =~ m/.*?:(.{2}).*?/;
- $mins = $1;
- return $mins;
- }
- # convert a weekday abbreviation to a number from 1-5
- sub dayToNumber($) {
- my $dayName = $_[0];
- my %days = ("Mon" => 1,
- "Tue" => 2,
- "Wed" => 3,
- "Thu" => 4,
- "Fri" => 5);
- return $days{$dayName};
- }
- # convert time of the format /(\d)?\d:\d\d[AP]M/ to a number from 0..23
- sub conv24($) {
- my $time = $_[0];
- $hour = $time;
- $hour =~ s/:.*$//;
- $hour += 12 if ($time =~ m/PM/ && $hour < 12); # convert to 24h time
- return $hour;
- }
- # substitutes event values into iCal string & returns resultant string
- sub subInValues($$$$$) {
- my ($title, $location, $startTime, $endTime, $description) = @_[0..4];
- my $icalEvent = $EVENTSTRING;
- $icalEvent =~ s/\*START\*/$startTime/;
- $icalEvent =~ s/\*END\*/$endTime/;
- $icalEvent =~ s/\*TITLE\*/$title/;
- $icalEvent =~ s/\*LOCATION\*/$location/;
- $icalEvent =~ s/\*DESCRIPTION\*/$description/;
- return $icalEvent;
- }
Advertisement
Add Comment
Please, Sign In to add comment