I use irssi/screen on a remote server to maintain a constant IRC presence and I wanted a nice way to pop up a pretty, on-screen notification when my nick is hilighted or when I get a direct message. Irssi already has Perl 5 scripting support built-in, so the rest just took a little whipuptitude.
Here is part of a screen shot of the result:
There were three things I needed to make it work:
- Run a simple web service locally on my desktop machine that translates remote notification requests to the local notification daemon
- Use reverse port forwarding in the ssh connection for my IRC session to connect a remote port to my local web service
- Script irssi to listen for hilights and HTTP POST the message to the remote port
I’ll explain each piece step-by-step.
The web service 🔗︎
I wrote a trivially-simple Plack application that reads the text content of a POST, splits it into a summary line and a message and calls the command line notification program with the message. I use ’notify-send’ because I use Ubuntu 11.10, but you could swap in a comparable program for your own operating system.
use v5.10;
use strict;
use warnings;
use Plack::Request;
my $icon = "/usr/share/notify-osd/icons/gnome/scalable/status/notification-message-im.svg";
sub _notify {
my $content = shift;
my ($summary, $body) = split "\n", $content, 2;
$summary //= "IRC";
$body //= "";
system("/usr/bin/notify-send", "-i", $icon, $summary, $body);
}
my $app = sub {
my $req = Plack::Request->new(shift);
_notify($req->raw_body);
my $res = $req->new_response(200);
return $res->finalize;
};
I saved that as app.psgi and fired it up to listen on port 7877:
plackup -l localhost:7877 app.psgi
(Making that start automatically as part of your own login session is left as an exercise for the reader.)
Reverse port forwarding 🔗︎
I already had an alias to ssh to the server with my irssi/screen session, so I just had to modify it to add the reverse forwarding.
alias irc="ssh xdg@example.com -R 7877:localhost:7877"
Irssi scripting 🔗︎
I already had an irssi script to email me on highlights, so I adapted that to make a web request instead. It has two configuration options: a cooldown delay between messages and a url for messages.
I savid it as ‘purr_notify.pl’, which you can also get from my irssi scripts repo.
use strict;
use vars qw($VERSION %IRSSI);
use Irssi;
$VERSION = '0.0.1';
%IRSSI = (
authors => 'David Golden',
contact => 'dagolden@cpan.org',
name => 'purr_notify',
description => 'Send a purr when someone is talking to you in some channel.',
url => 'https://github.com/dagolden/irssi-scripts/blob/master/purr_notify.pl',
license => 'Apache License 2.0',
changed => 'Sun Feb 15 22:54:27 EST 2012'
);
#--------------------------------------------------------------------
# In parts based on fnotify.pl 0.0.3 by Thorsten Leemhuis
# http://www.leemhuis.info/files/fnotify/
# In parts based on knotify.pl 0.1.1 by Hugo Haas
# http://larve.net/people/hugo/2005/01/knotify.pl
# which is based on osd.pl 0.3.3 by Jeroen Coekaerts, Koenraad Heijlen
# http://www.irssi.org/scripts/scripts/osd.pl
# Other parts based on notify.pl from Luke Macken
# http://fedora.feedjack.org/user/918/
#--------------------------------------------------------------------
#--------------------------------------------------------------------
# Configuration handling
#--------------------------------------------------------------------
my %CONFIG;
sub load_config {
%CONFIG = (
url => Irssi::settings_get_str("$IRSSI{name}_url"),
cooldown => Irssi::settings_get_int("$IRSSI{name}_cooldown"),
);
if ( ! length $CONFIG{url} ) {
$CONFIG{url} = "http://localhost:7877/";
Irssi::print("$IRSSI{name} setting '$IRSSI{name}_port' defaulting to $CONFIG{url}");
}
if ( $CONFIG{cooldown} < 0 ) {
$CONFIG{cooldown} = 120;
Irssi::print("$IRSSI{name} setting '$IRSSI{name}_cooldown' defaulting to $CONFIG{cooldown}");
}
}
#--------------------------------------------------------------------
# Handle private messages
#--------------------------------------------------------------------
my %last_priv_from;
sub priv_msg {
my ($server,$msg,$nick,$address,$target) = @_;
if ( time - ($last_priv_from{$nick} || 0 ) > $CONFIG{cooldown} ) {
$last_priv_from{$nick} = time;
_send_purr($nick => $msg);
}
}
#--------------------------------------------------------------------
# Handle public hilights
#--------------------------------------------------------------------
my %last_hilight_from;
sub hilight {
my ($dest, $text, $stripped) = @_;
my ($channel, $level) = ($dest->{target}, $dest->{level});
if ($level & MSGLEVEL_HILIGHT) {
if ( time - ($last_hilight_from{$channel} || 0 ) > $CONFIG{cooldown} ) {
$last_hilight_from{$channel} = time;
_send_purr($channel => $stripped);
}
}
}
#--------------------------------------------------------------------
# Send notification message
#--------------------------------------------------------------------
sub _send_purr {
system("/usr/bin/curl", $CONFIG{url}, "-s", "-d", join("\n",@_));
}
#--------------------------------------------------------------------
# Hook into irssi settings and signals
#--------------------------------------------------------------------
Irssi::settings_add_str($IRSSI{name}, "$IRSSI{name}_url", '');
Irssi::settings_add_int($IRSSI{name}, "$IRSSI{name}_cooldown", -1);
load_config();
Irssi::signal_add_last("message private", \&priv_msg);
Irssi::signal_add_last("print text", \&hilight);
Irssi::signal_add_last("setup changed", \&load_config);
You might note that ‘curl’ is running silent with ‘-s’ so it won’t give errors trying to notify when the ssh connection is down.
I copied that into my ~/.irssi/scripts/autorun directory, restarted irssi and I was done.
