mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-11-02 17:29:22 +01:00
Made into a flatfile, w00t!
This commit is contained in:
parent
07689261c6
commit
e9aac2e191
@ -47,9 +47,12 @@ import getopt
|
||||
import string
|
||||
from itertools import imap, ifilter
|
||||
|
||||
import log
|
||||
import conf
|
||||
import utils
|
||||
import world
|
||||
import ircdb
|
||||
import irclib
|
||||
import ircmsgs
|
||||
import plugins
|
||||
import ircutils
|
||||
@ -90,62 +93,164 @@ conf.registerChannelValue(conf.supybot.plugins.ChannelStats, 'frowns',
|
||||
(i.e., pieces of text with no spaces in them ) are considered 'frowns' for
|
||||
the purposes of stats-keeping."""))
|
||||
|
||||
class ChannelStat(irclib.IrcCommandDispatcher):
|
||||
def __init__(self, actions=0, chars=0, frowns=0, joins=0, kicks=0, modes=0,
|
||||
msgs=0, parts=0, quits=0, smileys=0, topics=0, words=0):
|
||||
self.actions = actions
|
||||
self.chars = chars
|
||||
self.frowns = frowns
|
||||
self.joins = joins
|
||||
self.kicks = kicks
|
||||
self.modes = modes
|
||||
self.msgs = msgs
|
||||
self.parts = parts
|
||||
self.quits = quits
|
||||
self.smileys = smileys
|
||||
self.topics = topics
|
||||
self.words = words
|
||||
self._values = ['actions', 'chars', 'frowns', 'joins', 'kicks','modes',
|
||||
'msgs', 'parts', 'quits', 'smileys', 'topics', 'words']
|
||||
def values(self):
|
||||
return map(curry(getattr, self), self._values)
|
||||
|
||||
class ChannelStats(plugins.ChannelDBHandler, callbacks.Privmsg):
|
||||
def addMsg(self, msg):
|
||||
self.msgs += 1
|
||||
method = self.dispatchCommand(msg.command)
|
||||
if method is not None:
|
||||
method(msg)
|
||||
|
||||
def doPayload(self, channel, payload):
|
||||
self.chars += len(payload)
|
||||
self.words += len(payload.split())
|
||||
fRe = conf.supybot.plugins.ChannelStats.get('frowns').get(channel)()
|
||||
sRe =conf.supybot.plugins.ChannelStats.get('smileys').get(channel)()
|
||||
self.frowns += len(fRe.findall(payload))
|
||||
self.smileys += len(sRe.findall(payload))
|
||||
|
||||
def doPrivmsg(self, msg):
|
||||
self.doPayload(*msg.args)
|
||||
if ircmsgs.isAction(msg):
|
||||
self.actions += 1
|
||||
|
||||
def doTopic(self, msg):
|
||||
self.doPayload(*msg.args)
|
||||
self.topics += 1
|
||||
|
||||
def doKick(self, msg):
|
||||
self.kicks += 1
|
||||
|
||||
def doPart(self, msg):
|
||||
self.doPayload(*msg.args)
|
||||
self.parts += 1
|
||||
|
||||
def doMode(self, msg):
|
||||
self.modes += 1
|
||||
|
||||
|
||||
class UserStat(ChannelStat):
|
||||
def __init__(self, id, kicked=0, *args):
|
||||
ChannelStat.__init__(self, *args)
|
||||
self.id = id
|
||||
self.kicked = kicked
|
||||
self._values.insert(0, 'kicked')
|
||||
|
||||
def doKick(self, msg):
|
||||
self.doPayload(msg.args[0], msg.args[2])
|
||||
self.kicks += 1
|
||||
|
||||
class StatsDB(object):
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
self.channels = ircutils.IrcDict()
|
||||
self.channelStats = ircutils.IrcDict()
|
||||
try:
|
||||
fd = file(filename)
|
||||
except EnvironmentError, e:
|
||||
log.info('Couldn\'t open %s: %s', filename, e)
|
||||
return
|
||||
lineno = 0
|
||||
for line in fd:
|
||||
lineno += 1
|
||||
line = line.rstrip('\r\n')
|
||||
try:
|
||||
(channelOrId, rest) = line.split(':', 1)
|
||||
if ircutils.isChannel(channelOrId):
|
||||
channel = channelOrId
|
||||
values = map(int, rest.split(','))
|
||||
self.channelStats[channel] = ChannelStat(*values)
|
||||
else:
|
||||
id = int(channelOrId)
|
||||
(channel, rest) = rest.split(':', 1)
|
||||
d = self.channels.setdefault(channel, {})
|
||||
values = map(int, rest.split(','))
|
||||
d[id] = UserStat(id, *values)
|
||||
except ValueError:
|
||||
log.warning('Invalid line (#%s): %r', lineno, line)
|
||||
continue
|
||||
fd.close()
|
||||
|
||||
def flush(self):
|
||||
fd = file(self.filename, 'w')
|
||||
L = self.channelStats.items()
|
||||
L.sort()
|
||||
for (channel, stat) in L:
|
||||
fd.write('%s:%s' % (channel, ','.join(map(str, stat.values()))))
|
||||
fd.write(os.linesep)
|
||||
if channel not in self.channels:
|
||||
continue
|
||||
d = self.channels[channel]
|
||||
LL = d.items()
|
||||
LL.sort()
|
||||
for (id, stat) in LL:
|
||||
fd.write('%s:%s:%s' % (id, channel,
|
||||
','.join(map(str, stat.values()))))
|
||||
fd.write(os.linesep)
|
||||
fd.close()
|
||||
|
||||
def close(self):
|
||||
self.flush()
|
||||
self.channels.clear()
|
||||
self.channelStats.clear()
|
||||
|
||||
def addMsg(self, msg, id=None):
|
||||
channel = msg.args[0]
|
||||
if ircutils.isChannel(channel):
|
||||
if channel not in self.channelStats:
|
||||
self.channelStats[channel] = ChannelStat()
|
||||
self.channelStats[channel].addMsg(msg)
|
||||
try:
|
||||
if id is None:
|
||||
id = ircdb.users.getUserId(msg.prefix)
|
||||
except KeyError:
|
||||
return
|
||||
if channel not in self.channels:
|
||||
self.channels[channel] = {}
|
||||
if id not in self.channels[channel]:
|
||||
self.channels[channel][id] = UserStat(id)
|
||||
self.channels[channel][id].addMsg(msg)
|
||||
|
||||
def get(self, channel, id=None):
|
||||
if id is None:
|
||||
return self.channelStats[channel]
|
||||
else:
|
||||
return self.channels[channel][id]
|
||||
|
||||
|
||||
class ChannelStats(callbacks.Privmsg):
|
||||
noIgnore = True
|
||||
def __init__(self):
|
||||
callbacks.Privmsg.__init__(self)
|
||||
plugins.ChannelDBHandler.__init__(self)
|
||||
self.lastmsg = None
|
||||
self.laststate = None
|
||||
self.outFiltering = False
|
||||
self.db = StatsDB(os.path.join(conf.supybot.directories.data(),
|
||||
'ChannelStats.db'))
|
||||
world.flushers.append(self.db.flush)
|
||||
|
||||
def die(self):
|
||||
world.flushers.remove(self.db.flush)
|
||||
self.db.close()
|
||||
callbacks.Privmsg.die(self)
|
||||
plugins.ChannelDBHandler.die(self)
|
||||
|
||||
def makeDb(self, filename):
|
||||
if os.path.exists(filename):
|
||||
db = sqlite.connect(filename)
|
||||
else:
|
||||
db = sqlite.connect(filename)
|
||||
cursor = db.cursor()
|
||||
cursor.execute("""CREATE TABLE user_stats (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER UNIQUE ON CONFLICT IGNORE,
|
||||
smileys INTEGER,
|
||||
frowns INTEGER,
|
||||
chars INTEGER,
|
||||
words INTEGER,
|
||||
msgs INTEGER,
|
||||
actions INTEGER,
|
||||
joins INTEGER,
|
||||
parts INTEGER,
|
||||
kicks INTEGER,
|
||||
kicked INTEGER,
|
||||
modes INTEGER,
|
||||
topics INTEGER,
|
||||
quits INTEGER
|
||||
)""")
|
||||
cursor.execute("""CREATE TABLE channel_stats (
|
||||
smileys INTEGER,
|
||||
frowns INTEGER,
|
||||
chars INTEGER,
|
||||
words INTEGER,
|
||||
msgs INTEGER,
|
||||
actions INTEGER,
|
||||
joins INTEGER,
|
||||
parts INTEGER,
|
||||
kicks INTEGER,
|
||||
modes INTEGER,
|
||||
topics INTEGER,
|
||||
quits INTEGER
|
||||
)""")
|
||||
cursor.execute("""INSERT INTO channel_stats
|
||||
VALUES (0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0)""")
|
||||
db.commit()
|
||||
return db
|
||||
|
||||
def __call__(self, irc, msg):
|
||||
try:
|
||||
@ -155,152 +260,49 @@ class ChannelStats(plugins.ChannelDBHandler, callbacks.Privmsg):
|
||||
self.laststate = irc.state.copy()
|
||||
finally:
|
||||
self.lastmsg = msg
|
||||
self.db.addMsg(msg)
|
||||
super(ChannelStats, self).__call__(irc, msg)
|
||||
|
||||
def doPrivmsg(self, irc, msg):
|
||||
if not ircutils.isChannel(msg.args[0]):
|
||||
return
|
||||
else:
|
||||
self._updatePrivmsgStats(msg)
|
||||
|
||||
def _updatePrivmsgStats(self, msg):
|
||||
(channel, s) = msg.args
|
||||
db = self.getDb(channel)
|
||||
cursor = db.cursor()
|
||||
chars = len(s)
|
||||
words = len(s.split())
|
||||
isAction = ircmsgs.isAction(msg)
|
||||
frowns = len(self.registryValue('frowns', channel).findall(s))
|
||||
smileys = len(self.registryValue('smileys', channel).findall(s))
|
||||
s = ircmsgs.prettyPrint(msg)
|
||||
cursor.execute("""UPDATE channel_stats
|
||||
SET smileys=smileys+%s,
|
||||
frowns=frowns+%s,
|
||||
chars=chars+%s,
|
||||
words=words+%s,
|
||||
msgs=msgs+1,
|
||||
actions=actions+%s""",
|
||||
smileys, frowns, chars, words, int(isAction))
|
||||
try:
|
||||
if self.outFiltering:
|
||||
id = 0
|
||||
else:
|
||||
id = ircdb.users.getUserId(msg.prefix)
|
||||
except KeyError:
|
||||
return
|
||||
cursor.execute("""INSERT INTO user_stats VALUES (
|
||||
NULL, %s, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0)""", id)
|
||||
cursor.execute("""UPDATE user_stats SET
|
||||
chars=chars+%s,
|
||||
words=words+%s, msgs=msgs+1,
|
||||
actions=actions+%s, smileys=smileys+%s,
|
||||
frowns=frowns+%s
|
||||
WHERE user_id=%s""",
|
||||
chars, words, int(isAction), smileys, frowns, id)
|
||||
db.commit()
|
||||
|
||||
def outFilter(self, irc, msg):
|
||||
if msg.command == 'PRIVMSG':
|
||||
if ircutils.isChannel(msg.args[0]):
|
||||
if self.registryValue('selfStats', msg.args[0]):
|
||||
try:
|
||||
self.outFiltering = True
|
||||
self._updatePrivmsgStats(msg)
|
||||
self.db.addMsg(msg, 0)
|
||||
finally:
|
||||
self.outFiltering = False
|
||||
return msg
|
||||
|
||||
def doPart(self, irc, msg):
|
||||
channel = msg.args[0]
|
||||
db = self.getDb(channel)
|
||||
cursor = db.cursor()
|
||||
cursor.execute("""UPDATE channel_stats SET parts=parts+1""")
|
||||
try:
|
||||
id = ircdb.users.getUserId(msg.prefix)
|
||||
cursor.execute("""UPDATE user_stats SET parts=parts+1
|
||||
WHERE user_id=%s""", id)
|
||||
except KeyError:
|
||||
pass
|
||||
db.commit()
|
||||
|
||||
def doTopic(self, irc, msg):
|
||||
channel = msg.args[0]
|
||||
db = self.getDb(channel)
|
||||
cursor = db.cursor()
|
||||
cursor.execute("""UPDATE channel_stats SET topics=topics+1""")
|
||||
try:
|
||||
id = ircdb.users.getUserId(msg.prefix)
|
||||
cursor.execute("""UPDATE user_stats
|
||||
SET topics=topics+1
|
||||
WHERE user_id=%s""", id)
|
||||
except KeyError:
|
||||
pass
|
||||
db.commit()
|
||||
|
||||
def doMode(self, irc, msg):
|
||||
channel = msg.args[0]
|
||||
db = self.getDb(channel)
|
||||
cursor = db.cursor()
|
||||
cursor.execute("""UPDATE channel_stats SET modes=modes+1""")
|
||||
try:
|
||||
id = ircdb.users.getUserId(msg.prefix)
|
||||
cursor.execute("""UPDATE user_stats
|
||||
SET modes=modes+1
|
||||
WHERE user_id=%s""", id)
|
||||
except KeyError:
|
||||
pass
|
||||
db.commit()
|
||||
|
||||
def doKick(self, irc, msg):
|
||||
channel = msg.args[0]
|
||||
db = self.getDb(channel)
|
||||
cursor = db.cursor()
|
||||
cursor.execute("""UPDATE channel_stats SET kicks=kicks+1""")
|
||||
try:
|
||||
id = ircdb.users.getUserId(msg.prefix)
|
||||
cursor.execute("""UPDATE user_stats
|
||||
SET kicks=kicks+1
|
||||
WHERE user_id=%s""", id)
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
kicked = msg.args[1]
|
||||
id = ircdb.users.getUserId(irc.state.nickToHostmask(kicked))
|
||||
cursor.execute("""UPDATE user_stats
|
||||
SET kicked=kicked+1
|
||||
WHERE user_id=%s""", id)
|
||||
except KeyError:
|
||||
pass
|
||||
db.commit()
|
||||
|
||||
def doJoin(self, irc, msg):
|
||||
channel = msg.args[0]
|
||||
db = self.getDb(channel)
|
||||
cursor = db.cursor()
|
||||
cursor.execute("""UPDATE channel_stats SET joins=joins+1""")
|
||||
try:
|
||||
id = ircdb.users.getUserId(msg.prefix)
|
||||
cursor.execute("""UPDATE user_stats
|
||||
SET joins=joins+1
|
||||
WHERE user_id=%s""", id)
|
||||
except KeyError:
|
||||
pass
|
||||
db.commit()
|
||||
|
||||
def doQuit(self, irc, msg):
|
||||
try:
|
||||
id = ircdb.users.getUserId(msg.prefix)
|
||||
except KeyError:
|
||||
id = None
|
||||
for (channel, c) in self.laststate.channels.iteritems():
|
||||
if msg.nick in c.users:
|
||||
db = self.getDb(channel)
|
||||
cursor = db.cursor()
|
||||
cursor.execute("""UPDATE channel_stats SET quits=quits+1""")
|
||||
try:
|
||||
id = ircdb.users.getUserId(msg.prefix)
|
||||
cursor.execute("""UPDATE user_stats SET quits=quits+1
|
||||
WHERE user_id=%s""", id)
|
||||
except KeyError:
|
||||
pass
|
||||
db.commit()
|
||||
if channel not in self.db.channelStats:
|
||||
self.db.channelStats[channel] = ChannelStat()
|
||||
self.db.channelStats[channel].quits += 1
|
||||
if id is not None:
|
||||
if channel not in self.db.channels:
|
||||
self.db.channels[channel] = {}
|
||||
if id not in self.db.channels[channel]:
|
||||
self.db.channels[channel][id] = UserStat(id)
|
||||
self.db.channels[channel][id].quits += 1
|
||||
|
||||
def doKick(self, irc, msg):
|
||||
(channel, nick, _) = msg.args
|
||||
hostmask = irc.state.nickToHostmask(nick)
|
||||
try:
|
||||
id = ircdb.users.getUserId(hostmask)
|
||||
except KeyError:
|
||||
return
|
||||
if channel not in self.db.channels:
|
||||
self.db.channels[channel] = {}
|
||||
if id not in self.db.channels[channel]:
|
||||
self.db.channels[channel][id] = UserStat(id)
|
||||
self.db.channels[channel][id].kicked += 1
|
||||
|
||||
def stats(self, irc, msg, args):
|
||||
"""[<channel>] [<name>]
|
||||
@ -329,34 +331,31 @@ class ChannelStats(plugins.ChannelDBHandler, callbacks.Privmsg):
|
||||
return
|
||||
else:
|
||||
id = ircdb.users.getUserId(name)
|
||||
db = self.getDb(channel)
|
||||
cursor = db.cursor()
|
||||
cursor.execute("""SELECT * FROM user_stats WHERE user_id=%s""", id)
|
||||
if cursor.rowcount == 0:
|
||||
irc.error('I have no stats for that user.')
|
||||
return
|
||||
values = cursor.fetchone()
|
||||
s = '%s has sent %s; a total of %s, %s, ' \
|
||||
'%s, and %s; %s of those messages %s' \
|
||||
'%s has joined %s, parted %s, quit %s, kicked someone %s, ' \
|
||||
'been kicked %s, changed the topic %s, ' \
|
||||
'and changed the mode %s.' % \
|
||||
(name, utils.nItems('message', values.msgs),
|
||||
utils.nItems('character', values.chars),
|
||||
utils.nItems('word', values.words),
|
||||
utils.nItems('smiley', values.smileys),
|
||||
utils.nItems('frown', values.frowns),
|
||||
values.actions, values.actions == 1 and 'was an ACTION. '
|
||||
or 'were ACTIONs. ',
|
||||
name,
|
||||
utils.nItems('time', values.joins),
|
||||
utils.nItems('time', values.parts),
|
||||
utils.nItems('time', values.quits),
|
||||
utils.nItems('time', values.kicks),
|
||||
utils.nItems('time', values.kicked),
|
||||
utils.nItems('time', values.topics),
|
||||
utils.nItems('time', values.modes))
|
||||
irc.reply(s)
|
||||
try:
|
||||
stats = self.db.get(channel, id)
|
||||
s = '%s has sent %s; a total of %s, %s, ' \
|
||||
'%s, and %s; %s of those messages %s' \
|
||||
'%s has joined %s, parted %s, quit %s, kicked someone %s, ' \
|
||||
'been kicked %s, changed the topic %s, ' \
|
||||
'and changed the mode %s.' % \
|
||||
(name, utils.nItems('message', stats.msgs),
|
||||
utils.nItems('character', stats.chars),
|
||||
utils.nItems('word', stats.words),
|
||||
utils.nItems('smiley', stats.smileys),
|
||||
utils.nItems('frown', stats.frowns),
|
||||
stats.actions, stats.actions == 1 and 'was an ACTION. '
|
||||
or 'were ACTIONs. ',
|
||||
name,
|
||||
utils.nItems('time', stats.joins),
|
||||
utils.nItems('time', stats.parts),
|
||||
utils.nItems('time', stats.quits),
|
||||
utils.nItems('time', stats.kicks),
|
||||
utils.nItems('time', stats.kicked),
|
||||
utils.nItems('time', stats.topics),
|
||||
utils.nItems('time', stats.modes))
|
||||
irc.reply(s)
|
||||
except KeyError:
|
||||
irc.error('I have no stats for that %s in %s' % (name, channel))
|
||||
|
||||
def channelstats(self, irc, msg, args):
|
||||
"""[<channel>]
|
||||
@ -365,19 +364,27 @@ class ChannelStats(plugins.ChannelDBHandler, callbacks.Privmsg):
|
||||
the message isn't sent on the channel itself.
|
||||
"""
|
||||
channel = privmsgs.getChannel(msg, args)
|
||||
db = self.getDb(channel)
|
||||
cursor = db.cursor()
|
||||
cursor.execute("""SELECT * FROM channel_stats""")
|
||||
values = cursor.fetchone()
|
||||
s = 'On %s there have been %s messages, containing %s characters, ' \
|
||||
'%s words, %s smileys, and %s frowns; %s of those messages were ' \
|
||||
'ACTIONs. There have been %s joins, %s parts, %s quits, ' \
|
||||
'%s kicks, %s mode changes, and %s topic changes.' % \
|
||||
(channel, values.msgs, values.chars,
|
||||
values.words, values.smileys, values.frowns, values.actions,
|
||||
values.joins, values.parts, values.quits,
|
||||
values.kicks, values.modes, values.topics)
|
||||
irc.reply(s)
|
||||
try:
|
||||
stats = self.db.get(channel)
|
||||
s = 'On %s there have been %s messages, containing %s ' \
|
||||
'characters, %s, %s, and %s; ' \
|
||||
'%s of those messages %s. There have been ' \
|
||||
'%s, %s, %s, %s, %s, and %s.' % \
|
||||
(channel, stats.msgs, stats.chars,
|
||||
utils.nItems('word', stats.words),
|
||||
utils.nItems('smiley', stats.smileys),
|
||||
utils.nItems('frown', stats.frowns),
|
||||
stats.actions, stats.actions == 1 and 'was an ACTION'
|
||||
or 'were ACTIONs',
|
||||
utils.nItems('join', stats.joins),
|
||||
utils.nItems('part', stats.parts),
|
||||
utils.nItems('quit', stats.quits),
|
||||
utils.nItems('kick', stats.kicks),
|
||||
utils.nItems('change', stats.modes, between='mode'),
|
||||
utils.nItems('change', stats.topics, between='topic'))
|
||||
irc.reply(s)
|
||||
except KeyError:
|
||||
irc.error('I\'ve never been on %s.' % channel)
|
||||
|
||||
|
||||
Class = ChannelStats
|
||||
|
Loading…
Reference in New Issue
Block a user