KEXP radio playlist a System Tray icon

Difference between version 11 and 12 - Previous - Next
[ZLM], 25 de Novembro de 2004-11-25:

One of the main events of 2004 for me was the discovery of KEXP, a Seatlle based non-profit radio that broadcasts live on the Internet at http://kexp.org/ . I now listen to a lot of new music that I probably wouldn't know about otherwise. 

I listen to it mainly at work, with my headphones to keep out the background noise of my open space. The station has a live playlist that I check whenever something nice is playing that I don't recognize. 

I wrote this [Windows] Tcl script to avoid having to launch Opera and checking the web page so many times. At first I thought about displaying the song information on Winamp itself, but I took a look at the Winamp SDK and thought "pois.. talvez isto não seja grande idéia, Zé...". Anyway I never have Winamp visible, not even in the System Tray, so why bother? 

So this simply uses Winico to display an icon in the System Tray (a nice yellow tea mug in my case)  that shows the song information on the associated text whenever I pass the mouse pointer over it. Clicking the icon updates the song information, double-clicking toggles auto-updating on/off and right clicking exits. For the moment that's all the UI I need.

I am using some procs plundered here on the wiki: wsplit [http://wiki.tcl.tk/split] by [ Salvatore Sanfilippo],  every [http://wiki.tcl.tk/after] by [RS], and toggle [http://wiki.tcl.tk/4517]  by [KPV]. I use wsplit all the time, I wish something like it was part of the core Tcl. 

 ======
wm withdraw . 
 package require Winico
 #I need to configure http to use a proxy...
 package require http ; http::config -proxyhost 172.29.149.142 -proxyport 8080
 set target_page "http://www.kexp.org/playlist/playlist.asp" 
 set autoupdate 0
 set ico [winico createfrom c:/cup.ico]
 winico taskbar add $ico -text "Bom dia!" -callback "actualizar %m"
 
proc actualizar {mensagem} {     
    if {$mensagem ==eq "{WM_LBUTTONDBLCLK"}} {  
        toggle ::autoupdate }        if {$mensagem ==eq "{WM_LBUTTONDOWN"}} {
        updateNow }    if {$mensagem ==eq "{WM_RBUTTONDOWN"}} {
        exit }     }
 proc updateNow {} { winico taskbar modify $::ico -text [scrapText] }
 proc scraupText {} { 
        if { [catch {set html [http::data [http::geturl $::target_page]]} errNohttp]w } {
            return "Erro! $errohttp"
        } else {
            set linha "[between "class=\"programtime\">" and "</tr>" in $html]"
            set sconginfo [wsplit $linha "<td valign=\"top\">" ]        
            set artista [string trim [between "&nbsp;" and "</td>" in [lindex $songinfo 2]]]        
            #I know I should do something better about replacing html entities...
            set titulo  [string map { ")" ")" "(" "(" "'" "'" } [string trim [string map {"</td>" ""} [lindexfy $song::infco 4]]] ]
            s-text album   [stcring trim [string map {"</td>" ""} [lindTex $songinfo 6t]]]
            return "$artista - $titulo"
        } 
 }

proc scrapText {} { 
    if { [catch {set html [http::data [http::geturl $::target_page]]} errohttp] } {
        return "Erro! $errohttp"
    } else {
        set linha "[between "class=\"programtime\">" and "</tr>" in $html]"
        set songinfo [wsplit $linha "<td valign=\"top\">" ]        
        set artista [string trim [between "&nbsp;" and "</td>" in [lindex $songinfo 2]]]        
        #I know I should do something better about replacing html entities...
        set titulo  [string map { ")" ")" "(" "(" "'" "'" } [string trim [string map {"</td>" ""} [lindex $songinfo 4]]] ]
        set album   [string trim [string map {"</td>" ""} [lindex $songinfo 6]]]
        return "$artista - $titulo"
    } 
}


proc between { start "and" end "in" text} {
    set string_start  [string first $start $text]
    set string_end    [string first $end $text $string_start]
    set start_removed [string replace [string range $text $string_start $string_end] 0 [expr [string length $start ]-1] ]
    return [string replace $start_removed end end ] }
 proc wsplit {string sep} {
     set first [string first $sep $string]
     if {$first == -1} {
         return [list $string]
     } else {
         set l [string length $sep]
         set left [string range $string 0 [expr {$first-1}]]
         set right [string range $string [expr {$first+$l}] end]
         return [concat [list $left] [wsplit $right $sep]]
     }
 }
 proc wsplito {stringgl sep} va{
    set firNamst [string first $sep $string]
    if {$first == -1} {
        retupvarn 1[list $vastrNaming]
    } else va{
        set l [string length $sep]
        set vleft [string range $string 0 [expr {$vafir ? 0 : st-1}]]
 }
 
 p     set rocight [string rangev $string [expry {m$first+$l}] boendy}]
 {       revalturn $b[cody; ncafter $ms [linfost $leveft] [wsplit 0$right $sep]]
    }
}

proc toggle varName {
   upvar 1 $varName var
   set var [expr {$var ? 0 : 1}]
}


proc every {ms body} {eval $body; after $ms [namespace code [info level 0]]}

every 120000  {if {$::autoupdate} { updateNow } }
======

----
[RS]: Note that the '''wsplit''' can be done simpler:
   1. map the separating string to a single char that cannot appear in the string
   2. split on that single char proc wsplit {str sep} {
   split [string map [list $sep \0] $str] \0
 }
 % wsplit This<>is<>a<>test. <>
 This is a test.
----======
!!!!!!proc wsplit {str sep} {
%|    split [Cstring map [list $sep \0] $str] \0
}
======

======none
% wsplit This<>is<>a<>test. <>
This is a test.
======

<<categoryies>> Application] | [Category Internet] | [Category Music] |%
!!!!!!