Help Wanted: Care to hack on a google calendar script?

cbrandtbuffalo on 2007-07-02T12:21:16

In case folks don't read the TPF blog, I need someone to help me out with a script that grabs info from the Perl calendar on Google calendar. I've got it started, just don't have the time right now to polish it.


Same thing I posted earlier?

brian_d_foy on 2007-07-02T14:50:33

I think this is related to my earlier post about the calendar, and stennie is working on something to provide a generic feed from it. You might talk to him about how you'd like to tag conference events, but I think he's going to abuse the location input for that.

My starter script is also available in that earlier post for anyone who wants to help.

Re:Same thing I posted earlier?

cbrandtbuffalo on 2007-07-02T15:10:22

I modified it a bit from that starter. After reading some of the docs, I think I can get data ranges and possibly specify the search as part of the request. Here's the script after my mods:


#!/usr/bin/perl
use strict;

use Data::Dumper;
use Template;
use DateTime;

use Net::Google::Calendar;

my $url = "http://www.google.com/calendar/feeds/ngctmrd1cac35061mrjt3hpgng%40group.calenda r.google.com/public/full";

my $cal = Net::Google::Calendar->new( url => $url );
my $dt = DateTime->now();

my @entries = ();

# Here, I want events that contain:
# YAPC, Workshop(s), Conference(s), Hackathon(s)
# Multiple hits to Google with get_events? Need to prevent dupes.
# Way to do it with one hit and and 'OR'?

foreach my $event ( $cal->get_events(
                                          'q' => "YAPC",
                                          'start-min' => $dt,
                                        )
                    )
    {

        my $hash = {};
        my $title = $event->title();
        $hash->{title} = $event->title;

        my $body = $event->content->body;

# warn $body, "\n\n\n";
        $body =~ s/ / /g;

        # This stuff doesn't seem to work for the 'full' style feed.
        # Need to figure out how to get these details out of the $event
        # object we get back.

        # Default something sensible if we get nothing.

        $hash->{description} = do { $body =~ s/(?:
\s*)*Event Description:\s+(.*)\s*//; $1 };
        $hash->{status} = do { $body =~ s/(?:
\s*)*Event Status:\s+(.*)\s*//; $1 };
        $hash->{where} = do { $body =~ s/(?:
\s*)*Where:\s+(.*)\s*//; $1 };
        $hash->{when} = do { $body =~ s/When:\s+(.*)\s*//; $1 };

        $hash->{when} =~ s/
Replaces.*//;

        push @entries, $hash;
    }

print Dumper (\@entries);

Net::Google::Calendar is seriously broken

Limbic Region on 2007-07-06T06:08:58

I have already provided working code to Jim, but I figured I would share for those following along at home:

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use DateTime;
use Getopt::Std;
use Net::Google::Calendar;
use XML::Atom::Util 'iso2dt';

my %opt;
get_args(\%opt);
my (%data, %seen);

my $cal = Net::Google::Calendar->new(url => $opt{url});

# Google Calendar supports OR'd category queries
# Google Calendar supports AND'd search string queries
# Multiple fetches are required for OR'd search string queries
# A different approach would be to pull all events and filter in perl land

for my $item (get_items($opt{search})) {

        for my $event ($cal->get_events('q' => $item, 'start-min' => $opt{datetime})) {

                # Since the same event may be found from different search strings
                # Store only one copy of the meta data but sym link as appropriate
                my $id = $event->id;
                if ($seen{$id}) {
                        $data{$item}{$id} = $seen{$id};
                }
                else {
                        $data{$item}{$id} = {};
                        $seen{$id} = $data{$item}{$id};
                }

                my $entry = $data{$item}{$id};
                $entry->{title} = $event->title || 'Unknown Title';
                $entry->{description} = $event->content->body || 'Unknown Description';
                $entry->{status} = get_status($event) || 'Unknown Status';
                $entry->{where} = get_location($event) || 'Unknown Location';
                $entry->{author} = get_author($event) || {};
                $entry->{when} = get_when($event) || {};
        }

}

print Dumper(\%data);

sub get_author {
        my ($event) = @_;
        my $author = $event->author;
        my $name = $author->name || 'Unknown';
        my $email = $author->email || 'Unknown';
        my $weburl = $author->homepage || 'Unknown';
        return {name => $name, email => $email, homepage => $weburl};
}

sub get_status {
        my ($event) = @_;
        my $ns = XML::Atom::Namespace->new(gd => 'http://schemas.google.com/g/2005');
        my $elem = $event->elem;
        my $node = ($elem->getElementsByTagNameNS($ns->{uri}, 'eventStatus'))[0];
        my $val = $node->getAttribute('value');
        $val =~ s!^http://schemas.google.com/g/2005#event\.!!;
        return $val;
}

sub get_location {
        my ($event) = @_;
        my $ns = XML::Atom::Namespace->new(gd => 'http://schemas.google.com/g/2005');
        my $elem = $event->elem;
        my $node = ($elem->getElementsByTagNameNS($ns->{uri}, 'where'))[0];
        my $val = $node->getAttribute('valueString');
        return $val;
}

sub get_when {
        my ($event) = @_;
        my $ns = XML::Atom::Namespace->new(gd => 'http://schemas.google.com/g/2005');
        my $elem = $event->elem;
        my $node = ($elem->getElementsByTagNameNS($ns->{uri}, 'when'))[0];
        my $beg = $node->getAttribute('startTime');
        my $end = $node->getAttribute('endTime');
        for ($beg, $end) {
                $_ = defined($_) ? iso2dt($_)->strftime("%Y-%m-%d") : 'Unknown';
        }
        return {start => $beg, end => $end};
}

sub get_items {
        my ($search_string) = @_;
        return grep {defined($_) && length($_)} split /\|/, $search_string;
}

sub get_args {
        my ($opt) = @_;
        my $Usage = qq{Usage: $0 [options]
                -h : This help message

                -u : The (u)rl of the calendar to fetch
                          Default: Full feed of The Perl Review

                -s : The date/time (s)tamp of when to fetch from
                          Format: RFC 3339. For example: 2005-08-09T10:57:00-08:00
                          Default: now

                -i : The (i)tems to query
                          Format: 'item1|item2|item3'
                          Default: 'YAPC|workshop|conference|hackathon'

        } . "\n";
        getopts('hu:s:', $opt) or die $Usage;
        die $Usage if $opt->{h};
        $opt->{datetime} = $opt->{s} || DateTime->now();
        $opt->{url} = $opt->{u} || 'http://www.google.com/calendar/feeds/ngctmrd1cac35061mrjt3hpgng%40group.calenda r.google.com/public/full';
        $opt->{search} = $opt->{i} || 'YAPC|workshop|conference|hackathon'
}
__END__
TODO
1. Support parsing various different strings for -s
2. Support advanced query items '(item1&item2)|item3'
3. Provide patches to Net::Google::Calendar
4. Provide more better tests to Net::Google::Calender (use test only)
5. Extract links from the description when available
6. Use Template for the output

Re:Net::Google::Calendar is seriously broken

kyloe on 2009-12-18T12:18:39

Hi - been trying to use this (and other) code, but cant seem to get any sense out of it - it logs on OK and seems to create a 'feed' object - but whatever I do the feed is empty - i.e. I can get the version - but no entries or calendars ... anyone seen this before - its got me stumped (am busy picking my way thorugh the ATOM code ... but its a bit out of my league ...)