Fixed up the bot a ton, rewrote it from scratch

This commit is contained in:
Chris Oliver 2010-02-13 17:37:58 -06:00
parent df6c918e40
commit 0ab04a77e7
4 changed files with 180 additions and 1739 deletions

View file

@ -1,11 +1,26 @@
[irc] [irc]
network = irc.freenode.net server = irc.freenode.net
port = 6667 port = 6667
channels = #keryx channels = #keryx
nick = Timber nick = Timber
password =
# This your nick identification password
password = testing
# Comma separated list of owner nicks
owners = excid3 owners = excid3
[log] [log]
# Location to store the logs
folder = logs folder = logs
stylesheet = file:///C:\Users\Chris Oliver\Desktop\logbot\conf\stylesheet.css # Location of the stylesheet
stylesheet = conf/stylesheet.css
[format]
join = -!- <span class="join">%user%</span> [%host%] has joined %channel%
kick = -!- <span class="kick">%user%</span> was kicked from %channel% by %kicker% [%reason%]
mode = -!- mode/<span class="mode">%channel%</span> [%modes% %person%] by %giver%
part = -!- <span class="part">%user%</span> has parted %channel%
pubmsg = <span class="person">&lt;%user%&gt;</span> %message%
pubnotice = <span class="notice">-%user%:%channel%-</span> %message%
quit = -!- <span class="quit">%user%</span> has quit [%reason%]

View file

