Update (14/02/2014):
Some folks over at http://www.247drumandbass.com are now utilizing this script on their IRC channel. You should check it out on Quakenet #247drumandbass.
Shoutcast TCL Script
I was recently approached by a friend to help out with a TCL script for his Shoutcast radio station. He has an eggdrop running on the EFNet IRC server which acts as an announcer for the radio station. It gives users the ability to call commands such as what song is currently playing, what is playing next and general advertising of the station.
Shoutcast have recently had a big upgrade to their software and in particular the admin interface. While this is always a welcome edition due to new features and bug fixes one of the downsides is that scripts that use the old software tend to be made null and void. In particular changes to the XML and the inclusion of stream IDs broke most of the old TCL scripts.
I wouldn’t say I am particularly skilled in the TCL language but I’m always willing to give something a go and by looking at the old scripts and the newer admin interface I did manage to make a fairly feature rich Shoutcast announcement script.
The below code block outlines how I made the basic commands by using an http connection to browse to the admin xml webpage and then using an exceptional TCL package called tDom to extract particular XML nodes and their inline text. This text is then displayed to an IRC channel.
package require http
package require tdom
bind pub -|- !song currsong
proc currplaying {nick uhost hand chan arg} {
global siteurl djchan radiochan adminpass
# Create an HTTP request to the admin xml page :
:http::config -useragent "Mozilla/5.0; Shoutinfo"
set http_req [::http::geturl http://$siteurl:8000/admin.cgi?pass=$adminpass&sid=1&mode=viewxml&page=0 -timeout 2000]
if {[::http::status $http_req] != "ok"} {
putnow "PRIVMSG $chan :Stream is unavailable";
}
set data [::http::data $http_req] ::http::cleanup $http_req
# Create dom document
set doc [dom parse $data] set xmlNodes [$doc documentElement]
# Grab Stream status from XML to check if the station is currently online or not
if {[[$xmlNodes selectNodes /SHOUTCASTSERVER/STREAMSTATUS/text()] data] == "1"} {
# If it is online display a message to the channel the current playing song
putnow "PRIVMSG $chan :package require http
package require tdom
bind pub -|- !song currsong
proc currplaying {nick uhost hand chan arg} {
global siteurl djchan radiochan adminpass
# Create an HTTP request to the admin xml page :
:http::config -useragent "Mozilla/5.0; Shoutinfo"
set http_req [::http::geturl http://$siteurl:8000/admin.cgi?pass=$adminpass&sid=1&mode=viewxml&page=0 -timeout 2000]
if {[::http::status $http_req] != "ok"} {
putnow "PRIVMSG $chan :Stream is unavailable";
}
set data [::http::data $http_req] ::http::cleanup $http_req
# Create dom document
set doc [dom parse $data] set xmlNodes [$doc documentElement]
# Grab Stream status from XML to check if the station is currently online or not
if {[[$xmlNodes selectNodes /SHOUTCASTSERVER/STREAMSTATUS/text()] data] == "1"} {
# If it is online display a message to the channel the current playing song
putnow "PRIVMSG $chan :\002Current Song\002: [[$xmlNodes selectNodes /SHOUTCASTSERVER/SONGTITLE/text()] data]"
} else {
# Otherwise let the user kmow the server is offline
if {$chan != $djchan} {
putnow "PRIVMSG $chan :Server status is offline..."
} else {
putnow "NOTICE $nick :Server status is offline..."
}
}
}
2Current Songpackage require http
package require tdom
bind pub -|- !song currsong
proc currplaying {nick uhost hand chan arg} {
global siteurl djchan radiochan adminpass
# Create an HTTP request to the admin xml page :
:http::config -useragent "Mozilla/5.0; Shoutinfo"
set http_req [::http::geturl http://$siteurl:8000/admin.cgi?pass=$adminpass&sid=1&mode=viewxml&page=0 -timeout 2000]
if {[::http::status $http_req] != "ok"} {
putnow "PRIVMSG $chan :Stream is unavailable";
}
set data [::http::data $http_req] ::http::cleanup $http_req
# Create dom document
set doc [dom parse $data] set xmlNodes [$doc documentElement]
# Grab Stream status from XML to check if the station is currently online or not
if {[[$xmlNodes selectNodes /SHOUTCASTSERVER/STREAMSTATUS/text()] data] == "1"} {
# If it is online display a message to the channel the current playing song
putnow "PRIVMSG $chan :\002Current Song\002: [[$xmlNodes selectNodes /SHOUTCASTSERVER/SONGTITLE/text()] data]"
} else {
# Otherwise let the user kmow the server is offline
if {$chan != $djchan} {
putnow "PRIVMSG $chan :Server status is offline..."
} else {
putnow "NOTICE $nick :Server status is offline..."
}
}
}
2: [[$xmlNodes selectNodes /SHOUTCASTSERVER/SONGTITLE/text()] data]"
} else {
# Otherwise let the user kmow the server is offline
if {$chan != $djchan} {
putnow "PRIVMSG $chan :Server status is offline..."
} else {
putnow "NOTICE $nick :Server status is offline..."
}
}
}
TCLI won’t go through it line by line as most of it is standard TCL code but I will point out the bits important to this post. Firstly you can see I include two packages. HTTP and tDom. As mentioned previously this allows me to make http calls and then extract and use the XML nodes.
package require http
package requite tdom
TCLNext up I make an http call to the servers admin interface passing through the $siteurl and $adminpass variables. These are set at the top of the script as global variables. As you can see in the url I am also calling &mode=viewxml to display the output in XML.
::http::config -useragent "Mozilla/5.0; Shoutinfo"
set http_req [::http::geturl http://$siteurl:8000/admin.cgi?pass=$adminpass&sid=1&mode=viewxml&page=0 -timeout 2000]
if {[::http::status $http_req] != "ok"} {
putnow "PRIVMSG $chan :Stream is unavailable";
}
set data [::http::data $http_req] ::http::cleanup $http_req
TCLFinally I create a Dom document from the returned http data and use that to extract particular nodes.
set doc [dom parse $data]
set xmlNodes [$doc documentElement]
putnow "PRIVMSG $chan :set doc [dom parse $data]
set xmlNodes [$doc documentElement]
putnow "PRIVMSG $chan :\002Current Song\002: [[$xmlNodes selectNodes /SHOUTCASTSERVER/SONGTITLE/text()] data]"
2Current Songset doc [dom parse $data]
set xmlNodes [$doc documentElement]
putnow "PRIVMSG $chan :\002Current Song\002: [[$xmlNodes selectNodes /SHOUTCASTSERVER/SONGTITLE/text()] data]"
2: [[$xmlNodes selectNodes /SHOUTCASTSERVER/SONGTITLE/text()] data]"
TCLThis similar technique is also used to display the next song, current bitrate, current listeners which are all grabbed from the XML output. Other features of the script include:
- Topic changes for when the radio station comes online/goes offline
- A periodic timer to check and show song changes
- A timer to check if the peak listeners changes
- Commands to show current song, next song, server status, radio url and radio url
- Ability for operators to disconnect current dj
- Ability for users to request songs (which are displayed to a separate dj channel)
- List the 10 previous songs
- Display the current and peak listeners
I add the script to my github page soon, so feel free to check it out and replace any old scripts you may have. I’m always up for a challenge so if you have any ideas for new features drop a comment or tweet and I’ll be happy to discuss it.
If you want to see it in action jump on EFNet and join the #android-radio channel.