Powiadomienie dźwiękowe przez SSH

13

Właśnie przełączyłem się z klienta Konversation IRC na IRSSI oparty na terminalu. Zaczynam IRSSI na zdalnym komputerze za pomocą ekranu GNU + SSH. Nie otrzymuję żadnego powiadomienia dźwiękowego o nowych wiadomościach, co oznacza, że ​​od czasu do czasu muszę sprawdzać IRSSI pod kątem nowych wiadomości.

Nie jest to zbyt produktywne, więc szukam aplikacji / skryptu, który odtworzy dźwięk (najlepiej /usr/share/sounds/KDE-Im-Irc-Event.oggnie denerwujący dźwięk) na moim komputerze, jeśli jest jakaś aktywność. Byłoby wspaniale, gdybym mógł wyłączyć powiadomienia dla niektórych kanałów.

Lub, jeśli nie jest to możliwe, jakieś powiadomienie za pośrednictwem libnotify, dzięki czemu jest ono dostępne dla GNOME i KDE.

Lekensteyn
źródło

Odpowiedzi:

10

Nie podobało mi się libnotify, więc stworzyłem serwer UDP w Pythonie i aplikację kliencką dla irssi. Należy zauważyć, że ta odpowiedź dotyczy pierwotnych wymagań w wersji 1 , nie ma powiadomienia tekstowego.

Klient

Ta wersja reaguje na różne wiadomości skierowane do Ciebie. Jeśli chcesz być powiadamiany o wiadomościach w każdym kanale, usuń wiodącą #w #'message public'linii. Wdrożono pewne ograniczenie prędkości, między powiadomieniami będzie opóźnienie co najmniej 1,3 sekundy.

##
## 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.');
}

serwer

Po uruchomieniu nasłuchuje na wszystkich adresach, port 3533. Jeśli odbierze pakiet UDP „M”, odtworzy /usr/share/sounds/KDE-Im-Irc-Event.oggprzy użyciu paplay(„Odtwarzanie PulseAudio”). Po otrzymaniu Swychodzi z serwera. Ponieważ jest to oprogramowanie typu open source, możesz to usunąć.

#!/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 __name__ == "__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)

Sekwencja uruchamiania zdalnego serwera wygląda następująco:

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

Po zalogowaniu uruchamiam:

screen -t irssi irssi

Jeśli chcesz ponownie połączyć się później:

screen -r irssi

Po uruchomieniu irssimusisz ustawić host i port:

/set notifyudp_ip_addr 127.0.0.1
/set notifyudp_port 5355

Aby połączyć się automatycznie podczas uruchamiania:

/set notifyudp_auto_start 1

Za pierwszym razem musisz uruchomić Powiadomienie UDP ręcznie, ponieważ nie zostało jeszcze uruchomione automatycznie:

/notifyudp start

Aby przetestować powiadomienie:

/notifyudp ping

Do zrobienia:

  • zatrzymaj serwer dźwiękowy po rozłączeniu
  • pozwalają na pomijanie kanałów
Lekensteyn
źródło
Powiedziałeś, że wskaźnik tekstu nie jest wymagany - frazowanie sugerowało, że byłoby fajnie, ale nie było preferowaną opcją. Przepraszam za edycję i możesz ją wycofać, jeśli chcesz.
jrg
Nie ma problemu, dobrze jest mieć alternatywy. Moje rozwiązanie jest, jak powiedziałem, zhakowanie razem, więc twoja odpowiedź może być warta wypróbowania.
Lekensteyn,
7

Robię to za pomocą libnotify. Znalazłem to wieki temu.

Działa jak mistrz. Kiedyś używałem go z libnotify na Linuksie (i nadal robię to, gdy jestem na komputerze z linuksem), ale przez większość czasu jestem teraz na MacBooku, więc używam growl jako zamiennika libnotify na Macu.

# 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

Aby go załadować irssi, uruchom następujące polecenie:

/load perl

/script load fnotify

Następnie musimy go przekierować libnotify. Aby to zrobić, zapisz następujące jako skrypt powłoki i uruchom go podczas logowania:

# 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?)
Bill Childers
źródło
Lame GROWLer. ;) Spojrzę na to.
jrg
Sprawdzę to później, dzień po opublikowaniu tego QI zhakowałem razem skrypt Perla i Pythona, którego wtedy używałem.
Lekensteyn,