Perl: Growl notifications for new feed/rss items

04 Feb 2011

You want to monitor a web feed and show Growl notifications on your desktop when new items are published. Furthermore, you want to be able to click on a notification to open the relevant link on your default web browser. Also, for some rather bizarre reason, you don’t want to use RSS Menu.

In my case the reason was that I don’t want to track the “read/unread” status of individual items. I found it distracting, because I was always going to click on “Mark all read” after each batch of new items arrived. This perl script gives items in the feed a one off chance to grab your attention and make you click on it. Otherwise the item is gone into oblivion and you never get to hear about it again.

Using Cocoa::EventLoop and Cocoa::Growl it was actually rather simple. And this script can also work as a skeleton for any program where you want to post Growl notifications and do something on the click callback.

#!/usr/bin/perl -w

use strict;
use Cocoa::EventLoop;
use Cocoa::Growl ':all';
use LWP::Simple;
use XML::Simple;

die "Growl is not running.\n" unless growl_running();

my $feed  = 'http://tex.stackexchange.com/feeds';
my $local = 'tex.se.xml';
my $last  = '';

growl_register(
  app           => 'FeedGrowl',
  icon          => 'http://tex.stackexchange.com/favicon.ico',
  notifications => ['New feed item'],
);

my $timer = Cocoa::EventLoop->timer(
  interval => 300, # every five minutes
  cb       => \&refresh_feed
);

Cocoa::EventLoop->run;

exit 0;

sub refresh_feed {
  mirror($feed, $local);
  my $data = (XMLin($local, keyattr => [], ForceArray => ['entry']))->{'entry'};
  return unless @$data;
  
  my $i = 0;
  for my $item (@$data) {
    last if $item->{'updated'} le $last;
    $i++;
    notify_new_item($item->{'title'}->{'content'}, $item->{'link'}->{'href'});
    last if $i == 5; # show at most 5 new items
  }
  
  $last = $data->[0]->{'updated'};
}

sub notify_new_item {
  my ($item, $link) = @_;
  my $open_link = eval "sub { system('open', '$link') }";
  growl_notify(
    name        => 'New feed item',
    title       => 'New item on TeX.se',
    description => $item,
    on_click    => $open_link
  );  
}