#!/usr/bin/perl
#
# $Id: scbot.pl,v 1.11 2004/01/16 20:55:04 sharl Exp $
use Socket;
use Jcode; # jcode() for Japanese
$rev = '$Revision: 1.11 $';
$rev =~ s/.*(\d+\.\d+).*/$1/;
$BOT_VERSION = 'SHOUTcast bot rev.' . $rev;
$USER_AGENT = "WatchLynx/$rev/scbot";
$LYNX = "/usr/bin/lynx -source -reload -useragent=$USER_AGENT";
$STREAM_NAME = "";
$SHOUTSERVER = "http://192.168.0.2:8000/"; # SHOUTcast D.N.A.S. Status URI
$IRC_SERVER = 'localhost'; # irc server host
$IRC_PORT = 6667; # irc service port
$IRC_NICK = 'scbot'; # bot nickname
$IRC_NICK_ONAIR = 'scbot-oa'; # onair nickname
$IRC_NAME = 'scbot'; # full name
$IRC_ONAIR_CHANNEL = '#sc_on_air'; # on air channel
$IRC_NOTICE_CHANNEL = '#live'; # notice channel
@IRC_CHANNEL = ($IRC_ONAIR_CHANNEL,
$IRC_NOTICE_CHANNEL); # auto join channel
$IRC_USERINFO = "$SHOUTSERVER [$STREAM_NAME]"; # CTCP USERINFO message
$PROFILE_MSG = $IRC_USERINFO; # WHOIS message
$DEBUG = 10;
$INTERVAL = 30;
$PREVTIME = time;
$status = "down";
$SIG{'ALRM'} = 'GetTitle';
########
# main #
########
while (1) {
next if (&Connect);
print S "NICK $IRC_NICK\r\n";
print S "USER $IRC_NAME 8 * :$PROFILE_MSG\r\n";
for $chan (@IRC_CHANNEL) {
print S "JOIN $chan\r\n";
}
#
# loop
#
while (<S>) {
$DEBUG && print STDERR;
if (/^:\S* 433 \* $IRC_NICK/o) {
print STDERR "$IRC_NICK Already in use at $IRC_SERVER.\n";
close(S);
sleep(120);
last;
}
# PING from server
(/^PING (\S+)/io && &PongServer($1));
# CTCP PING
/^:(\S+)\!\S* PRIVMSG (\S+) :\001PING (\d+)/o && &CTCP_Ping($1, $3);
# CTCP VERSION
/^:(\S+)\!\S* PRIVMSG (\S+) :\001VERSION/o && &CTCP_Version($1);
# CTCP USERINFO
/^:(\S+)\!\S* PRIVMSG (\S+) :\001USERINFO/o && &CTCP_UserInfo($1);
# CTCP CLIENTINFO
/^:(\S+)\!\S* PRIVMSG (\S+) :\001CLIENTINFO/o && &CTCP_ClientInfo($1);
if ($status eq "up" && /^:(.*)\!\S* JOIN :(\S+)/o
&& $1 ne $IRC_NICK && $1 ne $IRC_NICK_ONAIR) {
$chan = $2;
print S "NOTICE $chan :Now broadcasting. $SHOUTSERVER\r\n";
sleep(2);
}
if (/^:$IRC_NICK\!\S* JOIN :(\S+)/o) {
$STARTFLAG = 1 if (&ChanMatch($1));
eval { alarm $INTERVAL; };
}
&GetTitle; # for Windows
}
}
exit;
#############
# Get title #
#############
sub GetTitle {
return if (!$STARTFLAG);
alarm 0;
my $time = time;
return if ($time - $PREVTIME < $INTERVAL);
$DEBUG && print STDERR "status $status\nsearch title... $SHOUTSERVER\n";
open(FD, "$LYNX $SHOUTSERVER |");
@buffer = <FD>;
close(FD);
for (@buffer) {
if (/Stream Title: <\/font><\/td><td><font class=default><b>(.*?)<\/b>/o) {
$STREAM_NAME = $1;
$STREAM_NAME = jcode($STREAM_NAME)->iso_2022_jp;
}
if ($status eq "down" && /Server is currently up/o) {
$status = "up";
print S "NICK $IRC_NICK_ONAIR\r\n";
sleep(2);
for $chan (@IRC_CHANNEL) {
print S "NOTICE $chan :[$STREAM_NAME] Broadcast was started. $SHOUTSERVER\r\n";
sleep(2);
}
}
if ($status eq "up" && /Server is currently down/o) {
$status = "down";
for $chan (@IRC_CHANNEL) {
print S "NOTICE $chan :Broadcast was ended.\r\n";
sleep(2);
}
print S "NICK $IRC_NICK\r\n";
sleep(2);
}
if (/Current Song: <\/font><\/td><td><font class=default><b>(.*?)<\/b>/o) {
$newtitle = $1;
if ($newtitle ne $oldtitle) {
$line = jcode($newtitle)->iso_2022_jp;
print S "NOTICE $IRC_ONAIR_CHANNEL :$line\r\n";
sleep(2);
$oldtitle = $newtitle;
}
}
}
$DEBUG && print STDERR "search end...\n";
$PREVTIME = $time;
eval { alarm $INTERVAL; };
}
###############
# subroutines #
###############
#
# to pong the server back...
#
sub PongServer {
local($fromhost) = $_[0];
print S "PONG $fromhost\r\n";
$DEBUG && print STDERR "PONG $fromhost\n";
}
################
# CTCP message #
################
#
# CTCP VERSION
#
sub CTCP_Version {
local($nick) = $_[0];
print S "NOTICE $nick :\001VERSION $BOT_VERSION\001\r\n";
}
#
# CTCP USERINFO
#
sub CTCP_UserInfo {
local($nick) = $_[0];
print S "NOTICE $nick :\001USERINFO :$IRC_USERINFO \001\r\n";
}
#
# CTCP CLIENTINFO
#
sub CTCP_ClientInfo {
local($nick) = $_[0];
print S "NOTICE $nick :\001CLIENTINFO :VERSION USERINFO CLIENTINFO PING\001\r\n";
}
#
# CTCP PING
#
sub CTCP_Ping {
local($nick, $time) = @_;
print S "NOTICE $nick :\001PING $time\001\r\n";
}
####################
# channel matching #
####################
sub ChanMatch {
local($chan) = $_[0];
$chan =~ tr/A-Z/a-z/;
for $channel (@IRC_CHANNEL) {
$channel =~ tr/A-Z/a-z/;
return 1 if ($channel eq $chan);
}
return 0;
}
#####################
# server connection #
#####################
sub Connect {
$DEBUG && print STDERR "connect...\n";
socket(S, PF_INET, SOCK_STREAM, 0) || return 1;
connect(S, pack_sockaddr_in($IRC_PORT, inet_aton($IRC_SERVER))) || return 1;
select((select(S), $| = 1)[0]);
return 0;
}
|