web-dev-qa-db-fra.com

Notification sonore via SSH

Je viens de passer du client Konversation IRC à l'IRSSI basé sur le terminal. Je démarre IRSSI sur un ordinateur distant en utilisant GNU screen + SSH. Je ne reçois aucune notification sonore sur les nouveaux messages, ce qui signifie que je dois vérifier de temps à autre l'IRSSI pour les nouveaux messages.

Ce n'est pas vraiment productif, alors je cherche une application/script qui joue un son (de préférence /usr/share/sounds/KDE-Im-Irc-Event.ogg et non le bip agaçant) sur ma machine s'il y a une activité. Ce serait formidable si je pouvais désactiver la notification pour certains canaux.

Ou, si ce n'est pas possible, une sorte de notification via libnotify, le rendant ainsi disponible pour GNOME et KDE.

12
Lekensteyn

Je n'aimais pas libnotify, j'ai donc créé un serveur UDP dans Python et une application cliente pour irssi. Notez que cette réponse s'applique aux exigences d'origine dans révision 1 , il n'a pas de notification de texte.

Client

Cette version réagit à divers messages qui vous sont adressés. Si vous souhaitez être averti des messages sur n’importe quel canal, supprimez le # initial de la ligne #'message public'. Une certaine limitation de débit est mise en œuvre, il y aura un délai d'au moins 1,3 seconde entre les notifications.

##
## Put me in ~/.irssi/scripts, and then execute the following in irssi:
##
##       /load Perl
##       /script load notifyudp
##

use strict;
use Irssi;
use IO::Socket;
use vars qw($VERSION %IRSSI);
use Time::HiRes qw(time);

$VERSION = "0.3.20140930";
%IRSSI = (
    authors     => 'Lekensteyn',
    contact     => '[email protected]',
    name        => 'notifyudp.pl',
    description => 'Send a UDP signal to a remote machine',
    license     => 'GPLv3+'
);

Irssi::settings_add_str('notifyudp', 'notifyudp_ip_addr', '');
# port 0 = disabled
Irssi::settings_add_int('notifyudp', 'notifyudp_port', 0);
Irssi::settings_add_bool('notifyudp', 'notifyudp_auto_start', 0);

my $sock;

sub notify_load {
    if ($sock) {
        Irssi::print('NotifyUDP: Already connected.');
        return;
    }
    my $ip = Irssi::settings_get_str('notifyudp_ip_addr');
    my $port = Irssi::settings_get_int('notifyudp_port');
    if (!$port || !$ip) {
        Irssi::print('NotifyUDP: No port or Host set, /set notifyudp for more information..');
        return;
    }
    if ($port < 1024 || $port > 65535) {
        Irssi::print('NotifyUDP: Invalid port, must be 1024 <= port <= 65535, resetting and ignoring.');
        Irssi::settings_set_int('notifyudp_port', 0);
        return;
    }
    $sock = new IO::Socket::INET(
        PeerAddr => $ip,
        PeerPort => $port,
        Proto => 'udp',
        Timeout => 1
    );
    Irssi::print("NotifyUDP: IP $ip will be notified on port $port.");
}

my $last_time = 0;
sub notify {
    if ($sock) {
        my $now = time;
        my $notify_delay = 1.3;
        if (abs($now - $last_time) > $notify_delay) {
            $last_time = $now;
            $sock->send("M");
        }
    }
}
sub notify_if_hilighted {
    my ($dest, $text, $stripped) = @_;
    if ($dest->{level} & MSGLEVEL_HILIGHT) {
        notify();
    }
}

sub notify_stop {
    if ($sock) {
        Irssi::print("NotifyUDP: Stopping.");
        $sock->send("S");
        $sock = undef;
    } else {
        Irssi::print("NotifyUDP: not active.");
    }
}

sub cmd_notifyudp {
    my ($cmd) = @_;
    if ($cmd eq 'start') {
        notify_load();
    } elsif ($cmd eq 'stop') {
        notify_stop();
    } elsif ($cmd eq 'ping') {
        notify();
    } else {
        Irssi::print('NotifyUDP: Usage: /notifyudp [start|stop|ping]');
    }
}

Irssi::command_bind('notifyudp', 'cmd_notifyudp');

my @signals = (
# Uncomment the following to get notifs for every (channel) message
#'message public',
'message private',
'dcc request',

'message irc notice', # NickServ responses and such

# whenever the server dies
'server connected',
'server connect failed',
'server disconnected',

'message invite',
'message topic',
'message dcc',
'ctcp msg',
'ctcp reply',
);
Irssi::signal_add('print text', 'notify_if_hilighted');
foreach (@signals) {
    Irssi::signal_add($_, 'notify');
}

if (Irssi::settings_get_bool('notifyudp_auto_start')) {
    Irssi::print('NotifyUDP: automatic connection with the sound server is enabled.');
    notify_load();
} else {
    Irssi::print('NotifyUDP: automatic connection with the sound server is disabled.');
}

Serveur

Une fois démarré, il écoute toutes les adresses, port 3533. S'il reçoit un paquet UDP "M", il lit /usr/share/sounds/KDE-Im-Irc-Event.ogg en utilisant paplay ("PulseAudio play"). À la réception de S, il quitte le serveur. Comme il est open-source, vous êtes libre de le supprimer.

#!/usr/bin/env python
# udpsoundserver.py

"""Listen on a UDP port and play a sound when 'M' is received

Starts the server listening on UDP port PORT (3533 by default) on address Host
(by default all addresses). Valid commands are:
M - play Music
S - Stop the server
"""
try:
    import socketserver
except ImportError:
    import SocketServer as socketserver
