Misc & lint fixes
This commit is contained in:
parent
e11d068a6e
commit
fa8783e6cc
@ -6,7 +6,8 @@ from pyircbot import PyIRCBot
|
||||
|
||||
if __name__ == "__main__":
|
||||
" logging level and facility "
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)-15s %(levelname)-8s %(filename)s:%(lineno)d %(message)s")
|
||||
logging.basicConfig(level=logging.INFO,
|
||||
format="%(asctime)-15s %(levelname)-8s %(filename)s:%(lineno)d %(message)s")
|
||||
log = logging.getLogger('main')
|
||||
|
||||
" parse command line args "
|
||||
|
@ -24,6 +24,7 @@ try:
|
||||
except:
|
||||
from io import BytesIO as StringIO
|
||||
|
||||
|
||||
IRCEvent = namedtuple("IRCEvent", "args prefix trailing")
|
||||
UserPrefix = namedtuple("UserPrefix", "nick username hostname")
|
||||
ServerPrefix = namedtuple("ServerPrefix", "hostname")
|
||||
@ -34,7 +35,7 @@ class IRCCore(asynchat.async_chat):
|
||||
def __init__(self):
|
||||
asynchat.async_chat.__init__(self)
|
||||
|
||||
self.connected=False
|
||||
self.connected = False
|
||||
"""If we're connected or not"""
|
||||
|
||||
self.log = logging.getLogger('IRCCore')
|
||||
@ -74,7 +75,8 @@ class IRCCore(asynchat.async_chat):
|
||||
while self.alive:
|
||||
try:
|
||||
asyncore.loop(map=self.asynmap, timeout=1)
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
|
||||
self.log.error("Loop error: ")
|
||||
self.log.error(IRCCore.trace())
|
||||
|
||||
@ -86,7 +88,7 @@ class IRCCore(asynchat.async_chat):
|
||||
logging.info("Loop: reconnecting")
|
||||
try:
|
||||
self._connect()
|
||||
except Exception as e2:
|
||||
except Exception:
|
||||
self.log.error("Error reconnecting: ")
|
||||
self.log.error(IRCCore.trace())
|
||||
|
||||
@ -103,10 +105,10 @@ class IRCCore(asynchat.async_chat):
|
||||
# Clear any pending messages
|
||||
self.outputQueueRunner.clear()
|
||||
# Send quit message and flush queue
|
||||
self.act_QUIT(message) # TODO will this hang if the socket is having issues?
|
||||
self.act_QUIT(message) # TODO will this hang if the socket is having issues?
|
||||
self.outputQueueRunner.flush()
|
||||
# Signal disconnection
|
||||
self.alive=alive
|
||||
self.alive = alive
|
||||
# Close socket
|
||||
self.socket.shutdown(SHUT_RDWR)
|
||||
self.close()
|
||||
@ -126,7 +128,7 @@ class IRCCore(asynchat.async_chat):
|
||||
|
||||
:param data: the data that was recieved
|
||||
:type data: str"""
|
||||
#self.log.info("<< %(message)s", {"message":repr(data)})
|
||||
|
||||
self.buffer.write(data)
|
||||
|
||||
def found_terminator(self):
|
||||
@ -147,7 +149,7 @@ class IRCCore(asynchat.async_chat):
|
||||
def handle_close(self):
|
||||
"""Called when the socket is disconnected. Triggers the _DISCONNECT hook"""
|
||||
self.log.info("handle_close")
|
||||
self.connected=False
|
||||
self.connected = False
|
||||
self.close()
|
||||
self.fire_hook("_DISCONNECT")
|
||||
|
||||
@ -156,15 +158,15 @@ class IRCCore(asynchat.async_chat):
|
||||
self.log.error("Connection failed (handle_error)")
|
||||
self.log.error(str(args))
|
||||
self.log.error(str(kwargs))
|
||||
self.log.error(IRCCore.trace());
|
||||
self.log.error(IRCCore.trace())
|
||||
|
||||
def _connect(self):
|
||||
"""Connect to IRC"""
|
||||
self.server+=1
|
||||
self.server += 1
|
||||
if self.server >= len(self.servers):
|
||||
self.server=0
|
||||
self.server = 0
|
||||
serverHostname = self.servers[self.server]
|
||||
self.log.info("Connecting to %(server)s:%(port)i", {"server":serverHostname, "port":self.port})
|
||||
self.log.info("Connecting to %(server)s:%(port)i", {"server": serverHostname, "port": self.port})
|
||||
socket_type = socket.AF_INET
|
||||
if self.ipv6:
|
||||
self.log.info("IPv6 is enabled.")
|
||||
@ -175,12 +177,13 @@ class IRCCore(asynchat.async_chat):
|
||||
self.connect(socketInfo[0][4])
|
||||
self.log.info("Connection established")
|
||||
self._fileno = self.socket.fileno()
|
||||
self.asynmap[self._fileno] = self # http://willpython.blogspot.com/2010/08/multiple-event-loops-with-asyncore-and.html
|
||||
# See http://willpython.blogspot.com/2010/08/multiple-event-loops-with-asyncore-and.html
|
||||
self.asynmap[self._fileno] = self
|
||||
self.log.info("_connect: Socket map: %s" % str(self.asynmap))
|
||||
|
||||
def handle_connect(self):
|
||||
"""When asynchat indicates our socket is connected, fire the _CONNECT hook"""
|
||||
self.connected=True
|
||||
self.connected = True
|
||||
self.log.info("handle_connect: connected")
|
||||
self.fire_hook("_CONNECT")
|
||||
self.log.info("handle_connect: complete")
|
||||
@ -190,7 +193,7 @@ class IRCCore(asynchat.async_chat):
|
||||
|
||||
:param text: the string to send
|
||||
:type text: str"""
|
||||
text = (text+"\r\n").encode("UTF-8").decode().encode("UTF-8")
|
||||
text = (text + "\r\n").encode("UTF-8").decode().encode("UTF-8")
|
||||
self.outputQueue.put((prio, text), block=False)
|
||||
|
||||
def process_data(self, data):
|
||||
@ -203,71 +206,71 @@ class IRCCore(asynchat.async_chat):
|
||||
|
||||
prefix = None
|
||||
command = None
|
||||
args=[]
|
||||
trailing=None
|
||||
args = []
|
||||
trailing = None
|
||||
|
||||
if data[0]==":":
|
||||
prefix=data.split(" ")[0][1:]
|
||||
data=data[data.find(" ")+1:]
|
||||
if data[0] == ":":
|
||||
prefix = data.split(" ")[0][1:]
|
||||
data = data[data.find(" ") + 1:]
|
||||
command = data.split(" ")[0]
|
||||
data=data[data.find(" ")+1:]
|
||||
if(data[0]==":"):
|
||||
data = data[data.find(" ") + 1:]
|
||||
if(data[0] == ":"):
|
||||
# no args
|
||||
trailing = data[1:].strip()
|
||||
else:
|
||||
trailing = data[data.find(" :")+2:].strip()
|
||||
trailing = data[data.find(" :") + 2:].strip()
|
||||
data = data[:data.find(" :")]
|
||||
args = data.split(" ")
|
||||
for index,arg in enumerate(args):
|
||||
args[index]=arg.strip()
|
||||
for index, arg in enumerate(args):
|
||||
args[index] = arg.strip()
|
||||
self.fire_hook("_RECV", args=args, prefix=prefix, trailing=trailing)
|
||||
if not command in self.hookcalls:
|
||||
self.log.warning("Unknown command: cmd='%s' prefix='%s' args='%s' trailing='%s'" % (command, prefix, args, trailing))
|
||||
if command not in self.hookcalls:
|
||||
self.log.warning("Unknown command: cmd='%s' prefix='%s' args='%s' trailing='%s'" % (command, prefix, args,
|
||||
trailing))
|
||||
else:
|
||||
self.fire_hook(command, args=args, prefix=prefix, trailing=trailing)
|
||||
|
||||
|
||||
" Module related code "
|
||||
def initHooks(self):
|
||||
"""Defines hooks that modules can listen for events of"""
|
||||
self.hooks = [
|
||||
'_CONNECT', # Called when the bot connects to IRC on the socket level
|
||||
'_DISCONNECT', # Called when the irc socket is forcibly closed
|
||||
'_RECV', # Called on network activity
|
||||
'NOTICE', # :irc.129irc.com NOTICE AUTH :*** Looking up your hostname...
|
||||
'MODE', # :CloneABCD MODE CloneABCD :+iwx
|
||||
'PING', # PING :irc.129irc.com
|
||||
'JOIN', # :CloneA!dave@hidden-B4F6B1AA.rit.edu JOIN :#clonea
|
||||
'QUIT', # :HCSMPBot!~HCSMPBot@108.170.48.18 QUIT :Quit: Disconnecting!
|
||||
'NICK', # :foxiAway!foxi@irc.hcsmp.com NICK :foxi
|
||||
'PART', # :CloneA!dave@hidden-B4F6B1AA.rit.edu PART #clonea
|
||||
'PRIVMSG', # :CloneA!dave@hidden-B4F6B1AA.rit.edu PRIVMSG #clonea :aaa
|
||||
'KICK', # :xMopxShell!~rduser@host KICK #xMopx2 xBotxShellTest :xBotxShellTest
|
||||
'INVITE', # :gmx!~gmxgeek@irc.hcsmp.com INVITE Tyrone :#hcsmp'
|
||||
'001', # :irc.129irc.com 001 CloneABCD :Welcome to the 129irc IRC Network CloneABCD!CloneABCD@djptwc-laptop1.rit.edu
|
||||
'002', # :irc.129irc.com 002 CloneABCD :Your host is irc.129irc.com, running version Unreal3.2.8.1
|
||||
'003', # :irc.129irc.com 003 CloneABCD :This server was created Mon Jul 19 2010 at 03:12:01 EDT
|
||||
'004', # :irc.129irc.com 004 CloneABCD irc.129irc.com Unreal3.2.8.1 iowghraAsORTVSxNCWqBzvdHtGp lvhopsmntikrRcaqOALQbSeIKVfMCuzNTGj
|
||||
'005', # :irc.129irc.com 005 CloneABCD CMDS=KNOCK,MAP,DCCALLOW,USERIP UHNAMES NAMESX SAFELIST HCN MAXCHANNELS=10 CHANLIMIT=#:10 MAXLIST=b:60,e:60,I:60 NICKLEN=30 CHANNELLEN=32 TOPICLEN=307 KICKLEN=307 AWAYLEN=307 :are supported by this server
|
||||
'250', # :chaos.esper.net 250 xBotxShellTest :Highest connection count: 1633 (1632 clients) (186588 connections received)
|
||||
'251', # :irc.129irc.com 251 CloneABCD :There are 1 users and 48 invisible on 2 servers
|
||||
'252', # :irc.129irc.com 252 CloneABCD 9 :operator(s) online
|
||||
'254', # :irc.129irc.com 254 CloneABCD 6 :channels formed
|
||||
'255', # :irc.129irc.com 255 CloneABCD :I have 42 clients and 1 servers
|
||||
'265', # :irc.129irc.com 265 CloneABCD :Current Local Users: 42 Max: 47
|
||||
'266', # :irc.129irc.com 266 CloneABCD :Current Global Users: 49 Max: 53
|
||||
'332', # :chaos.esper.net 332 xBotxShellTest #xMopx2 :/ #XMOPX2 / https://code.google.com/p/pyircbot/ (Channel Topic)
|
||||
'333', # :chaos.esper.net 333 xBotxShellTest #xMopx2 xMopxShell!~rduser@108.170.60.242 1344370109
|
||||
'353', # :irc.129irc.com 353 CloneABCD = #clonea :CloneABCD CloneABC
|
||||
'366', # :irc.129irc.com 366 CloneABCD #clonea :End of /NAMES list.
|
||||
'372', # :chaos.esper.net 372 xBotxShell :motd text here
|
||||
'375', # :chaos.esper.net 375 xBotxShellTest :- chaos.esper.net Message of the Day -
|
||||
'376', # :chaos.esper.net 376 xBotxShell :End of /MOTD command.
|
||||
'422', # :irc.129irc.com 422 CloneABCD :MOTD File is missing
|
||||
'433', # :nova.esper.net 433 * pyircbot3 :Nickname is already in use.
|
||||
'_CONNECT', # Called when the bot connects to IRC on the socket level
|
||||
'_DISCONNECT', # Called when the irc socket is forcibly closed
|
||||
'_RECV', # Called on network activity
|
||||
'NOTICE', # :irc.129irc.com NOTICE AUTH :*** Looking up your hostname...
|
||||
'MODE', # :CloneABCD MODE CloneABCD :+iwx
|
||||
'PING', # PING :irc.129irc.com
|
||||
'JOIN', # :CloneA!dave@hidden-B4F6B1AA.rit.edu JOIN :#clonea
|
||||
'QUIT', # :HCSMPBot!~HCSMPBot@108.170.48.18 QUIT :Quit: Disconnecting!
|
||||
'NICK', # :foxiAway!foxi@irc.hcsmp.com NICK :foxi
|
||||
'PART', # :CloneA!dave@hidden-B4F6B1AA.rit.edu PART #clonea
|
||||
'PRIVMSG', # :CloneA!dave@hidden-B4F6B1AA.rit.edu PRIVMSG #clonea :aaa
|
||||
'KICK', # :xMopxShell!~rduser@host KICK #xMopx2 xBotxShellTest :xBotxShellTest
|
||||
'INVITE', # :gmx!~gmxgeek@irc.hcsmp.com INVITE Tyrone :#hcsmp'
|
||||
'001', # :irc.129irc.com 001 CloneABCD :Welcome to the 129irc IRC Network CloneABCD!CloneABCD@djptwc-laptop1.rit.edu
|
||||
'002', # :irc.129irc.com 002 CloneABCD :Your host is irc.129irc.com, running version Unreal3.2.8.1
|
||||
'003', # :irc.129irc.com 003 CloneABCD :This server was created Mon Jul 19 2010 at 03:12:01 EDT
|
||||
'004', # :irc.129irc.com 004 CloneABCD irc.129irc.com Unreal3.2.8.1 iowghraAsORTVSxNCWqBzvdHtGp lvhopsmntikrRcaqOALQbSeIKVfMCuzNTGj
|
||||
'005', # :irc.129irc.com 005 CloneABCD CMDS=KNOCK,MAP,DCCALLOW,USERIP UHNAMES NAMESX SAFELIST HCN MAXCHANNELS=10 CHANLIMIT=#:10 MAXLIST=b:60,e:60,I:60 NICKLEN=30 CHANNELLEN=32 TOPICLEN=307 KICKLEN=307 AWAYLEN=307 :are supported by this server
|
||||
'250', # :chaos.esper.net 250 xBotxShellTest :Highest connection count: 1633 (1632 clients) (186588 connections received)
|
||||
'251', # :irc.129irc.com 251 CloneABCD :There are 1 users and 48 invisible on 2 servers
|
||||
'252', # :irc.129irc.com 252 CloneABCD 9 :operator(s) online
|
||||
'254', # :irc.129irc.com 254 CloneABCD 6 :channels formed
|
||||
'255', # :irc.129irc.com 255 CloneABCD :I have 42 clients and 1 servers
|
||||
'265', # :irc.129irc.com 265 CloneABCD :Current Local Users: 42 Max: 47
|
||||
'266', # :irc.129irc.com 266 CloneABCD :Current Global Users: 49 Max: 53
|
||||
'332', # :chaos.esper.net 332 xBotxShellTest #xMopx2 :/ #XMOPX2 / https://code.google.com/p/pyircbot/ (Channel Topic)
|
||||
'333', # :chaos.esper.net 333 xBotxShellTest #xMopx2 xMopxShell!~rduser@108.170.60.242 1344370109
|
||||
'353', # :irc.129irc.com 353 CloneABCD = #clonea :CloneABCD CloneABC
|
||||
'366', # :irc.129irc.com 366 CloneABCD #clonea :End of /NAMES list.
|
||||
'372', # :chaos.esper.net 372 xBotxShell :motd text here
|
||||
'375', # :chaos.esper.net 375 xBotxShellTest :- chaos.esper.net Message of the Day -
|
||||
'376', # :chaos.esper.net 376 xBotxShell :End of /MOTD command.
|
||||
'422', # :irc.129irc.com 422 CloneABCD :MOTD File is missing
|
||||
'433', # :nova.esper.net 433 * pyircbot3 :Nickname is already in use.
|
||||
]
|
||||
" mapping of hooks to methods "
|
||||
self.hookcalls = {command:[] for command in self.hooks}
|
||||
self.hookcalls = {command: [] for command in self.hooks}
|
||||
|
||||
def fire_hook(self, command, args=None, prefix=None, trailing=None):
|
||||
"""Run any listeners for a specific hook
|
||||
@ -289,7 +292,7 @@ class IRCCore(asynchat.async_chat):
|
||||
hook(args, prefix, trailing)
|
||||
|
||||
except:
|
||||
self.log.warning("Error processing hook: \n%s"% self.trace())
|
||||
self.log.warning("Error processing hook: \n%s" % self.trace())
|
||||
|
||||
def addHook(self, command, method):
|
||||
"""**Internal.** Enable (connect) a single hook of a module
|
||||
@ -343,7 +346,9 @@ class IRCCore(asynchat.async_chat):
|
||||
|
||||
:param prefix: the prefix to disassemble
|
||||
:type prefix: str
|
||||
:returns: object -- an UserPrefix object with the properties `nick`, `username`, `hostname` or a ServerPrefix object with the property `hostname`"""
|
||||
:returns: object -- an UserPrefix object with the properties `nick`, `username`, `hostname` or a ServerPrefix
|
||||
object with the property `hostname`
|
||||
"""
|
||||
if "!" in prefix:
|
||||
nick, prefix = prefix.split("!")
|
||||
username, hostname = prefix.split("@")
|
||||
@ -412,7 +417,7 @@ class IRCCore(asynchat.async_chat):
|
||||
|
||||
:param channel: the channel to attempt to join
|
||||
:type channel: str"""
|
||||
self.sendRaw("JOIN %s"%channel)
|
||||
self.sendRaw("JOIN %s" % channel)
|
||||
|
||||
def act_PRIVMSG(self, towho, message):
|
||||
"""Use the `/msg` command
|
||||
@ -421,7 +426,7 @@ class IRCCore(asynchat.async_chat):
|
||||
:type towho: str
|
||||
:param message: the message to send
|
||||
:type message: str"""
|
||||
self.sendRaw("PRIVMSG %s :%s"%(towho,message))
|
||||
self.sendRaw("PRIVMSG %s :%s" % (towho, message))
|
||||
|
||||
def act_MODE(self, channel, mode, extra=None):
|
||||
"""Use the `/mode` command
|
||||
@ -432,10 +437,10 @@ class IRCCore(asynchat.async_chat):
|
||||
:type mode: str
|
||||
:param extra: additional argument if the mode needs it. Example: user@*!*
|
||||
:type extra: str"""
|
||||
if extra != None:
|
||||
self.sendRaw("MODE %s %s %s" % (channel,mode,extra))
|
||||
if extra is not None:
|
||||
self.sendRaw("MODE %s %s %s" % (channel, mode, extra))
|
||||
else:
|
||||
self.sendRaw("MODE %s %s" % (channel,mode))
|
||||
self.sendRaw("MODE %s %s" % (channel, mode))
|
||||
|
||||
def act_ACTION(self, channel, action):
|
||||
"""Use the `/me <action>` command
|
||||
@ -444,7 +449,7 @@ class IRCCore(asynchat.async_chat):
|
||||
:type channel: str
|
||||
:param action: the text to send
|
||||
:type action: str"""
|
||||
self.sendRaw("PRIVMSG %s :\x01ACTION %s"%(channel,action))
|
||||
self.sendRaw("PRIVMSG %s :\x01ACTION %s" % (channel, action))
|
||||
|
||||
def act_KICK(self, channel, who, comment=""):
|
||||
"""Use the `/kick <user> <message>` command
|
||||
@ -464,11 +469,18 @@ class IRCCore(asynchat.async_chat):
|
||||
:type message: str"""
|
||||
self.sendRaw("QUIT :%s" % message, prio=0)
|
||||
|
||||
def act_PASS(self, password):
|
||||
"""
|
||||
Send server password, for use on connection
|
||||
"""
|
||||
self.sendRaw("PASS %s" % password, prio=0)
|
||||
|
||||
|
||||
class OutputQueueRunner(Thread):
|
||||
"""Rate-limited output queue"""
|
||||
def __init__(self, bot):
|
||||
Thread.__init__(self, daemon=True)
|
||||
self.bot = bot #reference to main bot thread
|
||||
self.bot = bot # reference to main bot thread
|
||||
self.log = logging.getLogger('OutputQueueRunner')
|
||||
self.paused = False
|
||||
|
||||
@ -488,14 +500,14 @@ class OutputQueueRunner(Thread):
|
||||
self.process_queue_item()
|
||||
lastSend = time()
|
||||
except queue.Empty:
|
||||
#self.log.info("Queue is empty")
|
||||
# self.log.debug("Queue is empty")
|
||||
pass
|
||||
sleep(0.01)
|
||||
|
||||
def process_queue_item(self):
|
||||
"""Remove 1 item from queue and process it"""
|
||||
prio,text = self.bot.outputQueue.get(block=True, timeout=10)
|
||||
#self.log.info("%s>> %s" % (prio,text))
|
||||
prio, text = self.bot.outputQueue.get(block=True, timeout=10)
|
||||
# self.log.debug("%s>> %s" % (prio,text))
|
||||
self.bot.outputQueue.task_done()
|
||||
self.log.debug("> {}".format(text.decode('UTF-8')))
|
||||
self.bot.send(text)
|
||||
@ -508,7 +520,7 @@ class OutputQueueRunner(Thread):
|
||||
self.bot.outputQueue.get(block=False)
|
||||
except queue.Empty:
|
||||
pass
|
||||
#self.log.info("output queue cleared")
|
||||
# self.log.debug("output queue cleared")
|
||||
return length
|
||||
|
||||
def flush(self):
|
||||
@ -518,4 +530,4 @@ class OutputQueueRunner(Thread):
|
||||
self.process_queue_item()
|
||||
except:
|
||||
pass
|
||||
#self.log.info("output queue flushed")
|
||||
# self.log.debug("output queue flushed")
|
||||
|
@ -7,7 +7,6 @@
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
from .pyircbot import PyIRCBot
|
||||
|
||||
|
||||
@ -21,20 +20,20 @@ class ModuleBase:
|
||||
"""
|
||||
|
||||
def __init__(self, bot, moduleName):
|
||||
self.moduleName=moduleName
|
||||
self.moduleName = moduleName
|
||||
"""Assigned name of this module"""
|
||||
|
||||
self.bot = bot
|
||||
"""Reference to the master PyIRCBot object"""
|
||||
|
||||
self.hooks=[]
|
||||
self.hooks = []
|
||||
"""Hooks (aka listeners) this module has"""
|
||||
|
||||
self.services=[]
|
||||
self.services = []
|
||||
"""If this module provides services usable by another module, they're listed
|
||||
here"""
|
||||
|
||||
self.config={}
|
||||
self.config = {}
|
||||
"""Configuration dictionary. Autoloaded from `%(datadir)s/%(modulename)s.json`"""
|
||||
|
||||
self.log = logging.getLogger("Module.%s" % self.moduleName)
|
||||
@ -70,7 +69,8 @@ class ModuleBase:
|
||||
writable. The bot's data dir *should* always be writable"""
|
||||
return self.bot.getDataPath(self.moduleName) + (f if f else '')
|
||||
|
||||
|
||||
class ModuleHook:
|
||||
def __init__(self, hook, method):
|
||||
self.hook=hook
|
||||
self.method=method
|
||||
self.hook = hook
|
||||
self.method = method
|
||||
|
@ -7,21 +7,22 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase
|
||||
|
||||
|
||||
class AttributeStorage(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[]
|
||||
self.services=["attributes"]
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = []
|
||||
self.services = ["attributes"]
|
||||
self.db = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("mysql")
|
||||
if len(serviceProviders)==0:
|
||||
if len(serviceProviders) == 0:
|
||||
self.log.error("AttributeStorage: Could not find a valid mysql service provider")
|
||||
else:
|
||||
self.log.info("AttributeStorage: Selecting mysql service provider: %s" % serviceProviders[0])
|
||||
self.db = serviceProviders[0]
|
||||
|
||||
|
||||
if not self.db.connection.tableExists("attribute"):
|
||||
self.log.info("AttributeStorage: Creating table: attribute")
|
||||
c = self.db.connection.query("""CREATE TABLE IF NOT EXISTS `attribute` (
|
||||
@ -31,7 +32,7 @@ class AttributeStorage(ModuleBase):
|
||||
UNIQUE KEY `attribute` (`attribute`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;""")
|
||||
c.close()
|
||||
|
||||
|
||||
if not self.db.connection.tableExists("items"):
|
||||
self.log.info("AttributeStorage: Creating table: items")
|
||||
c = self.db.connection.query("""CREATE TABLE IF NOT EXISTS `items` (
|
||||
@ -40,7 +41,7 @@ class AttributeStorage(ModuleBase):
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;""")
|
||||
c.close()
|
||||
|
||||
|
||||
if not self.db.connection.tableExists("values"):
|
||||
self.log.info("AttributeStorage: Creating table: values")
|
||||
c = self.db.connection.query("""CREATE TABLE IF NOT EXISTS `values` (
|
||||
@ -50,20 +51,14 @@ class AttributeStorage(ModuleBase):
|
||||
PRIMARY KEY (`itemid`,`attributeid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 ;""")
|
||||
c.close()
|
||||
|
||||
# self.getItem('xMopxShell', 'name')
|
||||
# self.getKey('xMopxShell', 'name')
|
||||
# self.setKey('xMopxShell', 'name', 'dave')
|
||||
|
||||
# SELECT `i`.`id`, `i`.`item`, `a`.`attribute`, `v`.`value` FROM `items` `i` INNER JOIN `values` `v` on `v`.`itemid`=`i`.`id` INNER JOIN `attribute` `a` on `a`.`id`=`v`.`attributeid` ORDER BY `i`.`id` ASC, `a`.`id` ASC LIMIT 1000 ;
|
||||
|
||||
|
||||
def getItem(self, name):
|
||||
"""Get all values for a item
|
||||
|
||||
|
||||
:param name: the item
|
||||
:type name: str
|
||||
:returns: dict -- the item's values expressed as a dict"""
|
||||
c = self.db.connection.query("""SELECT
|
||||
c = self.db.connection.query("""SELECT
|
||||
`i`.`id`,
|
||||
`i`.`item`,
|
||||
`a`.`attribute`,
|
||||
@ -74,35 +69,33 @@ class AttributeStorage(ModuleBase):
|
||||
on `v`.`itemid`=`i`.`id`
|
||||
INNER JOIN `attribute` `a`
|
||||
on `a`.`id`=`v`.`attributeid`
|
||||
|
||||
WHERE
|
||||
`i`.`item`=%s;""",
|
||||
(name,)
|
||||
)
|
||||
|
||||
WHERE
|
||||
`i`.`item`=%s;""", (name,))
|
||||
item = {}
|
||||
while True:
|
||||
row = c.fetchone()
|
||||
if row == None:
|
||||
if row is None:
|
||||
break
|
||||
item[row["attribute"]]=row["value"]
|
||||
item[row["attribute"]] = row["value"]
|
||||
c.close()
|
||||
|
||||
if len(item)==0:
|
||||
|
||||
if len(item) == 0:
|
||||
return {}
|
||||
return item
|
||||
|
||||
|
||||
def get(self, item, key):
|
||||
return self.getKey(item, key)
|
||||
|
||||
|
||||
def getKey(self, item, key):
|
||||
"""Get the value of an key on an item
|
||||
|
||||
:param item: the item to fetch a key from
|
||||
|
||||
:param item: the item to fetch a key from
|
||||
:type item: str
|
||||
:param key: they key who's value to return
|
||||
:type key: str
|
||||
:returns: str -- the item from the database or **None**"""
|
||||
c = self.db.connection.query("""SELECT
|
||||
c = self.db.connection.query("""SELECT
|
||||
`i`.`id`,
|
||||
`i`.`item`,
|
||||
`a`.`attribute`,
|
||||
@ -113,25 +106,23 @@ class AttributeStorage(ModuleBase):
|
||||
on `v`.`itemid`=`i`.`id`
|
||||
INNER JOIN `attribute` `a`
|
||||
on `a`.`id`=`v`.`attributeid`
|
||||
|
||||
WHERE
|
||||
|
||||
WHERE
|
||||
`i`.`item`=%s
|
||||
AND
|
||||
`a`.`attribute`=%s;""",
|
||||
(item,key)
|
||||
)
|
||||
`a`.`attribute`=%s;""", (item, key))
|
||||
row = c.fetchone()
|
||||
c.close()
|
||||
if row == None:
|
||||
if row is None:
|
||||
return None
|
||||
return row["value"]
|
||||
|
||||
|
||||
def set(self, item, key, value):
|
||||
return self.setKey(item, key, value)
|
||||
|
||||
|
||||
def setKey(self, item, key, value):
|
||||
"""Set the key on an item
|
||||
|
||||
|
||||
:param item: the item name to set the key on
|
||||
:type item: str
|
||||
:param key: the key to set
|
||||
@ -140,35 +131,38 @@ class AttributeStorage(ModuleBase):
|
||||
:type value: str"""
|
||||
item = item.lower()
|
||||
attribute = key.lower()
|
||||
|
||||
|
||||
# Check attribute exists
|
||||
c = self.db.connection.query("SELECT `id` FROM `attribute` WHERE `attribute`=%s;", (attribute))
|
||||
row = c.fetchone()
|
||||
attributeId = -1
|
||||
if row == None:
|
||||
if row is None:
|
||||
c = self.db.connection.query("INSERT INTO `attribute` (`attribute`) VALUES (%s);", (attribute))
|
||||
attributeId = c.lastrowid
|
||||
else:
|
||||
attributeId = row["id"]
|
||||
c.close()
|
||||
|
||||
|
||||
# check item exists
|
||||
c = self.db.connection.query("SELECT `id` FROM `items` WHERE `item`=%s;", (item))
|
||||
row = c.fetchone()
|
||||
itemId = -1
|
||||
if row == None:
|
||||
if row is None:
|
||||
c = self.db.connection.query("INSERT INTO `items` (`item`) VALUES (%s);", (item))
|
||||
itemId = c.lastrowid
|
||||
else:
|
||||
itemId = row["id"]
|
||||
c.close()
|
||||
|
||||
if value == None:
|
||||
|
||||
if value is None:
|
||||
# delete it
|
||||
c = self.db.connection.query("DELETE FROM `values` WHERE `itemid`=%s AND `attributeid`=%s ;", (itemId, attributeId))
|
||||
self.log.info("AttributeStorage: Stored item %s attribute %s value: %s (Deleted)" % (itemId, attributeId, value))
|
||||
c = self.db.connection.query("DELETE FROM `values` WHERE `itemid`=%s AND `attributeid`=%s ;",
|
||||
(itemId, attributeId))
|
||||
self.log.info("AttributeStorage: Stored item %s attribute %s value: %s (Deleted)" %
|
||||
(itemId, attributeId, value))
|
||||
else:
|
||||
# add attribute
|
||||
c = self.db.connection.query("REPLACE INTO `values` (`itemid`, `attributeid`, `value`) VALUES (%s, %s, %s);", (itemId, attributeId, value))
|
||||
c = self.db.connection.query("REPLACE INTO `values` (`itemid`, `attributeid`, `value`) "
|
||||
"VALUES (%s, %s, %s);", (itemId, attributeId, value))
|
||||
self.log.info("AttributeStorage: Stored item %s attribute %s value: %s" % (itemId, attributeId, value))
|
||||
c.close()
|
||||
|
@ -7,22 +7,23 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase
|
||||
|
||||
|
||||
class AttributeStorageLite(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[]
|
||||
self.services=["attributes"]
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = []
|
||||
self.services = ["attributes"]
|
||||
self.db = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("sqlite")
|
||||
if len(serviceProviders)==0:
|
||||
if len(serviceProviders) == 0:
|
||||
self.log.error("Could not find a valid sqlite service provider")
|
||||
raise Exception("No sqlite provider available")
|
||||
else:
|
||||
self.log.info("Selecting sqlite service provider: %s" % serviceProviders[0])
|
||||
self.db = serviceProviders[0].opendb("attributes.db")
|
||||
|
||||
|
||||
if not self.db.tableExists("attribute"):
|
||||
self.log.info("Creating table: attribute")
|
||||
c = self.db.query("""CREATE TABLE IF NOT EXISTS `attribute` (
|
||||
@ -30,7 +31,7 @@ class AttributeStorageLite(ModuleBase):
|
||||
`attribute` varchar(128) UNIQUE
|
||||
) ;""")
|
||||
c.close()
|
||||
|
||||
|
||||
if not self.db.tableExists("items"):
|
||||
self.log.info("Creating table: items")
|
||||
c = self.db.query("""CREATE TABLE IF NOT EXISTS `items` (
|
||||
@ -38,7 +39,7 @@ class AttributeStorageLite(ModuleBase):
|
||||
`item` varchar(512)
|
||||
) ;""")
|
||||
c.close()
|
||||
|
||||
|
||||
if not self.db.tableExists("values"):
|
||||
self.log.info("Creating table: values")
|
||||
c = self.db.query("""CREATE TABLE IF NOT EXISTS `values` (
|
||||
@ -48,18 +49,14 @@ class AttributeStorageLite(ModuleBase):
|
||||
PRIMARY KEY (`itemid`, `attributeid`)
|
||||
) ;""")
|
||||
c.close()
|
||||
|
||||
#print(self.setKey('xmopxshell', 'name', 'dave'))
|
||||
#print(self.getKey('xmopxshell', 'name'))
|
||||
#print(self.getItem('xMopxShell'))
|
||||
|
||||
|
||||
def getItem(self, name):
|
||||
"""Get all values for a item
|
||||
|
||||
|
||||
:param name: the item
|
||||
:type name: str
|
||||
:returns: dict -- the item's values expressed as a dict"""
|
||||
c = self.db.query("""SELECT
|
||||
c = self.db.query("""SELECT
|
||||
`i`.`id`,
|
||||
`i`.`item`,
|
||||
`a`.`attribute`,
|
||||
@ -70,34 +67,33 @@ class AttributeStorageLite(ModuleBase):
|
||||
on `v`.`itemid`=`i`.`id`
|
||||
INNER JOIN `attribute` `a`
|
||||
on `a`.`id`=`v`.`attributeid`
|
||||
|
||||
WHERE
|
||||
`i`.`item`=?;""",
|
||||
(name.lower(),)
|
||||
)
|
||||
|
||||
WHERE
|
||||
`i`.`item`=?;""", (name.lower(),))
|
||||
item = {}
|
||||
while True:
|
||||
row = c.fetchone()
|
||||
if row == None:
|
||||
if row is None:
|
||||
break
|
||||
item[row["attribute"]]=row["value"]
|
||||
item[row["attribute"]] = row["value"]
|
||||
c.close()
|
||||
|
||||
if len(item)==0:
|
||||
|
||||
if not item:
|
||||
return {}
|
||||
return item
|
||||
|
||||
|
||||
def get(self, item, key):
|
||||
return self.getKey(item, key)
|
||||
|
||||
def getKey(self, item, key):
|
||||
"""Get the value of an key on an item
|
||||
|
||||
:param item: the item to fetch a key from
|
||||
|
||||
:param item: the item to fetch a key from
|
||||
:type item: str
|
||||
:param key: they key who's value to return
|
||||
:type key: str
|
||||
:returns: str -- the item from the database or **None**"""
|
||||
c = self.db.query("""SELECT
|
||||
c = self.db.query("""SELECT
|
||||
`i`.`id`,
|
||||
`i`.`item`,
|
||||
`a`.`attribute`,
|
||||
@ -108,25 +104,24 @@ class AttributeStorageLite(ModuleBase):
|
||||
on `v`.`itemid`=`i`.`id`
|
||||
INNER JOIN `attribute` `a`
|
||||
on `a`.`id`=`v`.`attributeid`
|
||||
|
||||
WHERE
|
||||
|
||||
WHERE
|
||||
`i`.`item`=?
|
||||
AND
|
||||
`a`.`attribute`=?;""",
|
||||
(item.lower(),key.lower())
|
||||
)
|
||||
`a`.`attribute`=?;""", (item.lower(), key.lower()))
|
||||
row = c.fetchone()
|
||||
|
||||
|
||||
c.close()
|
||||
if row == None:
|
||||
if row is None:
|
||||
return None
|
||||
return row["value"]
|
||||
|
||||
|
||||
def set(self, item, key, value):
|
||||
return self.setKey(item, key, value)
|
||||
|
||||
def setKey(self, item, key, value):
|
||||
"""Set the key on an item
|
||||
|
||||
|
||||
:param item: the item name to set the key on
|
||||
:type item: str
|
||||
:param key: the key to set
|
||||
@ -135,35 +130,35 @@ class AttributeStorageLite(ModuleBase):
|
||||
:type value: str"""
|
||||
item = item.lower()
|
||||
attribute = key.lower()
|
||||
|
||||
|
||||
# Check attribute exists
|
||||
c = self.db.query("SELECT `id` FROM `attribute` WHERE `attribute`=?;", (attribute,))
|
||||
row = c.fetchone()
|
||||
attributeId = -1
|
||||
if row == None:
|
||||
if row is None:
|
||||
c = self.db.query("INSERT INTO `attribute` (`attribute`) VALUES (?);", (attribute,))
|
||||
attributeId = c.lastrowid
|
||||
else:
|
||||
attributeId = row["id"]
|
||||
c.close()
|
||||
|
||||
|
||||
# check item exists
|
||||
c = self.db.query("SELECT `id` FROM `items` WHERE `item`=?;", (item,))
|
||||
row = c.fetchone()
|
||||
itemId = -1
|
||||
if row == None:
|
||||
if row is None:
|
||||
c = self.db.query("INSERT INTO `items` (`item`) VALUES (?);", (item,))
|
||||
itemId = c.lastrowid
|
||||
else:
|
||||
itemId = row["id"]
|
||||
c.close()
|
||||
|
||||
if value == None:
|
||||
|
||||
if value is None:
|
||||
# delete it
|
||||
c = self.db.query("DELETE FROM `values` WHERE `itemid`=? AND `attributeid`=? ;", (itemId, attributeId))
|
||||
self.log.info("Stored item %s attribute %s value: %s (Deleted)" % (itemId, attributeId, value))
|
||||
else:
|
||||
# add attribute
|
||||
c = self.db.query("REPLACE INTO `values` (`itemid`, `attributeid`, `value`) VALUES (?, ?, ?);", (itemId, attributeId, value))
|
||||
c = self.db.query("REPLACE INTO `values` (`itemid`, `attributeid`, `value`) VALUES (?, ?, ?);",
|
||||
(itemId, attributeId, value))
|
||||
self.log.info("Stored item %s attribute %s value: %s" % (itemId, attributeId, value))
|
||||
c.close()
|
||||
|
@ -6,37 +6,37 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
from requests import get
|
||||
from time import time
|
||||
|
||||
|
||||
class BitcoinPrice(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
|
||||
self.cache = None
|
||||
self.cacheAge = 0
|
||||
|
||||
self.hooks=[
|
||||
|
||||
self.hooks = [
|
||||
ModuleHook(["PRIVMSG"], self.btc)
|
||||
]
|
||||
|
||||
|
||||
def btc(self, args, prefix, trailing):
|
||||
prefix = self.bot.decodePrefix(prefix)
|
||||
replyTo = prefix.nick if not "#" in args[0] else args[0]
|
||||
|
||||
replyTo = prefix.nick if "#" not in args[0] else args[0]
|
||||
|
||||
cmd = self.bot.messageHasCommand([".btc", ".bitcoin"], trailing)
|
||||
if cmd:
|
||||
data = self.getApi()
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: %s" % (
|
||||
prefix.nick,
|
||||
"\x02\x0307Bitcoin:\x03\x02 \x0307{buy:.0f}\x0f$ - High: \x0307{high:.0f}\x0f$ - Low: \x0307{low:.0f}\x0f$ - Volume: \x0307{vol_cur:.0f}\x03฿".format(**data['ticker'])
|
||||
"\x02\x0307Bitcoin:\x03\x02 \x0307{buy:.0f}\x0f$ - High: \x0307{high:.0f}\x0f$ - "
|
||||
"Low: \x0307{low:.0f}\x0f$ - Volume: \x0307{vol_cur:.0f}\x03฿".format(**data['ticker'])
|
||||
))
|
||||
|
||||
|
||||
def getApi(self):
|
||||
if self.cache == None or time()-self.cacheAge>self.config["cache"]:
|
||||
if self.cache is None or time() - self.cacheAge > self.config["cache"]:
|
||||
self.cache = get("https://btc-e.com/api/2/btc_usd/ticker").json()
|
||||
self.cacheAge = time()
|
||||
return self.cache
|
||||
|
||||
|
@ -1,22 +1,24 @@
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
import datetime
|
||||
import time
|
||||
import math
|
||||
|
||||
|
||||
class Calc(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.calc)]
|
||||
self.timers={}
|
||||
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.calc)]
|
||||
self.timers = {}
|
||||
|
||||
self.sqlite = self.bot.getBestModuleForService("sqlite")
|
||||
if self.sqlite==None:
|
||||
if self.sqlite is None:
|
||||
self.log.error("Calc: SQLIite service is required.")
|
||||
return
|
||||
|
||||
|
||||
self.sql = self.sqlite.opendb("calc.db")
|
||||
|
||||
|
||||
if not self.sql.tableExists("calc_addedby"):
|
||||
c = self.sql.getCursor()
|
||||
c.execute("""
|
||||
@ -59,41 +61,40 @@ class Calc(ModuleBase):
|
||||
);
|
||||
""")
|
||||
c.close()
|
||||
|
||||
|
||||
def timeSince(self, channel, timetype):
|
||||
if not channel in self.timers:
|
||||
if channel not in self.timers:
|
||||
self.createDefaultTimers(channel)
|
||||
return time.time()-self.timers[channel][timetype]
|
||||
|
||||
return time.time() - self.timers[channel][timetype]
|
||||
|
||||
def updateTimeSince(self, channel, timetype):
|
||||
if not channel in self.timers:
|
||||
if channel not in self.timers:
|
||||
self.createDefaultTimers(channel)
|
||||
self.timers[channel][timetype] = time.time()
|
||||
|
||||
|
||||
def createDefaultTimers(self, channel):
|
||||
self.timers[channel]={"add":0, "calc":0, "calcspec":0, "match":0}
|
||||
|
||||
self.timers[channel] = {"add": 0, "calc": 0, "calcspec": 0, "match": 0}
|
||||
|
||||
def remainingToStr(self, total, elasped):
|
||||
remaining = total-elasped
|
||||
minutes = int(math.floor(remaining/60))
|
||||
seconds = int(remaining - (minutes*60))
|
||||
remaining = total - elasped
|
||||
minutes = int(math.floor(remaining / 60))
|
||||
seconds = int(remaining - (minutes * 60))
|
||||
return "Please wait %s minute(s) and %s second(s)." % (minutes, seconds)
|
||||
|
||||
|
||||
def calc(self, args, prefix, trailing):
|
||||
# Channel only
|
||||
if not args[0][0]=="#":
|
||||
if not args[0][0] == "#":
|
||||
return
|
||||
sender = self.bot.decodePrefix(prefix)
|
||||
|
||||
|
||||
foundCalc = False
|
||||
commandFound = ""
|
||||
for cmd in self.config["cmd_calc"]:
|
||||
if trailing[0:len(cmd)] == cmd and ( len(trailing) == len(cmd) or (trailing[len(cmd):len(cmd)+1] in [" ", "="])):
|
||||
commandFound=cmd
|
||||
foundCalc=True
|
||||
|
||||
if trailing[0:len(cmd)] == cmd and (len(trailing) == len(cmd) or
|
||||
(trailing[len(cmd):len(cmd) + 1] in [" ", "="])):
|
||||
foundCalc = True
|
||||
|
||||
if foundCalc:
|
||||
calcCmd = trailing[len(cmd)-1:].strip()
|
||||
calcCmd = trailing[len(cmd) - 1:].strip()
|
||||
if "=" in calcCmd[1:]:
|
||||
" Add a new calc "
|
||||
calcWord, calcDefinition = calcCmd.split("=", 1)
|
||||
@ -106,153 +107,172 @@ class Calc(ModuleBase):
|
||||
else:
|
||||
self.bot.act_PRIVMSG(args[0], "Sorry %s, I don't know what '%s' is." % (sender.nick, calcWord))
|
||||
else:
|
||||
if self.config["delaySubmit"]>0 and self.timeSince(args[0], "add") < self.config["delaySubmit"]:
|
||||
self.bot.act_PRIVMSG(sender.nick, self.remainingToStr(self.config["delaySubmit"], self.timeSince(args[0], "add")))
|
||||
if self.config["delaySubmit"] > 0 and self.timeSince(args[0], "add") < self.config["delaySubmit"]:
|
||||
self.bot.act_PRIVMSG(sender.nick, self.remainingToStr(self.config["delaySubmit"],
|
||||
self.timeSince(args[0], "add")))
|
||||
else:
|
||||
self.addNewCalc(args[0], calcWord, calcDefinition, prefix)
|
||||
self.bot.act_PRIVMSG(args[0], "Thanks for the info, %s." % sender.nick)
|
||||
self.updateTimeSince(args[0], "add")
|
||||
elif len(calcCmd)>0:
|
||||
elif len(calcCmd) > 0:
|
||||
" Lookup the word in calcCmd "
|
||||
|
||||
if self.config["delayCalcSpecific"]>0 and self.timeSince(args[0], "calcspec") < self.config["delayCalcSpecific"]:
|
||||
self.bot.act_PRIVMSG(sender.nick, self.remainingToStr(self.config["delayCalcSpecific"], self.timeSince(args[0], "calcspec")))
|
||||
|
||||
if self.config["delayCalcSpecific"] > 0 and \
|
||||
self.timeSince(args[0], "calcspec") < self.config["delayCalcSpecific"]:
|
||||
self.bot.act_PRIVMSG(sender.nick, self.remainingToStr(self.config["delayCalcSpecific"],
|
||||
self.timeSince(args[0], "calcspec")))
|
||||
else:
|
||||
randCalc = self.getSpecificCalc(args[0], calcCmd)
|
||||
if randCalc==None:
|
||||
if randCalc is None:
|
||||
self.bot.act_PRIVMSG(args[0], "Sorry %s, I don't know what '%s' is." % (sender.nick, calcCmd))
|
||||
else:
|
||||
self.bot.act_PRIVMSG(args[0], "%s \x03= %s \x0314[added by: %s]" % (randCalc["word"], randCalc["definition"], randCalc["by"]))
|
||||
self.bot.act_PRIVMSG(args[0], "%s \x03= %s \x0314[added by: %s]" %
|
||||
(randCalc["word"], randCalc["definition"], randCalc["by"]))
|
||||
self.updateTimeSince(args[0], "calcspec")
|
||||
else:
|
||||
if self.config["delayCalc"]>0 and self.timeSince(args[0], "calc") < self.config["delayCalc"]:
|
||||
self.bot.act_PRIVMSG(sender.nick, self.remainingToStr(self.config["delayCalc"], self.timeSince(args[0], "calc")))
|
||||
if self.config["delayCalc"] > 0 and self.timeSince(args[0], "calc") < self.config["delayCalc"]:
|
||||
self.bot.act_PRIVMSG(sender.nick, self.remainingToStr(self.config["delayCalc"],
|
||||
self.timeSince(args[0], "calc")))
|
||||
else:
|
||||
randCalc = self.getRandomCalc(args[0])
|
||||
if randCalc == None:
|
||||
if randCalc is None:
|
||||
self.bot.act_PRIVMSG(args[0], "This channel has no calcs, %s :(" % (sender.nick,))
|
||||
else:
|
||||
self.bot.act_PRIVMSG(args[0], "%s \x03= %s \x0314[added by: %s]" % (randCalc["word"], randCalc["definition"], randCalc["by"]))
|
||||
self.bot.act_PRIVMSG(args[0], "%s \x03= %s \x0314[added by: %s]" % (randCalc["word"],
|
||||
randCalc["definition"], randCalc["by"]))
|
||||
self.updateTimeSince(args[0], "calc")
|
||||
return
|
||||
|
||||
|
||||
cmd = self.bot.messageHasCommand(self.config["cmd_match"], trailing, True)
|
||||
if cmd:
|
||||
if self.config["delayMatch"]>0 and self.timeSince(args[0], "match") < self.config["delayMatch"]:
|
||||
self.bot.act_PRIVMSG(sender.nick, self.remainingToStr(self.config["delayMatch"], self.timeSince(args[0], "match")))
|
||||
if self.config["delayMatch"] > 0 and self.timeSince(args[0], "match") < self.config["delayMatch"]:
|
||||
self.bot.act_PRIVMSG(sender.nick, self.remainingToStr(self.config["delayMatch"],
|
||||
self.timeSince(args[0], "match")))
|
||||
else:
|
||||
term = cmd.args_str
|
||||
if term.strip()=='':
|
||||
if not term.strip():
|
||||
return
|
||||
c = self.sql.getCursor()
|
||||
channelId = self.getChannelId(args[0])
|
||||
c.execute("SELECT * FROM `calc_words` WHERE `word` LIKE ? AND `channel`=? ORDER BY `word` ASC ;", ("%%"+term+"%%", channelId))
|
||||
c.execute("SELECT * FROM `calc_words` WHERE `word` LIKE ? AND `channel`=? ORDER BY `word` ASC ;",
|
||||
("%%" + term + "%%", channelId))
|
||||
rows = c.fetchall()
|
||||
if len(rows)==0:
|
||||
if not rows:
|
||||
self.bot.act_PRIVMSG(args[0], "%s: Sorry, no matches" % sender.nick)
|
||||
else:
|
||||
matches = []
|
||||
for row in rows[0:10]:
|
||||
if row == None:
|
||||
if not row:
|
||||
break
|
||||
matches.append(row["word"])
|
||||
self.bot.act_PRIVMSG(args[0], "%s: %s match%s (%s\x03)" % (sender.nick, len(matches), "es" if len(matches)>1 else "", ", \x03".join(matches) ))
|
||||
self.bot.act_PRIVMSG(args[0], "%s: %s match%s (%s\x03)" %
|
||||
(sender.nick, len(matches), "es" if len(matches) > 1 else
|
||||
"", ", \x03".join(matches)))
|
||||
self.updateTimeSince(args[0], "match")
|
||||
|
||||
|
||||
def addNewCalc(self, channel, word, definition, prefix):
|
||||
sender = self.bot.decodePrefix(prefix)
|
||||
|
||||
|
||||
" Find the channel ID"
|
||||
channelId = self.getChannelId(channel)
|
||||
|
||||
|
||||
" Check if we need to add a user"
|
||||
c = self.sql.getCursor()
|
||||
name = sender.nick
|
||||
host = sender.hostname
|
||||
c.execute("SELECT * FROM `calc_addedby` WHERE `username`=? AND `userhost`=? ;", (name, host))
|
||||
rows = c.fetchall()
|
||||
if len(rows)==0:
|
||||
if not rows:
|
||||
c.execute("INSERT INTO `calc_addedby` (`username`, `userhost`) VALUES (?, ?) ;", (name, host,))
|
||||
c.execute("SELECT * FROM `calc_addedby` WHERE `username`=? AND `userhost`=? ;", (name, host))
|
||||
rows = c.fetchall()
|
||||
addedId = rows[0]["id"]
|
||||
|
||||
|
||||
" Check if the word exists"
|
||||
c.execute("SELECT * FROM `calc_words` WHERE `channel`=? AND `word`=? ;", (channelId, word))
|
||||
rows = c.fetchall()
|
||||
if len(rows)==0:
|
||||
c.execute("INSERT INTO `calc_words` (`channel`, `word`, `status`) VALUES (?, ?, ?) ;", (channelId, word, 'approved'))
|
||||
if not rows:
|
||||
c.execute("INSERT INTO `calc_words` (`channel`, `word`, `status`) VALUES (?, ?, ?) ;",
|
||||
(channelId, word, 'approved'))
|
||||
c.execute("SELECT * FROM `calc_words` WHERE `channel`=? AND `word`=? ;", (channelId, word))
|
||||
rows = c.fetchall()
|
||||
wordId = rows[0]["id"]
|
||||
" Add definition "
|
||||
c.execute("INSERT INTO `calc_definitions` (`word`, `definition`, `addedby`, `date`, `status`) VALUES (?, ?, ?, ?, ?) ;", (wordId, definition, addedId, datetime.datetime.now(), 'approved',))
|
||||
c.execute("INSERT INTO `calc_definitions` (`word`, `definition`, `addedby`, `date`, `status`) VALUES "
|
||||
"(?, ?, ?, ?, ?) ;", (wordId, definition, addedId, datetime.datetime.now(), 'approved',))
|
||||
c.close()
|
||||
pass
|
||||
|
||||
|
||||
def getSpecificCalc(self, channel, word):
|
||||
c = self.sql.getCursor()
|
||||
channelId = self.getChannelId(channel)
|
||||
c.execute("SELECT `cw`.`word`, (SELECT `cdq`.`id` FROM `calc_definitions` `cdq` WHERE `cdq`.`word`=`cw`.`id` AND `cdq`.`status`='approved' ORDER BY `cdq`.`date` DESC LIMIT 1) as `definitionId` FROM `calc_words` `cw` WHERE `cw`.`channel`=? AND `cw`.`status`='approved' AND `cw`.`word`=? COLLATE NOCASE ORDER BY RANDOM() LIMIT 1 ;", (channelId, word.lower()))
|
||||
c.execute("SELECT `cw`.`word`, (SELECT `cdq`.`id` FROM `calc_definitions` `cdq` WHERE `cdq`.`word`=`cw`.`id` "
|
||||
"AND `cdq`.`status`='approved' ORDER BY `cdq`.`date` DESC LIMIT 1) as `definitionId` FROM "
|
||||
"`calc_words` `cw` WHERE `cw`.`channel`=? AND `cw`.`status`='approved' AND `cw`.`word`=? "
|
||||
"COLLATE NOCASE ORDER BY RANDOM() LIMIT 1 ;", (channelId, word.lower()))
|
||||
word = c.fetchone()
|
||||
|
||||
if word == None:
|
||||
|
||||
if word is None:
|
||||
return None
|
||||
|
||||
c.execute("SELECT `ca`.`username`, `cd`.`definition` FROM `calc_definitions` `cd` JOIN `calc_addedby` `ca` ON `ca`.`id` = `cd`.`addedby` WHERE `cd`.`id`=? LIMIT 1 ;", (word["definitionId"], ))
|
||||
|
||||
|
||||
c.execute("SELECT `ca`.`username`, `cd`.`definition` FROM `calc_definitions` `cd` JOIN `calc_addedby` `ca` ON "
|
||||
"`ca`.`id` = `cd`.`addedby` WHERE `cd`.`id`=? LIMIT 1 ;", (word["definitionId"], ))
|
||||
|
||||
who = c.fetchone()
|
||||
|
||||
if who == None:
|
||||
|
||||
if who is None:
|
||||
return None
|
||||
|
||||
|
||||
c.close()
|
||||
return {"word":word["word"], "definition":who["definition"], "by":who["username"]}
|
||||
|
||||
|
||||
return {"word": word["word"], "definition": who["definition"], "by": who["username"]}
|
||||
|
||||
def getRandomCalc(self, channel):
|
||||
c = self.sql.getCursor()
|
||||
channelId = self.getChannelId(channel)
|
||||
|
||||
|
||||
for i in range(0, 5):
|
||||
c.execute("SELECT `cw`.`word`, (SELECT `cdq`.`id` FROM `calc_definitions` `cdq` WHERE `cdq`.`word`=`cw`.`id` AND `cdq`.`status`='approved' ORDER BY `cdq`.`date` DESC LIMIT 1) as `definitionId` FROM `calc_words` `cw` WHERE `cw`.`channel`=? AND `cw`.`status`='approved' ORDER BY RANDOM() LIMIT 1 ;", (channelId,))
|
||||
c.execute("SELECT `cw`.`word`, (SELECT `cdq`.`id` FROM `calc_definitions` `cdq` WHERE "
|
||||
"`cdq`.`word`=`cw`.`id` AND `cdq`.`status`='approved' ORDER BY `cdq`.`date` DESC LIMIT 1) as "
|
||||
"`definitionId` FROM `calc_words` `cw` WHERE `cw`.`channel`=? AND `cw`.`status`='approved' "
|
||||
"ORDER BY RANDOM() LIMIT 1 ;", (channelId,))
|
||||
word = c.fetchone()
|
||||
if word == None:
|
||||
if word is None:
|
||||
return None
|
||||
c.execute("SELECT `ca`.`username`, `cd`.`definition` FROM `calc_definitions` `cd` JOIN `calc_addedby` `ca` ON `ca`.`id` = `cd`.`addedby` WHERE `cd`.`id`=? LIMIT 1 ;", (word["definitionId"], ))
|
||||
|
||||
c.execute("SELECT `ca`.`username`, `cd`.`definition` FROM `calc_definitions` `cd` JOIN `calc_addedby` `ca` "
|
||||
"ON `ca`.`id` = `cd`.`addedby` WHERE `cd`.`id`=? LIMIT 1 ;", (word["definitionId"], ))
|
||||
|
||||
who = c.fetchone()
|
||||
|
||||
if who == None:
|
||||
|
||||
if who is None:
|
||||
continue
|
||||
|
||||
|
||||
c.close()
|
||||
return {"word":word["word"], "definition":who["definition"], "by":who["username"]}
|
||||
|
||||
return {"word": word["word"], "definition": who["definition"], "by": who["username"]}
|
||||
|
||||
def deleteCalc(self, channel, word):
|
||||
" Return true if deleted something, false if it doesnt exist"
|
||||
c = self.sql.getCursor()
|
||||
channelId = self.getChannelId(channel)
|
||||
c.execute("SELECT * FROM `calc_words` WHERE `channel`=? and `word`=? ;", (channelId, word))
|
||||
rows = c.fetchall()
|
||||
if len(rows)==0:
|
||||
if not rows:
|
||||
c.close()
|
||||
return False
|
||||
|
||||
|
||||
wordId = rows[0]["id"]
|
||||
|
||||
#c.execute("DELETE FROM `calc_words` WHERE `id`=? ;", (wordId,))
|
||||
#c.execute("DELETE FROM `calc_definitions` WHERE `word`=? ;", (wordId,))
|
||||
|
||||
# c.execute("DELETE FROM `calc_words` WHERE `id`=? ;", (wordId,))
|
||||
# c.execute("DELETE FROM `calc_definitions` WHERE `word`=? ;", (wordId,))
|
||||
c.execute("UPDATE `calc_definitions` SET `status`='deleted' WHERE `word`=? ;", (wordId,))
|
||||
|
||||
|
||||
c.close()
|
||||
return True
|
||||
|
||||
|
||||
def getChannelId(self, channel):
|
||||
c = self.sql.getCursor()
|
||||
c.execute("SELECT * FROM `calc_channels` WHERE `channel` = ?", (channel,))
|
||||
rows = c.fetchall()
|
||||
if len(rows)==0:
|
||||
if not rows:
|
||||
c.execute("INSERT INTO `calc_channels` (`channel`) VALUES (?);", (channel,))
|
||||
c.execute("SELECT * FROM `calc_channels` WHERE `channel` = ?", (channel,))
|
||||
rows = c.fetchall()
|
||||
|
@ -5,47 +5,44 @@
|
||||
.. moduleauthor:: Nick Krichevsky <nick@ollien.com>
|
||||
|
||||
"""
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
import os
|
||||
import time
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
from threading import Timer
|
||||
from operator import itemgetter
|
||||
from random import choice
|
||||
|
||||
|
||||
class CardsAgainstHumanity(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
# init the base module
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.scramble)]
|
||||
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.scramble)]
|
||||
|
||||
# Dictionary
|
||||
self.whitesFile = open(self.getFilePath("answers.txt"),'r')
|
||||
self.blacksFile = open(self.getFilePath("questions.txt"),'r')
|
||||
self.whitesFile = open(self.getFilePath("answers.txt"), 'r')
|
||||
self.blacksFile = open(self.getFilePath("questions.txt"), 'r')
|
||||
self.whites = [line.rstrip() for line in self.whitesFile]
|
||||
self.blacks = [line.rstrip() for line in self.blacksFile]
|
||||
self.currentBlack = ""
|
||||
self.whitesFile.close()
|
||||
self.blacksFile.close()
|
||||
self.log.info("CAH: Loaded."+str(len(self.whites))+" White Cards "+str(len(self.blacks))+" Black Cards")
|
||||
self.log.info("CAH: Loaded." + str(len(self.whites)) + " White Cards " + str(len(self.blacks)) + " Black Cards")
|
||||
# Per channel games
|
||||
self.games = {}
|
||||
|
||||
|
||||
|
||||
def scramble(self, args, prefix, trailing):
|
||||
channel = args[0]
|
||||
if channel[0] == "#":
|
||||
if not channel in self.games:
|
||||
self.games[channel]=cardsGame(self, channel,self.whites,self.blacks)
|
||||
if channel not in self.games:
|
||||
self.games[channel] = cardsGame(self, channel, self.whites, self.blacks)
|
||||
self.games[channel].stuff(args, prefix, trailing)
|
||||
|
||||
|
||||
|
||||
def ondisable(self):
|
||||
self.log.info("CAH: Unload requested, ending games...")
|
||||
# for game in self.games:
|
||||
# self.games[game].gameover()
|
||||