Я очень долго пытался найти подходящий нотификатор и в конце концов сделал то, что меня полностью удовлетворяет.
#!/usr/bin/wish
# :action:color:bgcolor:timeout:message
## Setup ###########################################################
set GEOMETRY -100-0
set FONT {-cronyx-helvetica-bold-r-*-*-14-*-*-*-*-*-koi8-r}
set PORT 7778
# /Setup ###########################################################
###### EVENTS
set messages {}
proc shift_message {} {
global messages # not changed directly
remove_message [lindex $messages end]
}
proc drop_all_messages {} {
global messages # not changed directly
foreach x $messages {
remove_message $x
}
}
###### DISPLAING
proc update_label {} {
global messages # not changed directly
set m [lindex $messages end]
set l [llength $messages]
if {$l == 0} {
wm withdraw .
} else {
if {$l == 1} {
set a {}
} else {
set a " ($l)"
}
.l configure -text "[string range $m 14 end]$a" \
-fg "#[string range $m 0 5]" \
-bg "#[string range $m 7 12]"
wm deiconify .
raise .
}
}
###### TIMERS
array set message_timeouts {}
proc set_timeout_for_message {mess timeout} {
global message_timeouts
unset_timeout_for_message $mess
if {$timeout > 0} {
set t [after [expr {$timeout * 1000}] [list remove_message $mess]]
set message_timeouts($mess) $t
}
}
proc unset_timeout_for_message {mess} {
global message_timeouts
set t [array names message_timeouts -exact $mess]
if {[llength $t] == 1} {
after cancel $message_timeouts($mess)
unset message_timeouts($mess)
}
}
###### PROCESSING
proc remove_message {mess} {
global messages
set i [lsearch -exact $messages $mess]
if {$i >= 0} {
set messages [lreplace $messages $i $i]
update_label
unset_timeout_for_message $mess
}
}
proc insert_message {mess timeout} {
global messages
lappend messages $mess
update_label
set_timeout_for_message $mess $timeout
}
proc append_message {m} {
# -- parse
if {[regexp {(?x)^
:(set|clean|)
:([0-9a-fA-F]{6}|)
:([0-9a-fA-F]{6}|)
:(\d*)
:(.*)$
} $m x action color bgcolor timeout text]} {
} else {
set action {set}
set color {}
set bgcolor {}
set timeout {}
set text $m
}
if {$color == {}} {set color {000000}}
if {$bgcolor == {}} {set bgcolor {999999}}
if {$timeout == {}} {set timeout -1}
# -- process
set mess "$color:$bgcolor:$text"
remove_message $mess
if {$action != {clean}} {
insert_message $mess $timeout
}
}
###### NETWORK
array set accumulators {}
array set timeouts {}
proc read_from_channel {channel} {
global accumulators
set s [read $channel]
if {$s == {}} {
close_channel $channel
} else {
set t "$accumulators($channel)$s"
set i [string first "\n" $t]
if {$i > 0} {
set accumulators($channel) [string range $t 0 [expr {$i - 1}]]
close_channel $channel
} else {
set accumulators($channel) $t
}
}
}
proc close_channel {channel} {
global accumulators timeouts
append_message $accumulators($channel)
after cancel $timeouts($channel)
unset accumulators($channel)
unset timeouts($channel)
fileevent $channel readable {}
close $channel
}
proc setup_channel {channel} {
global accumulators timeouts
#### DEBUG
puts {-- on open}
puts "acc = [array get accumulators]"
puts "tos = [array get timeouts]"
global messages message_timeouts
puts "mes = $messages"
puts "mto = [array get message_timeouts]"
puts {--}
####
fconfigure $channel -blocking 0
set timeout [after 2000 [list close_channel $channel]]
set timeouts($channel) $timeout
set accumulators($channel) {}
fileevent $channel readable [list read_from_channel $channel]
}
proc accept_connection {channel addr port} {
setup_channel $channel
}
###### MAIN
socket -server accept_connection $PORT
wm title . {uNote}
tk appname {uNote}
wm overrideredirect . 1
label .l -font $FONT -padx 10 -pady 1
pack .l
#tkwait visibility .
wm geometry . $GEOMETRY
bind . <1> shift_message
bind . <3> drop_all_messages
append_message {:set:000000:ffffcc:10:uNote (c) Michurin 2010-2011}
Если сообщение не поддаётся разбору, то оно считается простым и выводится дефолтными цветами и без таймаута.
:action:foreground:background:timeout:message
^ ^ ^ ^ ^
| | | | |
| | | | `-- текст сообщения
| | | `-- таймаут в секундах, по прошествии
| | | которого сообщение будет автоматически
| | | забыто
| | `-- цвета в HTML-формате без префикса '#'
| `------------- то есть ffffff — белый, ff0000 — красный
`-- действие, поддерживаются set и clean
Просто вывести 'OK!'.
echo 'OK!' | nc localhost 7778
Вывести 'OK!' белого цвета на зелёном фоне на десять секунд.
echo '::ffffff:009900:10:OK!' | nc localhost 7778
Запланировать вывод сообщения на 18:30.
echo 'echo ":set:990000:ffff00::It is 18:30 now!" | nc localhost 7778' | at 18:30
#!/bin/sh
pid=$1
while test `ps h $pid | wc -l` -eq 1
do
echo -en "\e[1G\t"
echo -n `date`
echo -en "\e[K\e[1G"
sleep 3
done
echo ''
echo ":set:990000:ffff00::PID=$pid DONE" | nc localhost 7778
Выдаёт сообщение о том, что завершился процесс с заданным PID.
#!/bin/sh
fl="$1"
os=''
while
if test -e "$fl"
then
s=`stat -c %Y "$fl"`
test "${os:-0}" -ne "$s"
else
false
fi
do
echo -en "\e[1G\t"
echo -n "$os -> $s"
echo -en "\e[K\e[1G"
os="$s"
sleep 120
done
echo ''
echo "FILE $fl DONE" | nc localhost 7778
Выдаёт сообщение, когда файл перестал изменяться (закончено скачивание, конвертирование или ещё что-то).
#!/bin/sh
#url='http://scfire-ntc-aa02.stream.aol.com:80/stream/1049'
url='http://scfire-ntc-aa03.stream.aol.com:80/stream/1049'
#url='http://scfire-dtc-aa03.stream.aol.com:80/stream/1049'
#url='http://scfire-dtc-aa01.stream.aol.com:80/stream/1049'
#url='http://scfire-ntc-aa04.stream.aol.com:80/stream/1049'
#url='http://scfire-dtc-aa05.stream.aol.com:80/stream/1049'
#url='http://scfire-dtc-aa06.stream.aol.com:80/stream/1049'
mplayer -quiet "$url" </dev/null |
while read l
do
echo "| $l"
if echo $l | grep 'ICY Info' 2>&1 >/dev/null
then
u=`echo "$l" | sed 's/.*StreamUrl=.//;s/..$//;'`
# echo "u=[$u]"
if `echo "$u" | grep covers 2>&1 >/dev/null`
then
f=/tmp/radio/${u##*/}
# echo "test file [$f]"
if test ! -e "$f"
then
# echo "wget file [$f]"
# echo wget -qO "$f" "$u"
mkdir -p /tmp/radio
wget -qO "$f" "$u"
fi
(
echo "display file [$f]"
display -geometry +0-0 "$f" &
sleep 15
kill %-
) &
else
echo "[not cover]"
fi
l=`echo "$l" | sed 's/ICY Info: StreamTitle=.//;s/.;StreamUrl=.*//'`
# l=`echo "$l" | sed 's/ICY Info: StreamTitle=.//;s/-.*//'`
echo ":set:aaccaa:223322:30:$l" | nc localhost 7778
fi
done
Скрипт проигрывает интернет-радио, показывает обложки альбомов (это фича Radio Paradise; ваша любимая радиостанция может и не передавать обложки альбомов; нужен ImageMagic) и названия композиций.