Mit etwas Perl ordnet Pidgin, der Tausendsassa unter den Instant-Messaging-Clients, verschiedenen Kommunikationspartnern unterschiedliche Geräusche zu, und spielt sie zu eintreffenden Nachrichten ab.
Wer während der Arbeitszeit Instant Messaging zur Kommunikation nutzt, sieht sich häufig mit dem Problem konfrontiert, dass plötzlich eintrudelnde Nachrichten die Konzentration stören. Vieles könnte man auch liegen lassen und später bearbeiten. Doch falls ein als Gschaftlhuber bekannter Manager eine Nachricht schickt, ist schnelle Reaktion gefragt. Wie filtern?
Pidgin, ein Messaging-Client [2], der alle gängigen
Kommunikationsprotokolle wie
Yahoo Messenger, AOL AIM oder auch IRC fährt, bietet
sogenannte ``Buddy Pounces'' an, die eintreffenden
Ereignissen entsprechende Aktionen zuordnen.
Der dafür zuständige
Dialog (Abbildung 1), erreichbar über den Menüpunkt ``Tools->Buddy Pounces'',
erlaubt es zum Beispiel, bei den Ereignissen ``Sends a message''
(schickt eine IM-Nachricht) oder ``Signs on'' (loggt sich ein)
eines bestimmten Kommunikationspartners eine vordefinierte
Sound-Datei abzuspielen oder
ein externes Programm auszuführen. Dazu ist in dem Formular in Abbildung
1 das Protokoll des genutzten IM-Service, der eigene Account und der Name
des IM-Partners anzugeben, bei dessen Aktivität das Ereignis ausgelöst
wird. Wichtig ist es, die Checkbox
recurring
zu aktivieren, sonst wirft Pidgin den Handler genau einmal
an und löscht danach dessen Definition.
Abbildung 1: Die "Pounce"-Funktion in Pidgin führt das Skript ~/bin/pounce-sound aus, falls ein IM-Buddy ein Ereignis auslöst. |
Nun habe ich zufälligerweise vor ein paar Wochen im Kaufrauf bei Amazon.com 500 Soundeffekte als runterladbare MP3-Dateien zum Schlagerpreis von $2.59 erstanden ([3], mittlerweile ist der Preis aber wieder auf $9.49 hochgeschnellt). Was liegt näher, als sie meinen liebsten IM-Freunden zuzuordnen? Ist das Pidgin-Chatfenster anschließend verdeckt, rüttelt mich nur bei ausgewählten Partnern ein eindeutig zu identifizierendes Geräusch aus der Konzentration. Alle anderen müssen warten. Der Gschaftlhuber bekommt eine Militärtrompete (bugle.mp3) zugeordnet, mein tanzversessener Arbeitskollege eine Samba-Rassel (cabassa.mp3) und ein Bekannter auf AIM, der immer den neuesten Tratsch parat hat, ein kurzes Soundschmankerl mit Geschnatter von fliegenden Wildgänsen (goose.mp3).
Allerdings hatte ich naturgemäß keine Lust, alles einzeln von Hand
in Pidgins Dialogfelder einzutragen und dies bei jeder weiteren Pidgin-Instanz,
auf dem Netbook und zuhause, zu wiederholen. Zum Glück legt Pidgin die
Pounce-Definitionen aber in einer leicht lesbaren XML-Datei unter
~/.purple/pounces.xml
ab.
Abbildung 2: Pidgin legt die konfigurierten Pounces in einer XML-Datei unter dem Verzeichnis .purple im Home-Verzeichnis ab. |
Das Perlskript pounce-yml-to-xml
nimmt
eine kompakt formatierte YAML-Datei wie in Abbildung 3 und wandelt sie
ohne viel Federlesens in das viel umständlichere aber von Pidgin
favorisierte XML-Format um. Die YAML-Datei pounces.yml
liegt unter
einem neu angelegten Verzeichnis
~/.pidgin-pounces
und dort trägt der Benutzer für jeden seiner
Online-Buddies eine Sounddatei ein.
Da Pidgin verschiedenste IM-Protokolle
fährt und ein Nutzer meist unter mehreren Accounts auf mehreren Servern
gleichzeitig eingeloggt ist, steht unter dem Eintrag sound_map
in der YAML-Datei zuerst
ein Schlüssel, der den jeweiligen IM-Anbieter und den dort verwendeten
Nutzernamen durch einen Doppelpunkt getrennt auflistet. Unter dieser
Hierarchiestufe folgen die Zuordnungen von Online-Partnern und Sounddateien,
die Pidgin abspielen soll, falls der Partner sich einloggt oder
dem Nutzer eine Nachricht schickt.
Nach Abbildung 3 ist also mein Screenname auf Yahoos Messenger-Service
``mikeschilli'', und falls
mir dort ``elcaramba'' eine Nachricht schickt, rasselt Pidgin mit ``cabassa.mp3''
einen heißen südamerikanischen Rhythmus.
Abbildung 3: Aus den Daten dieser YAML-Datei generiert das Skript pounce-yml-to-xml die XML-Datei in Abbildung 1. |
Neben der Zuordnung der Buddies zu den Geräuschen unter dem Eintrag
``sound_map'' setzt die YAML-Datei auch noch den Parameter interval
,
damit das System nicht bei jeder eintrudelnden Nachricht ein Geräusch
abspielt. Steht interval
auf 60, ist die Mindestzeitspanne zwischen zwei
Geräuscheinspielungen 60 Sekunden. Kommen in diesem Zeitraum mehrere
Nachrichten an, unterdrückt das System das abzuspielende Geräusch, denn
schließlich soll der arme User kein akustisches
Trommelfeuer ertragen sondern arbeiten.
YAML-Daten lassen sich 1:1 in Perl importieren, die Funktion LoadFile()
aus
dem YAML-Modul wandelt sie in die in Abbildung 4 gezeigte Struktur um.
Im nächsten Schritt steht nun die Umwandlung der Daten in aufgeblähtes
XML an.
Abbildung 4: Mit LoadFile() eingelesen, ergeben die YAML-Daten Abbildung 3 diese Datenstruktur in Perl. |
Das von Pidgin verwendete XML-Format (Abbildung 2)
definiert für jeden ``Pounce'' ein
Konstrukt, das in <pounce>
-Tags eingeschlossen ist. Die
Gesamtheit aller dieser Tags steht innerhalb eines Sammeltags mit dem
Namen <pounces>
(Plural). Dies ist einfach mittels
Reverse-Engineering herauszufinden, in dem man mehrere Pounces mit
Pidgins grafischer Oberfläche definiert und anschließend die
automatisch neu geschriebene XML-Datei inspiziert.
Das Skript pounce-yml-to-xml
wandelt nun die kompakte YAML-Datei
in Abbildung 3 in ausführliche XML-Instruktionen für Pidgin um, die
es anschließend in ~/.purple/pounces.xml
speichert.
Die for-Schleife ab Zeile 17 iteriert über die Einträge
im sound_map
-Hash der YAML-Datei, die allesamt im Format
protocol:account
vorliegen. Darunter wiederum liegt ein weiterer
Hash, der den Online-Partnern (Buddies) Geräusche zuordnet. Die
keys()-Funktion gibt eine Liste dieser Partner zurück, und Zeile
26 ruft für jeden die ab Zeile 51 definierte
Funktion mk_pounce()
auf. Als Parameter
erhält sie den Namen des Buddies, den Namen des Accounts (recv
genannt,
weil dieser später Nachrichten von den Buddies empfängt) und das
verwendete Protokoll (``yahoo'', ``aim'', oder dergleichen). Die Funktion
gibt jeweils einen XML-String zurück, der einem Eintrag in Pidgins
Konfigurationsdatei pounces.xml
entspricht.
01 #!/usr/local/bin/perl -w 02 use strict; 03 use Sysadm::Install qw(:all); 04 05 use YAML qw(LoadFile); 06 use Template; 07 08 my($home) = glob "~"; 09 my $path = "$home/.pidgin-pounce"; 10 my $yaml = LoadFile( "$path/pounce.yml" ); 11 12 my $xml_file = "$home/.purple/pounces.xml"; 13 my $SOUND_CMD = "~/bin/pounce-sound"; 14 15 my @pounces = (); 16 17 for my $account ( 18 keys %{ $yaml->{sound_map} }) { 19 20 my($proto, $recv) = split /:/, $account; 21 22 for my $buddy (keys %{ 23 $yaml->{sound_map}->{$account} }) { 24 25 push @pounces, 26 mk_pounce($buddy, $recv, $proto); 27 } 28 } 29 30 binmode STDOUT, ":utf8"; 31 32 my $xml = q{ 33 <?xml version='1.0' encoding='UTF-8' ?> 34 <pounces version='1.0'> 35 [% FOR pounce IN pounces %] 36 [% pounce %] 37 [% END %] 38 </pounces> 39 }; 40 41 my $tmpl = Template->new(); 42 43 mv $xml_file, "$xml_file.old" if 44 -f $xml_file; 45 46 $tmpl->process( \$xml, 47 { pounces => \@pounces }, 48 $xml_file ) or die $tmpl->error; 49 50 ########################################### 51 sub mk_pounce { 52 ########################################### 53 my($buddy, $recv, $prot) = @_; 54 55 return qq{ 56 <pounce ui='gtk-gaim'> 57 <account 58 protocol='prpl-$prot'>$recv</account> 59 <pouncee>$buddy</pouncee> 60 <options/> 61 <events> 62 <event type='sign-on'/> 63 <event type='message-received'/> 64 </events> 65 <actions> 66 <action type='execute-command'> 67 <param name='command' 68 >$SOUND_CMD $prot:$recv $buddy</param> 69 </action> 70 </actions> 71 <save/> 72 </pounce> 73 } 74 }
Zum Schreiben
des XML-Formats der Gesamtdatei kommt das Modul Template vom CPAN zum
Einsatz, ein
Template-Prozessor, der normalerweise beim dynamischen Aufbau von
Webseiten hilft. Im Skript pounce-yml-to-xml
expandiert es nur Makros
im Format
[% variable %]
und das praktische FOR
-Konstrukt der Template-Sprache
hilft in Zeile 35, die unästetische Vermengung von Perl- und XML-Code
zu vermeiden.
Zuerst habe ich zu diesem Zweck
ein wenig mit XML::Simple experimentiert, aber damit XML zu
erzeugen, das genauso aussieht wie die Vorgabe, ist praktisch
unmöglich. Und Pidgin ist nicht gerade robust, was die Abfolge der
Daten in dieser XML-Datei betrifft. Wer einen gnadenlos abkrachenden Pidgin
beobachten will, braucht nur den pouncee
-Eintrag vom Anfang ans Ende der
pounce
-Struktur zu schieben.
Die Funktion mv
aus dem Modul Sysadm::Install schiebt höflicherweise
eine eventuell
schon von Pidgin verwaltete
Datei pounces.xml
zur Seite und benennt sie in
pounces.xml.old
um.
Die process
-Methode in Zeile 46 nimmt einen Array von
Pounce-XML-Texten entgegen, über den die FOR-Schleife im Template-Code
iteriert, das parametrisierte XML an die richtigen Stellen einpflanzt,
und anschließend Pidgins Datei pounces.xml
mit den neuen Daten
überschreibt. Das Ergebnis, sichtbar in Abbildung 5, zeigt einen Wust
von XML für jede Kombination aus Protokoll, Account und
Kommunikationspartner. Alle Instanzen dieses XML-Snippets rufen
das externe Programm pounce-sound
mit ebendiesen Parametern auf.
Abbildung 5: Das von pounce-yml-to-xml generierte XML, das Pidgin dazu veranlasst, bei eintreffenden Nachrichten von bigboss an mikeschilli das externe Skript pounce-sound aufzurufen. |
Die den Online-Buddies zugeordneten Geräuschdateien werden allesamt
im Verzeichnis sounds
unterhalb des .pidgin-pounces
-Directories
installiert. Ihre Länge sollte jeweils ein paar
Sekunden nicht überschreiten. Liegt eine längere Sounddatei vor, eignet
sich zum Kürzen, wie in Abbildung
6 gezeigt, das Tool audacity
, mit dem man das Geräusch außerdem einfach
mit dem Effekten ``Fade in'' und ``Fade out'' sanft ein- und ausblenden kann.
Abbildung 6: Das Tool Audacity schneidet das Geräusch auf die korrekte Länge zurecht und lässt es mit dem Effekt "Fade Out" sanft ausklingen. |
Das von Pidgin im Ereignisfall aufgerufene
Skript pounce-sound
nimmt auf der Kommandozeile als Parameter die
Kombination aus Protokoll und Account, sowie das
Kürzel des sendenden Users entgegen. Es
liest die YAML-Datei ein, und findet heraus, und
ob ein Spezialsound für den User vorliegt. Falls ja, spielt es diesen
mit der Utility play
über die Soundkarte ab. Erhält Pidgin zum Beispiel
über das Yahoo-Protokoll mit dem eingeloggten User 'mikeschilli' eine
Nachricht von 'bigboss', ruft es
pounce-sound yahoo:mikeschilli bigboss
auf. Das Skript wiederum sieht in der YAML-Datei nach, findet, dass für diesen Fall die MP3-Datei ``bugle.mp3'' vorgesehen ist, und spielt sie ab.
Das einzig Bemerkenswerte an pounce-sound
ist der Aufruf
von Data::Throttler, der verhindert, dass zu häufiges Abspielen der
Sounds den Zorn des Benutzers erregt. Data::Throttler legt unter
~/.pidgin-pounce/throttler.yml
eine YAML-Datei an und merkt sich dort,
wann und wie oft das Programm zuletzt aufgerufen wurde. Die Methode
try_push()
merkt sich unter einem Schlüssel aus Protokoll,
dem Accountnamen und dem Namen des sendenden Buddies die Aktivitäten
und liefert einen
unwahren Wert zurück, falls der Buddy während der Zeitspanne der
letzten
interval
Sekunden schon aktiv war. Andere Kommunikationspartner
hingegen lässt es gewähren, bis auch diese ihr Quota überschritten haben.
01 #!/usr/local/bin/perl -w 02 use strict; 03 use YAML qw(LoadFile); 04 use lib '/home/mike/perl-modules/lib/perl5'; 05 use Data::Throttler; 06 07 my($proto, $buddy) = @ARGV; 08 09 die "usage: $0 proto:recv buddy" 10 if !defined $buddy; 11 12 my($home) = glob "~"; 13 my $path = "$home/.pidgin-pounce"; 14 15 my $yaml = LoadFile( "$path/pounce.yml" ); 16 17 my $throttler = Data::Throttler->new( 18 max_items => 1, 19 interval => $yaml->{interval}, 20 backend => "YAML", 21 backend_options => { 22 db_file => "$path/throttle.yml", 23 }, 24 ); 25 26 if(! $throttler->try_push( 27 key => "$proto:$buddy")) { 28 # rate limit reached, skip it 29 exit 0; 30 } 31 32 if(exists 33 $yaml->{sound_map}->{$proto}->{$buddy}) { 34 my $sound = 35 $yaml->{sound_map}->{$proto}->{$buddy}; 36 system("play $path/sounds/$sound"); 37 }
Das von Pidgin im Ereignisfall aufgerufene Skript pounce-sound
wandert ins bin
-Verzeichnis unterhalb
des Home-Verzeichnisses und wird mit chmod +x
ausführbar gemacht.
Die CPAN-Module YAML, Template, Sysadm::Install liegen vielen
Distributionen bei und lassen sich mit deren Package-Manager
installieren. Das Modul Data::Throttler wird über eine CPAN-Shell
mit perl -MCPAN -e'install Data::Throttler'
vom CPAN geholt
und installiert.
Die Utility play
, mit der das Skript pounce-sound
die .mp3-Datei
abspielt, ist Bestandteil des Pakets sox
, das der erfahrende
Ubuntu-Administrator mit sudo apt-get install sox
installiert.
Die eventuell noch gekürzten und weich ein- und ausklingenden Sounddateien
wandern ins Unterverzeichnis sounds
. Danach gilt es, die YAML-Datei
in Abbildung 2 an die lokalen Verhältnisse anzupassen, den eventuell
laufenden Pidgin-Prozess zu stoppen und das Skript
pounce-yml-to-xml
aufzurufen.
Wer den eingestellten Sound nur bei eingehenden Nachrichten hören möchte
und nicht wenn der Buddy sich einloggt, löscht den sign-on
-Event
im XML in Zeile 66 von pounce-yml-to-xml
.
Abbildung 7: Pidgin hat sich die XML-Datei geschnappt und zeigt nun im Pounce-Dialog die auto-generierten Einstellungen an. |
Nach einem Neustart schnappt Pidgin sich dann die autogenerierte XML-Datei und zeigt die neue Konfiguration auf Abfrage, wie in Abbildung 7 gezeigt, l im Pounce-Dialog an. Passiert ein reaktionswürdiges Ereignis, führt Pidgin den dazu definierten Pounce aus ruft das Soundskript auf, worauf die Militärtrompete erschallt, die den Anwender aus dem Büroschlaf schreckt. Jaja, Boss, bin praktisch fertig!
Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2010/02/Perl
``Pidgin, the universal chat client'', http://www.pidgin.im/
``500+ Sound Effects'' als MP3 bei Amazon, http://www.amazon.com/gp/product/B002OVD5FK
Michael Schilliarbeitet als Software-Engineer bei Yahoo! in Sunnyvale, Kalifornien. Er hat "Goto Perl 5" (deutsch) und "Perl Power" (englisch) für Addison-Wesley geschrieben und ist unter mschilli@perlmeister.com zu erreichen. Seine Homepage: http://perlmeister.com. |