@ -4,12 +4,18 @@ body {
font-size: 13px; font-size: 13px;
} }
.time { h1 {
font-family: sans-serif;
font-size: 24px;
text-align: center;
}
a, .time {
color: #525552; color: #525552;
text-decoration: none; text-decoration: none;
} }
.time:hover { text-decoration: underline; } a:hover, .time:hover { text-decoration: underline; }
.person { color: #DD1144; } .person { color: #DD1144; }

1560
irclib.py

File diff suppressed because it is too large Load diff

328
logbot.py
View file

@ -25,7 +25,7 @@
__author__ = "Chris Oliver <excid3@gmail.com>" __author__ = "Chris Oliver <excid3@gmail.com>"
__version__ = "0.2.1" __version__ = "0.3.0"
__date__ = "08/11/2009" __date__ = "08/11/2009"
__copyright__ = "Copyright (c) Chris Oliver" __copyright__ = "Copyright (c) Chris Oliver"
__license__ = "GPL2" __license__ = "GPL2"
@ -33,13 +33,16 @@ __license__ = "GPL2"
import os import os
import os.path import os.path
import irclib import shutil
from ConfigParser import ConfigParser from ConfigParser import ConfigParser
from ftplib import FTP from ftplib import FTP
from optparse import OptionParser from optparse import OptionParser
from time import strftime from time import strftime
from irclib import nm_to_n
from ircbot import SingleServerIRCBot
html_header = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" html_header = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
@ -47,161 +50,99 @@ html_header = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>%s</title> <title>%s</title>
<link href="%s" rel="stylesheet" type="text/css" /> <link href="stylesheet.css" rel="stylesheet" type="text/css" />
</head> </head>
<body> <body>
</body> </body>
</html> </html>
""" """
index_header = """<h1>%s</h1><br />"""
class LogBot(object):
def __init__(self, network, port, channels, owner, nick, password, folder, stylesheet): class LogBot(SingleServerIRCBot):
self.network = network def __init__(self, server, port, channels, owners, nickname, password):
self.port = port """Initialize this badboy"""
self.channels = channels SingleServerIRCBot.__init__(self, [(server, port, password)],
self.owner = owner nickname,
self.nick = nick nickname)
self.password = password self.chans = channels
def set_format(self, folder, format, stylesheet):
self.folder = folder self.folder = folder
self.format = format
self.stylesheet = stylesheet self.stylesheet = stylesheet
def start(self): def on_nicknameinuse(self, c, e):
# Write logs locally, so we need the folder to exist """Append an underscore to the nick if it's already in use"""
if not os.path.exists(self.folder): c.nick(c.get_nickname() + "_")
os.mkdir(self.folder)
#os.chdir(self.folder) def on_welcome(self, c, e):
"""Join the channels once we have made a successful connection"""
for channel in self.chans:
c.join(channel)
# Create an IRC object def on_pubmsg(self, c, e):
self.irc = irclib.IRC() user = nm_to_n(e.source())
message = e.arguments()[0]
# Setup the IRC functionality we want to log channel = e.target()
handlers = {'join': self.handleJoin, self.write(channel, self.format["pubmsg"].replace("%user%", user) \
'pubmsg': self.handlePubMessage, .replace("%message%", message))
'privmsg': self.handlePrivMessage,
'part': self.handlePart, def on_invite(self, c, e):
'invite': self.handleInvite, pass
'kick': self.handleKick,
'mode': self.handleMode,
'pubnotice': self.handlePubNotice,
'quit': self.handleQuit}
for key, val in handlers.items():
self.irc.add_global_handler(key, val)
# Create a server object, connect and join the channel
self.server = self.irc.server()
self.server.connect(self.network, self.port, self.nick, ircname=self.nick)
if self.password:
self.server.privmsg("nickserv", "identify %s" % self.password)
for channel in self.channels:
self.server.join(channel)
# Jump into an infinte loop
self.irc.process_forever()
#eventtype -- A string describing the event. def on_join(self, c, e):
#source -- The originator of the event (a nick mask or a server). user = nm_to_n(e.source())
#target -- The target of the event (a nick or a channel). host = e.source()
#arguments channel = e.target()
self.write(channel, self.format["join"].replace("%user%", user) \
def handleKick(self, connection, event): .replace("%host%", host) \
"""Handles kick messages .replace("%channel%", channel))
Writes messages to log
""" def on_kick(self, c, e):
# kicker, channel, [person, reason] kicker = e.source()
# event.source(), event.target(), event.arguments() channel = e.target()
person, reason = event.arguments() user, reason = e.arguments()
self.write(event.target(), self.write(channel, self.format["kick"].replace("%kicker%", kicker) \
"-!- <span class=\"kick\">%s</span> was kicked from %s by %s [%s]" % \ .replace("%channel%", channel) \
(person, event.target(), event.source().split("!")[0], reason)) .replace("%user%", user) \
.replace("%reason%", reason))
def handleMode(self, connection, event):
"""Handles mode changes def on_mode(self, c, e):
Writes messages to log modes, person = e.arguments()
""" channel = e.target()
# person giving ops, #channel, [modes, person] giver = nm_to_n(e.source())
#print event.source(), event.target(), event.arguments() self.write(channel, self.format["mode"].replace("%channel%", channel) \
modes, person = event.arguments() .replace("%modes%", modes) \
self.write(event.target(), .replace("%person%", person) \
"-!- mode/<span class=\"mode\">%s</span> [%s %s] by %s" % \ .replace("%giver%", giver))
(event.target(), modes, person, event.source().split("!")[0]))
def on_part(self, c, e):
def handlePubNotice(self, connection, event): user = nm_to_n(e.source())
"""Handles public notices channel = e.target()
Writes messages to log self.write(channel, self.format["part"].replace("%user%", user) \
""" .replace("%channel%", channel))
# user, channel, [msg]
#print event.source(), event.target(), event.arguments() def on_privmsg(self, c, e):
self.write(event.target(), pass
"<span class=\"notice\">-%s:%s-</span> %s" % \
(event.source().split("!")[0], event.target(), event.arguments()[0])) def on_pubnotice(self, c, e):
user = nm_to_n(e.source())
def handleQuit(self, connection, event): channel = e.target()
"""Handles quite messages message = e.arguments()[0]
Writes messages to log self.write(channel, self.format["pubnotice"].replace("%user%", user) \
""" .replace("%channel%", channel) \
# user, channel?, [reason] .replace("%message%", message))
#print event.source(), event.target(), event.arguments()
self.write(None,
"-!- <span class=\"quit\">%s</span> has quit [%s]" % \
(event.source().split("!")[0], event.arguments()[0]))
def handlePrivMessage(self, connection, event):
"""Handles private messages
Used for owners to send instructions to bot
"""
# sender, receiver (me), [msg]
print "PRIVATE MESSGAE", event.source(), event.target(), event.arguments()
def handleJoin(self, connection, event):
"""Handles user join messages
Writes messages to log
"""
nick = event.source().split("!")
try:
nickmask = nick[1]
except:
nickmask = "unknown"
nick = nick[0]
self.write(event.target(),
"-!- <span class=\"join\">%s</span> (%s) has joined %s" % \
(nick, nickmask, event.target()))
def handlePubMessage(self, connection, event):
"""Handles public messages
Writes messages to log
"""
nick = event.source().split("!")[0]
self.write(event.target(),
"<span class=\"person\">&lt;%s&gt;</span> %s" % \
(nick, event.arguments()[0]))
def handlePart(self, connection, event):
"""Handles part messages
Writes messages to log
"""
nick = event.source().split("!")[0]
self.write(event.target(),
"-!- <span class=\"part\">%s</span> has parted %s" % \
(nick, event.target()))
def handleInvite(self, connection, event):
"""Handles invitations from IRC users
Only accept invites to join a channel if they are from an owner
"""
nick = event.source().split("!")[0]
# Only allow invites from owner(s)
if not nick in self.owner:
print "Invite from %s denied" % nick
return
for channel in event.arguments():
self.server.join(channel)
def on_quit(self, c, e):
user = nm_to_n(e.source())
reason = e.arguments()[0]
channel = e.target()
print channel
self.write(channel, self.format["quit"].replace("%user%", user) \
.replace("%reason%", reason))
def write(self, channel, message): def write(self, channel, message):
time = strftime("%H:%M:%S") time = strftime("%H:%M:%S")
date = strftime("%d-%m-%Y") date = strftime("%d-%m-%Y")
@ -211,28 +152,59 @@ class LogBot(object):
else: else:
# Quits don't have channels # Quits don't have channels
print "%s %s" % (time, message) print "%s %s" % (time, message)
channels = self.channels channels = self.chans
if not os.path.exists(self.folder):
# Create the log folder if we need to
os.mkdir(self.folder)
index = os.path.join(self.folder, "index.html")
create_html_file(index, "Logged Channels")
append_to_index(index, index_header % "Logged Channels")
shutil.copy2(self.stylesheet, self.folder)
for channel in channels: for channel in channels:
path = os.path.abspath(os.path.join(self.folder, channel)) path = os.path.abspath(os.path.join(self.folder, channel))
if not os.path.exists(path): if not os.path.exists(path):
# Create the folder if it doesn't exist
os.mkdir(path) os.mkdir(path)
if not os.path.exists(os.path.join(path, "stylesheet.css")):
shutil.copy2(self.stylesheet, path)
chan_index = os.path.join(path, "index.html")
path = os.path.join(path, date+".html") path = os.path.join(path, date+".html")
if not os.path.exists(path): if not os.path.exists(path):
# Create the html header create_html_file(chan_index, "%s | Logs" % channel)
f = open(path, "wb") append_to_index(chan_index, index_header % "%s | Logs" % channel)
f.write(html_header % (("%s | Logs for %s" % (channel, date)), self.stylesheet))
f.close() append_to_index(index, "<a href=\"%%23%s\">%s</a>" % \
(channel[1:]+"/index.html", channel))
create_html_file(path, "%s | Logs for %s" % (channel, date))
append_to_index(chan_index, "<a href=\"%s\">%s</a>" % \
(date+".html", date))
str = "<a href=\"#%s\" name=\"%s\" class=\"time\">[%s]</a> %s" % \
(time, time, time, message)
append_to_index(path, str)
def create_html_file(path, title):
f = open(path, "wb")
f.write(html_header % title)
f.close()
def append_to_index(path, line):
data = open(path, "rb").readlines()[:-2]
data.append(line + "<br />\n")
data += [" </body>\n", "</html>\n"]
f = open(path, "wb")
f.writelines(data)
f.close()
data = open(path, "rb").readlines()[:-2]
data.append("<a href=\"#%s\" name=\"%s\" class=\"time\">[%s]</a> %s<br />\n" % (time, time, time, message))
data += [" </body>\n", "</html>\n"]
f = open(path, "wb")
f.writelines(data)
def main(conf): def main(conf):
""" """
Start the bot using a config file. Start the bot using a config file.
@ -242,29 +214,37 @@ def main(conf):
""" """
CONFIG = ConfigParser() CONFIG = ConfigParser()
CONFIG.read(conf) CONFIG.read(conf)
network = CONFIG.get('irc', 'network')
port = CONFIG.getint('irc', 'port') # Get the irc network configuration
channels = CONFIG.get('irc', 'channels').split(',') server = CONFIG.get("irc", "server")
nick = CONFIG.get('irc', 'nick') port = CONFIG.getint("irc", "port")
channels = CONFIG.get("irc", "channels").split(",")
nick = CONFIG.get("irc", "nick")
try: try:
password = CONFIG.get('irc', 'password') password = CONFIG.get("irc", "password")
except: except:
password = None password = None
owner = CONFIG.get('irc', 'owners').split(',') owner = CONFIG.get("irc", "owners").split(",")
logs_folder = CONFIG.get('log', 'folder')
stylesheet = CONFIG.get('log', 'stylesheet') # Get the log section
folder = CONFIG.get("log", "folder")
stylesheet = CONFIG.get("log", "stylesheet")
# Get the formation information
types = ["join", "kick", "mode", "part", "pubmsg", "pubnotice", "quit"]
format = {}
for type in types:
format[type] = CONFIG.get("format", type)
bot = LogBot(server, port, channels, owner, nick, password)
bot.set_format(folder, format, stylesheet)
bot.start()
bot = LogBot(network, port, channels, owner, nick, password, logs_folder, stylesheet)
try:
bot.start()
except KeyboardInterrupt:
pass
if __name__ == "__main__":
if __name__ == '__main__':
# Require a config # Require a config
parser = OptionParser() parser = OptionParser()
parser.add_option('-c', '--config', dest='conf', help='Config to use') parser.add_option("-c", "--config", dest="conf", help="Config to use")
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
if not options.conf or not os.access(options.conf, os.R_OK): if not options.conf or not os.access(options.conf, os.R_OK):