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.