from os import system,getpid
import threading
import sys

# leave it empty to listen on all addresses
Host = ""
PORT = 3533


class UDPSvr(socketserver.BaseRequestHandler):
    def handle(self):
        data = self.request[0]
        if sys.version >= '3':
            data = str(data, "ISO-8859-1")
        data = data.strip()
        if data == "M":
            Ding.dong()
        Elif data == "S":
            Ding.die()

class Worker(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.daemon = True
    def run(self):
        server.serve_forever();

class Handler(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        self.daemon = True
        self.play = False
        self.must_die = False

    def run(self):
        self.event = threading.Event()
        while True:
            self.event.wait(1.)
            if self.event.isSet():
                if self.play:
                    print("Playing...")
                    system("paplay /usr/share/sounds/KDE-Im-Irc-Event.ogg")
                # no else if to allow shutdown signals 
                if self.must_die:
                    print("Shutting down...")
                    server.shutdown()
                    break
                self.play = False
                self.event.clear()

    def dong(self):
        self.play = True
        self.event.set()

    def die(self):
        self.must_die = True
        self.event.set()

def ca(num, x):
    print("Caught SIGINT, shutting down...")
    Ding.die()

import signal
if __== "__main__":
    print("My PID is: " + str(getpid()))

    if len(sys.argv) > 1:
        Host = sys.argv[1]
    if len(sys.argv) > 2:
        PORT = int(sys.argv[2])

    print("Host: " + Host)
    print("Port: " + str(PORT))
    server = socketserver.UDPServer((Host, PORT), UDPSvr)

    Ding = Handler()
    signal.signal(signal.SIGINT, ca)
    worker = Worker()
    Ding.start()
    worker.start()
    # might not be the cleanest, but it allows Ctrl + C
    while Ding.isAlive():
        Ding.join(3600)

La séquence de démarrage du serveur distant devient:

screen -dm path/to/udpsoundserver.py
ssh -R 5355:localhost:5355

Une fois connecté, je lance:

screen -t irssi irssi

Si vous avez besoin de vous reconnecter plus tard:

screen -r irssi

Après avoir démarré irssi, vous devez définir l'hôte et le port:

/set notifyudp_ip_addr 127.0.0.1
/set notifyudp_port 5355

Pour qu’il se connecte automatiquement au démarrage:

/set notifyudp_auto_start 1

La première fois, vous devez démarrer Notify UDP manuellement car le démarrage automatique n'a pas encore eu lieu:

/notifyudp start

Afin de tester la notification:

/notifyudp ping

Faire:

  • faire en sorte que le serveur de sons s'arrête à la déconnexion
  • permettre de sauter des chaînes
9
Lekensteyn

Je le fais avec libnotify. J'ai trouvé cela il y a très longtemps.

Cela fonctionne comme un champion. J'avais l'habitude de l'utiliser avec libnotify sur Linux (et c'est toujours le cas lorsque je suis sur une machine Linux), mais la plupart du temps, je suis sur un macbook maintenant, donc j'utilise grondement pour remplacer libnotify sur le mac.

# todo: grap topic changes

use strict;
use vars qw($VERSION %IRSSI);

use Irssi;
$VERSION = '0.0.3';
%IRSSI = (
    authors     => 'Thorsten Leemhuis',
    contact     => '[email protected]',
    name        => 'fnotify',
    description => 'Write a notification to a file that shows who is talking to you in which channel.',
    url         => 'http://www.leemhuis.info/files/fnotify/',
    license     => 'GNU General Public License',
    changed     => '$Date: 2007-01-13 12:00:00 +0100 (Sat, 13 Jan 2007) $'
);

#--------------------------------------------------------------------
# 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/
#
#--------------------------------------------------------------------

#--------------------------------------------------------------------
# Private message parsing
#--------------------------------------------------------------------

sub priv_msg {
    my ($server,$msg,$nick,$address,$target) = @_;
    filewrite($nick." " .$msg );
}

#--------------------------------------------------------------------
# Printing hilight's
#--------------------------------------------------------------------

sub hilight {
    my ($dest, $text, $stripped) = @_;
    if ($dest->{level} & MSGLEVEL_HILIGHT) {
    filewrite($dest->{target}. " " .$stripped );
    }
}

#--------------------------------------------------------------------
# The actual printing
#--------------------------------------------------------------------

sub filewrite {
    my ($text) = @_;
    # FIXME: there is probably a better way to get the irssi-dir...
        open(FILE,">>$ENV{HOME}/.irssi/fnotify");
    print FILE $text . "\n";
        close (FILE);
}

#--------------------------------------------------------------------
# Irssi::signal_add_last / Irssi::command_bind
#--------------------------------------------------------------------

Irssi::signal_add_last("message private", "priv_msg");
Irssi::signal_add_last("print text", "hilight");

#- end

Pour le charger dans irssi, exécutez la commande suivante:

/load Perl

/script load fnotify

Ensuite, nous devons l’acheminer vers libnotify. Pour ce faire, enregistrez les éléments suivants en tant que script Shell et exécutez-les à la connexion:

# yes, we need a way to flush the file on disconnect; i don't know one
# yes, that's flush is not atomic (but good enough for me)
ssh remote.system.somewhere "tail -n 10 .irssi/fnotify ; : > .irssi/fnotify ; tail -f .irssi/fnotify " | sed -u 's/[<@&]//g' | while read heading message  do  notify-send -i gtk-dialog-info -t 300000 -- "${heading}" "${message}"; done # the sed -u 's/[<@&]//g' is needed as those characters might confuse  notify-send (FIXME: is that a bug or a feature?)
7
Bill Childers