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 => 'lekensteyn@gmail.com',
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.ogg
przy użyciu paplay
(„Odtwarzanie PulseAudio”). Po otrzymaniu S
wychodzi 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 irssi
musisz 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