Misc & lint fixes
This commit is contained in:
@@ -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()
|
||||
|
||||
|
||||
class cardsGame:
|
||||
def __init__(self, master, channel,whites,blacks):
|
||||
def __init__(self, master, channel, whites, blacks):
|
||||
self.master = master
|
||||
self.channel = channel
|
||||
# Running?
|
||||
@@ -63,33 +60,34 @@ class cardsGame:
|
||||
self.allowPick = 0
|
||||
self.choices = {}
|
||||
self.czarTimer = None
|
||||
|
||||
def stuff(self, args, prefix, trailing):
|
||||
prefix = self.master.bot.decodePrefix(prefix)
|
||||
sender = prefix.nick
|
||||
if self.master.bot.messageHasCommand(".joinGame", trailing):
|
||||
self.join(sender)
|
||||
elif self.master.bot.messageHasCommand(".ready",trailing):
|
||||
elif self.master.bot.messageHasCommand(".ready", trailing):
|
||||
result = self.markReady(sender)
|
||||
if result:
|
||||
self.started = True
|
||||
self.master.bot.act_PRIVMSG(self.channel,"All players are ready!")
|
||||
self.master.bot.act_PRIVMSG(self.channel, "All players are ready!")
|
||||
for player in self.players:
|
||||
self.master.bot.act_PRIVMSG(player,"ITS TIME TO D-D-D-D-D-DUEL!")
|
||||
self.players[player]=[]
|
||||
self.master.bot.act_PRIVMSG(player, "ITS TIME TO D-D-D-D-D-DUEL!")
|
||||
self.players[player] = []
|
||||
for player in self.players:
|
||||
self.deal(player)
|
||||
self.sendCards(player)
|
||||
self.active = True
|
||||
self.makeTurn()
|
||||
elif self.master.bot.messageHasCommand(".pick",trailing):
|
||||
elif self.master.bot.messageHasCommand(".pick", trailing):
|
||||
if self.active:
|
||||
if sender != self.czar:
|
||||
print(sender,self.czar)
|
||||
print(sender != self.czar)
|
||||
print(sender, self.czar)
|
||||
print(sender != self.czar)
|
||||
if self.allowPick > 0:
|
||||
if sender in self.players:
|
||||
cards = trailing.split(' ')[1:]
|
||||
if len(cards)==self.allowPick:
|
||||
if len(cards) == self.allowPick:
|
||||
if self.checkBounds(cards):
|
||||
if sender not in self.choices:
|
||||
cardChoices = [self.players[sender][int(index)] for index in cards]
|
||||
@@ -98,104 +96,123 @@ class cardsGame:
|
||||
self.removeAndReplenishCards(sender, cardChoices)
|
||||
self.sendCards(sender)
|
||||
del self.choices[sender]
|
||||
if sender in timers:
|
||||
if sender in self.timers:
|
||||
self.timers[sender].cancel()
|
||||
if self.allDrawn():
|
||||
self.readChoices()
|
||||
self.master.bot.act_PRIVMSG(self.channel,self.czar+"! Please choose the winner!")
|
||||
czarTimer = Timer(180,self.kick,(self.czar,"taking too long to pick a choice. The next turn iwll be made."))
|
||||
self.master.bot.act_PRIVMSG(self.channel,
|
||||
self.czar + "! Please choose the winner!")
|
||||
self.czarTimer = Timer(180, self.kick, (self.czar, "taking too long to pick a "
|
||||
"choice. The next turn iwll be made."))
|
||||
self.makeTurn()
|
||||
|
||||
|
||||
else:
|
||||
self.master.bot.act_PRIVMSG(self.channel,sender+", you picked a card that was out of the range. Please don't do that.")
|
||||
self.master.bot.act_PRIVMSG(self.channel, sender + ", you picked a card that was "
|
||||
"out of the range. Please don't do that.")
|
||||
else:
|
||||
self.master.bot.act_PRIVMSG(self.channel,sender+", you picked "+str(len(cards))+" cards. You were supposed to pick "+str(self.allowPick))
|
||||
elif self.master.bot.messageHasCommand(".choose",trailing):
|
||||
if sender==self.czar:
|
||||
self.master.bot.act_PRIVMSG(self.channel, sender + ", you picked " + str(len(cards)) +
|
||||
" cards. You were supposed to pick " + str(self.allowPick))
|
||||
elif self.master.bot.messageHasCommand(".choose", trailing):
|
||||
if sender == self.czar:
|
||||
choice = trailing.split()[1:]
|
||||
if len(choice)==1:
|
||||
if len(choice) == 1:
|
||||
if self.checkChoiceBounds(int(choice[0])):
|
||||
self.master.bot.act_PRIVMSG(self.channel,list(self.choices.keys())[int(choice[0])]+", you won the round!")
|
||||
if self.czarTimer!=None:
|
||||
self.master.bot.act_PRIVMSG(self.channel, list(self.choices.keys())[int(choice[0])] + ", you "
|
||||
"won the round!")
|
||||
if self.czarTimer is not None:
|
||||
self.czarTimer.cancel()
|
||||
self.makeTurn()
|
||||
else:
|
||||
self.master.bot.act_PRIVMSG(self.channel,sender+", your choice was out of the range. Please don't do that.")
|
||||
self.master.bot.act_PRIVMSG(self.channel, sender + ", your choice was out of the range. Please "
|
||||
"don't do that.")
|
||||
else:
|
||||
self.master.bot.act_PRIVMSG(self.channel,sender+", you picked "+str(len(choice))+" "+" winners. You were only supposed to pick 1.")
|
||||
elif self.master.bot.messageHasCommand('.leave',trailing):
|
||||
self.master.bot.act_PRIVMSG(self.channel, sender + ", you picked " + str(len(choice)) + " winners."
|
||||
" You were only supposed to pick 1.")
|
||||
elif self.master.bot.messageHasCommand('.leave', trailing):
|
||||
if sender in self.players:
|
||||
self.kick(sender,'choosing to leave the game you dolt')
|
||||
self.kick(sender, 'choosing to leave the game you dolt')
|
||||
if sender is self.czar:
|
||||
self.makeTurn()
|
||||
|
||||
def join(self,nick):
|
||||
|
||||
def join(self, nick):
|
||||
if not self.started:
|
||||
if nick not in self.players:
|
||||
self.players[nick]=False
|
||||
self.master.bot.act_PRIVMSG(self.channel, nick+" has joined the game! | The players currently are "+str(self.players))
|
||||
self.players[nick] = False
|
||||
self.master.bot.act_PRIVMSG(self.channel, nick + " has joined the game! | The players currently are " +
|
||||
str(self.players))
|
||||
else:
|
||||
print("the game has already started!")
|
||||
self.master.bot.act_PRIVMSG(self.channel,"The game has already started!")
|
||||
def markReady(self,nick):
|
||||
self.master.bot.act_PRIVMSG(self.channel, "The game has already started!")
|
||||
|
||||
def markReady(self, nick):
|
||||
if not self.started:
|
||||
if nick in self.players:
|
||||
self.players[nick]=True
|
||||
self.players[nick] = True
|
||||
for player in self.players:
|
||||
print(player)
|
||||
if not self.players[player]:
|
||||
print (player+" not ready")
|
||||
print (player + " not ready")
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "You are not in the game! Type .joinGame!")
|
||||
else:
|
||||
print("game has already started!")
|
||||
self.master.bot.act_PRIVMSG(self.channel,"The game has already started!")
|
||||
def deal(self,nick):
|
||||
self.master.bot.act_PRIVMSG(self.channel, "The game has already started!")
|
||||
|
||||
def deal(self, nick):
|
||||
self.players[nick] = [self.pickWhite() for i in range (7)]
|
||||
|
||||
def pickWhite(self):
|
||||
card = choice(self.whites)
|
||||
self.whites.remove(card)
|
||||
return card
|
||||
|
||||
def pickBlack(self):
|
||||
card = choice(self.blacks)
|
||||
self.blacks.remove(card)
|
||||
return card
|
||||
def sendCards(self,nick):
|
||||
|
||||
def sendCards(self, nick):
|
||||
cards = ""
|
||||
for card in self.players[nick]:
|
||||
cards+=str(self.players[nick].index(card))+". "
|
||||
cards+=card+" "
|
||||
self.master.bot.act_PRIVMSG(nick,"Your cards are "+cards)
|
||||
def readCard(self,card):
|
||||
cards += str(self.players[nick].index(card)) + ". "
|
||||
cards += card + " "
|
||||
self.master.bot.act_PRIVMSG(nick, "Your cards are " + cards)
|
||||
|
||||
def readCard(self, card):
|
||||
count = card.count('_')
|
||||
if count == 0:
|
||||
if 'haiku' in card:
|
||||
count = 3
|
||||
else:
|
||||
count = 1
|
||||
self.master.bot.act_PRIVMSG(self.channel,"The black card is \""+card+"\" Pick "+str(count))
|
||||
self.master.bot.act_PRIVMSG(self.channel, "The black card is \"" + card + "\" Pick " + str(count))
|
||||
return count
|
||||
|
||||
def pickCzar(self):
|
||||
index = self.lastCzar+1
|
||||
index = self.lastCzar + 1
|
||||
if index < len(self.players):
|
||||
self.lastCzar = index
|
||||
return index
|
||||
else:
|
||||
self.lastCzar = 0
|
||||
return 0
|
||||
|
||||
def announceCzar(self):
|
||||
self.master.bot.act_PRIVMSG(self.channel,"The Czar is "+self.czar+"!")
|
||||
def checkBounds(self,cards):
|
||||
self.master.bot.act_PRIVMSG(self.channel, "The Czar is " + self.czar + "!")
|
||||
|
||||
def checkBounds(self, cards):
|
||||
for item in cards:
|
||||
if int(item)>6 or int(item)<0:
|
||||
if int(item) > 6 or int(item) < 0:
|
||||
return False
|
||||
return True
|
||||
def checkChoiceBounds(self,choice):
|
||||
if choice<0 or choice>len(self.choices)-1:
|
||||
|
||||
def checkChoiceBounds(self, choice):
|
||||
if choice < 0 or choice > len(self.choices) - 1:
|
||||
return False
|
||||
return True
|
||||
|
||||
def makeTurn(self):
|
||||
self.choices.clear()
|
||||
card = self.pickBlack()
|
||||
@@ -204,47 +221,51 @@ class cardsGame:
|
||||
self.allowPick = self.readCard(card)
|
||||
self.lastCzar = self.pickCzar()
|
||||
self.czar = list(self.players.keys())[self.lastCzar]
|
||||
print (self.lastCzar,self.czar)
|
||||
print (self.lastCzar, self.czar)
|
||||
for player in self.players:
|
||||
if player!=self.czar:
|
||||
self.timers[player] = Timer(180,self.kick,(player,"taking more than 180 seconds for their turn."))
|
||||
if player != self.czar:
|
||||
self.timers[player] = Timer(180, self.kick, (player, "taking more than 180 seconds for their turn."))
|
||||
self.timers[player].start()
|
||||
self.announceCzar()
|
||||
def kick(self,nick,reason):
|
||||
|
||||
def kick(self, nick, reason):
|
||||
del self.players[nick]
|
||||
if nick in self.timers:
|
||||
self.timers[nick].cancel()
|
||||
del self.timers[nick]
|
||||
self.master.bot.act_PRIVMSG(self.channel,nick+" has been kicked due to "+reason)
|
||||
if len(self.players)<=1:
|
||||
self.master.bot.act_PRIVMSG(self.channel,"The game is being shut down due to having <=1 players")
|
||||
self.master.bot.act_PRIVMSG(self.channel, nick + " has been kicked due to " + reason)
|
||||
|
||||
if len(self.players) <= 1:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "The game is being shut down due to having <=1 players")
|
||||
self.started = False
|
||||
self.active = False
|
||||
for timer in self.timers:
|
||||
timer.cancel()
|
||||
self.timers.clear()
|
||||
self.players.clear()
|
||||
def removeAndReplenishCards(self,nick,cards):
|
||||
|
||||
def removeAndReplenishCards(self, nick, cards):
|
||||
for card in cards:
|
||||
self.players[nick].remove(card)
|
||||
self.players[nick].append(self.pickWhite())
|
||||
|
||||
def readChoices(self):
|
||||
if '_' in self.currentBlack:
|
||||
for player in list(self.choices.keys()):
|
||||
cardInstance = str(list(self.choices.keys()).index(player))+". "+self.currentBlack
|
||||
cardInstance = list(cardInstance) #do this as opposed to space to preserve spaces
|
||||
for choice in self.choices[player]:
|
||||
cardInstance = str(list(self.choices.keys()).index(player)) + ". " + self.currentBlack
|
||||
cardInstance = list(cardInstance) # do this as opposed to space to preserve spaces
|
||||
for plr_choice in self.choices[player]:
|
||||
for char in cardInstance:
|
||||
if char=='_':
|
||||
if char == '_':
|
||||
print(char)
|
||||
choice = choice.replace('.','')
|
||||
cardInstance[cardInstance.index(char)] = choice
|
||||
plr_choice = plr_choice.replace('.', '')
|
||||
cardInstance[cardInstance.index(char)] = plr_choice
|
||||
break
|
||||
self.master.bot.act_PRIVMSG(self.channel,''.join(cardInstance))
|
||||
self.master.bot.act_PRIVMSG(self.channel, ''.join(cardInstance))
|
||||
else:
|
||||
for player in self.choices:
|
||||
self.master.bot.act_PRIVMSG(self.channel,self.currentBlack+' '+' '.join(self.choices[player]))
|
||||
|
||||
self.master.bot.act_PRIVMSG(self.channel, self.currentBlack + ' ' + ' '.join(self.choices[player]))
|
||||
|
||||
def allDrawn(self):
|
||||
for player in self.players:
|
||||
if player not in self.choices:
|
||||
|
||||
@@ -7,185 +7,206 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
import time
|
||||
import hashlib
|
||||
|
||||
|
||||
class CryptoWallet(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.handle_message)]
|
||||
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.handle_message)]
|
||||
|
||||
def getMods(self):
|
||||
return (self.bot.getBestModuleForService("attributes"), self.bot.getBestModuleForService("bitcoinrpc"))
|
||||
|
||||
|
||||
def handle_setaddr(self, args, prefix, trailing, cmd):
|
||||
usage = ".setaddr <currency> <address>"
|
||||
attr,rpc = self.getMods()
|
||||
|
||||
attr, rpc = self.getMods()
|
||||
|
||||
# Check for args
|
||||
if not len(cmd.args)==2:
|
||||
if not len(cmd.args) == 2:
|
||||
self.bot.act_PRIVMSG(args[0], ".setaddr: usage: %s" % usage)
|
||||
#self.bot.act_PRIVMSG(args[0], ".setaddr: usage: .setaddr BTC 1xyWx6X5EABprhe3s9XduNxLn5NCtpSNB")
|
||||
# self.bot.act_PRIVMSG(args[0], ".setaddr: usage: .setaddr BTC 1xyWx6X5EABprhe3s9XduNxLn5NCtpSNB")
|
||||
return
|
||||
# Check if currency is known
|
||||
if not rpc.isSupported(cmd.args[0]):
|
||||
supportedStr = ', '.join(rpc.getSupported())
|
||||
self.bot.act_PRIVMSG(args[0], ".setaddr: '%s' is not a supported currency. Supported currencies are: %s" % (cmd.args[0], supportedStr))
|
||||
self.bot.act_PRIVMSG(args[0], ".setaddr: '%s' is not a supported currency. Supported currencies are: %s" %
|
||||
(cmd.args[0], supportedStr))
|
||||
return
|
||||
if len(cmd.args[1])<16 or len(cmd.args[1])>42:
|
||||
if len(cmd.args[1]) < 16 or len(cmd.args[1]) > 42:
|
||||
self.bot.act_PRIVMSG(args[0], ".setaddr: '%s' appears to be an invalid address." % (cmd.args[1]))
|
||||
return
|
||||
|
||||
|
||||
# Just make sure they have a wallet
|
||||
self.checkUserHasWallet(prefix.nick, cmd.args[0])
|
||||
|
||||
|
||||
# Set their address
|
||||
attr.setKey(prefix.nick, "cryptowallet-%s-address"%cmd.args[0].lower(), cmd.args[1])
|
||||
self.bot.act_PRIVMSG(args[0], ".setaddr: Your address has been saved as: %s. Please verify that this is correct or your coins could be lost." % (cmd.args[1]))
|
||||
|
||||
attr.setKey(prefix.nick, "cryptowallet-%s-address" % cmd.args[0].lower(), cmd.args[1])
|
||||
self.bot.act_PRIVMSG(args[0], ".setaddr: Your address has been saved as: %s. Please verify that this is correct"
|
||||
" or your coins could be lost." % (cmd.args[1]))
|
||||
|
||||
def handle_getbal(self, args, prefix, trailing, cmd):
|
||||
usage = ".getbal <currency>"
|
||||
attr,rpc = self.getMods()
|
||||
attr, rpc = self.getMods()
|
||||
# Check for args
|
||||
if not len(cmd.args)==1:
|
||||
if not len(cmd.args) == 1:
|
||||
self.bot.act_PRIVMSG(args[0], ".getbal: usage: %s" % usage)
|
||||
self.bot.act_PRIVMSG(args[0], ".getbal: usage: .getbal BTC")
|
||||
return
|
||||
# Check if currency is known
|
||||
if not rpc.isSupported(cmd.args[0]):
|
||||
supportedStr = ', '.join(rpc.getSupported())
|
||||
self.bot.act_PRIVMSG(args[0], ".getbal: '%s' is not a supported currency. Supported currencies are: %s" % (cmd.args[0], supportedStr))
|
||||
self.bot.act_PRIVMSG(args[0], ".getbal: '%s' is not a supported currency. Supported currencies are: %s" %
|
||||
(cmd.args[0], supportedStr))
|
||||
return
|
||||
|
||||
|
||||
# Just make sure they have a wallet
|
||||
self.checkUserHasWallet(prefix.nick, cmd.args[0])
|
||||
|
||||
|
||||
# fetch RPC and tell them the balance
|
||||
walletname = attr.getKey(prefix.nick, "cryptowallet-account-%s"%cmd.args[0].lower())
|
||||
walletname = attr.getKey(prefix.nick, "cryptowallet-account-%s" % cmd.args[0].lower())
|
||||
amount = 0.0
|
||||
if walletname:
|
||||
client = rpc.getRpc(cmd.args[0].lower())
|
||||
amount = client.getBal(walletname)
|
||||
self.bot.act_PRIVMSG(args[0], "%s: your balance is: %s %s" % (prefix.nick, amount, cmd.args[0].upper()))
|
||||
|
||||
|
||||
def handle_withdraw(self, args, prefix, trailing, cmd):
|
||||
usage = ".withdraw <currency> <amount>"
|
||||
attr,rpc = self.getMods()
|
||||
attr, rpc = self.getMods()
|
||||
# Check for args
|
||||
if not len(cmd.args)==2:
|
||||
if not len(cmd.args) == 2:
|
||||
self.bot.act_PRIVMSG(args[0], ".withdraw: usage: %s" % usage)
|
||||
self.bot.act_PRIVMSG(args[0], ".withdraw: usage: .getbal BTC 0.035")
|
||||
return
|
||||
# Check if currency is known
|
||||
if not rpc.isSupported(cmd.args[0]):
|
||||
supportedStr = ', '.join(rpc.getSupported())
|
||||
self.bot.act_PRIVMSG(args[0], ".getbal: '%s' is not a supported currency. Supported currencies are: %s" % (cmd.args[0], supportedStr))
|
||||
self.bot.act_PRIVMSG(args[0], ".getbal: '%s' is not a supported currency. Supported currencies are: %s" %
|
||||
(cmd.args[0], supportedStr))
|
||||
return
|
||||
|
||||
|
||||
# Just make sure they have a wallet
|
||||
self.checkUserHasWallet(prefix.nick, cmd.args[0])
|
||||
|
||||
|
||||
# check that they have a withdraw addr
|
||||
withdrawaddr = attr.getKey(prefix.nick, "cryptowallet-%s-address"%cmd.args[0].lower())
|
||||
if withdrawaddr == None:
|
||||
self.bot.act_PRIVMSG(args[0], ".withdraw: You need to set a withdraw address before withdrawing. Try .setaddr")
|
||||
withdrawaddr = attr.getKey(prefix.nick, "cryptowallet-%s-address" % cmd.args[0].lower())
|
||||
if withdrawaddr is None:
|
||||
self.bot.act_PRIVMSG(args[0], ".withdraw: You need to set a withdraw address before withdrawing. "
|
||||
"Try .setaddr")
|
||||
return
|
||||
|
||||
|
||||
# fetch RPC and check balance
|
||||
walletname = attr.getKey(prefix.nick, "cryptowallet-account-%s"%cmd.args[0].lower())
|
||||
walletname = attr.getKey(prefix.nick, "cryptowallet-account-%s" % cmd.args[0].lower())
|
||||
balance = 0.0
|
||||
|
||||
|
||||
client = rpc.getRpc(cmd.args[0].lower())
|
||||
balance = client.getBal(walletname)
|
||||
withdrawamount = float(cmd.args[1])
|
||||
|
||||
if balance < withdrawamount or withdrawamount<0:
|
||||
self.bot.act_PRIVMSG(args[0], ".withdraw: You don't have enough %s to withdraw %s" % (cmd.args[0].upper(), withdrawamount))
|
||||
|
||||
if balance < withdrawamount or withdrawamount < 0:
|
||||
self.bot.act_PRIVMSG(args[0], ".withdraw: You don't have enough %s to withdraw %s" %
|
||||
(cmd.args[0].upper(), withdrawamount))
|
||||
return
|
||||
|
||||
|
||||
if not client.reserve == 0 and balance - client.reserve < withdrawamount:
|
||||
self.bot.act_PRIVMSG(args[0], ".withdraw: Withdrawing that much would put you below the reserve (%s %s)." % (client.reserve, cmd.args[0].upper()))
|
||||
self.bot.act_PRIVMSG(args[0], ".withdraw: The reserve is to cover network transaction fees. To recover it you must close your account. (Talk to an admin)")
|
||||
self.bot.act_PRIVMSG(args[0], ".withdraw: Withdrawing that much would put you below the reserve (%s %s)." %
|
||||
(client.reserve, cmd.args[0].upper()))
|
||||
self.bot.act_PRIVMSG(args[0], ".withdraw: The reserve is to cover network transaction fees. To recover it "
|
||||
"you must close your account. (Talk to an admin)")
|
||||
return
|
||||
|
||||
|
||||
# Check if the precision is wrong
|
||||
if not client.checkPrecision(withdrawamount):
|
||||
self.bot.act_PRIVMSG(args[0], ".withdraw: %s has maximum %s decimal places" % (cmd.args[0].upper(), client.precision))
|
||||
self.bot.act_PRIVMSG(args[0], ".withdraw: %s has maximum %s decimal places" % (cmd.args[0].upper(),
|
||||
client.precision))
|
||||
return
|
||||
|
||||
|
||||
# Create a transaction
|
||||
txn = client.send(walletname, withdrawaddr, withdrawamount)
|
||||
if txn:
|
||||
self.bot.act_PRIVMSG(args[0], "%s: .withdraw: %s %s sent to %s. "% (prefix.nick, withdrawamount, client.name, withdrawaddr))
|
||||
self.bot.act_PRIVMSG(prefix.nick, "Withdrawal: (You)->%s: Transaction ID: %s" % (prefix.nick, withdrawaddr, txn))
|
||||
self.bot.act_PRIVMSG(args[0], "%s: .withdraw: %s %s sent to %s. " %
|
||||
(prefix.nick, withdrawamount, client.name, withdrawaddr))
|
||||
self.bot.act_PRIVMSG(prefix.nick, "Withdrawal: (You)->%s: Transaction ID: %s" %
|
||||
(prefix.nick, withdrawaddr, txn))
|
||||
else:
|
||||
self.bot.act_PRIVMSG(args[0], "%s: .withdraw: Transaction create failed. Maybe the transaction was too large for the network? Try a smaller increment." % prefix.nick)
|
||||
|
||||
self.bot.act_PRIVMSG(args[0], "%s: .withdraw: Transaction create failed. Maybe the transaction was too "
|
||||
"large for the network? Try a smaller increment." % prefix.nick)
|
||||
|
||||
def handle_send(self, args, prefix, trailing, cmd):
|
||||
usage = ".send <currency> <amount> <nick or address>"
|
||||
attr,rpc = self.getMods()
|
||||
attr, rpc = self.getMods()
|
||||
# Check for args
|
||||
if not len(cmd.args)==3:
|
||||
if not len(cmd.args) == 3:
|
||||
self.bot.act_PRIVMSG(args[0], ".withdraw: usage: %s" % usage)
|
||||
self.bot.act_PRIVMSG(args[0], ".withdraw: usage: .getbal BTC 0.035")
|
||||
return
|
||||
# Check if currency is known
|
||||
if not rpc.isSupported(cmd.args[0]):
|
||||
supportedStr = ', '.join(rpc.getSupported())
|
||||
self.bot.act_PRIVMSG(args[0], ".getbal: '%s' is not a supported currency. Supported currencies are: %s" % (cmd.args[0], supportedStr))
|
||||
self.bot.act_PRIVMSG(args[0], ".getbal: '%s' is not a supported currency. Supported currencies are: %s" %
|
||||
(cmd.args[0], supportedStr))
|
||||
return
|
||||
|
||||
|
||||
# Just make sure they have a wallet
|
||||
self.checkUserHasWallet(prefix.nick, cmd.args[0])
|
||||
|
||||
|
||||
# fetch RPC and check balance
|
||||
walletname = attr.getKey(prefix.nick, "cryptowallet-account-%s"%cmd.args[0].lower())
|
||||
walletname = attr.getKey(prefix.nick, "cryptowallet-account-%s" % cmd.args[0].lower())
|
||||
balance = 0.0
|
||||
|
||||
|
||||
client = rpc.getRpc(cmd.args[0].lower())
|
||||
balance = client.getBal(walletname)
|
||||
withdrawamount = float(cmd.args[1])
|
||||
|
||||
if balance < withdrawamount or withdrawamount<0:
|
||||
self.bot.act_PRIVMSG(args[0], "%s: .send: You don't have enough %s to send %s" % (prefix.nick, cmd.args[0].upper(), withdrawamount))
|
||||
|
||||
if balance < withdrawamount or withdrawamount < 0:
|
||||
self.bot.act_PRIVMSG(args[0], "%s: .send: You don't have enough %s to send %s" %
|
||||
(prefix.nick, cmd.args[0].upper(), withdrawamount))
|
||||
return
|
||||
|
||||
|
||||
# Check if the precision is wrong
|
||||
if not client.checkPrecision(withdrawamount):
|
||||
self.bot.act_PRIVMSG(args[0], ".send: %s has maximum %s decimal places" % (cmd.args[0].upper(), client.precision))
|
||||
self.bot.act_PRIVMSG(args[0], ".send: %s has maximum %s decimal places" %
|
||||
(cmd.args[0].upper(), client.precision))
|
||||
return
|
||||
|
||||
|
||||
# Check if the recierver is a dogecoin address
|
||||
if len(cmd.args[2]) == 34 and cmd.args[2][0:1]=="D":
|
||||
if len(cmd.args[2]) == 34 and cmd.args[2][0:1] == "D":
|
||||
# Check if we can cover network fees
|
||||
if not client.reserve == 0 and balance - client.reserve < withdrawamount:
|
||||
self.bot.act_PRIVMSG(args[0], ".send: Sending that much would put you below the reserve (%s %s)." % (client.reserve, cmd.args[0].upper()))
|
||||
self.bot.act_PRIVMSG(args[0], ".send: The reserve is to cover network transaction fees. To recover it you must close your account. (Talk to an admin)")
|
||||
self.bot.act_PRIVMSG(args[0], ".send: Sending that much would put you below the reserve (%s %s)." %
|
||||
(client.reserve, cmd.args[0].upper()))
|
||||
self.bot.act_PRIVMSG(args[0], ".send: The reserve is to cover network transaction fees. To recover it "
|
||||
"you must close your account. (Talk to an admin)")
|
||||
return
|
||||
|
||||
|
||||
# Create a transaction
|
||||
txn = client.send(walletname, cmd.args[2], withdrawamount)
|
||||
if txn:
|
||||
self.bot.act_PRIVMSG(args[0], "%s: .send: %s %s sent to %s. "% (prefix.nick, withdrawamount, client.name, cmd.args[2]))
|
||||
self.bot.act_PRIVMSG(args[0], "%s: .send: %s %s sent to %s. " %
|
||||
(prefix.nick, withdrawamount, client.name, cmd.args[2]))
|
||||
self.bot.act_PRIVMSG(prefix.nick, "Send: (You)->%s: Transaction ID: %s" % (cmd.args[2], txn))
|
||||
else:
|
||||
self.bot.act_PRIVMSG(args[0], "%s: .send: Transaction create failed. Maybe the address is invalid or transaction too large for the network? Try a smaller increment."%prefix.nick)
|
||||
|
||||
self.bot.act_PRIVMSG(args[0], "%s: .send: Transaction create failed. Maybe the address is invalid or "
|
||||
"transaction too large for the network? Try a smaller increment." %
|
||||
prefix.nick)
|
||||
|
||||
else:
|
||||
# Move between local wallets
|
||||
# Check if dest user has a password set
|
||||
destUserPassword = attr.getKey(cmd.args[2], "password")
|
||||
if destUserPassword == None:
|
||||
if destUserPassword is None:
|
||||
self.bot.act_PRIVMSG(args[0], "%s .send: %s doesn't have a password set." % (prefix.nick, cmd.args[2]))
|
||||
return
|
||||
|
||||
|
||||
# Since the user has a password set, check that they have a wallet and create if not
|
||||
self.checkUserHasWallet(cmd.args[2], cmd.args[0])
|
||||
|
||||
srcWalletName = attr.getKey(prefix.nick, "cryptowallet-account-%s"%cmd.args[0])
|
||||
destWalletName = attr.getKey(cmd.args[2], "cryptowallet-account-%s"%cmd.args[0])
|
||||
|
||||
|
||||
srcWalletName = attr.getKey(prefix.nick, "cryptowallet-account-%s" % cmd.args[0])
|
||||
destWalletName = attr.getKey(cmd.args[2], "cryptowallet-account-%s" % cmd.args[0])
|
||||
|
||||
assert srcWalletName is not None
|
||||
assert destWalletName is not None
|
||||
try:
|
||||
@@ -197,100 +218,105 @@ class CryptoWallet(ModuleBase):
|
||||
print(destWalletName)
|
||||
if client.canMove(srcWalletName, destWalletName, withdrawamount):
|
||||
if client.move(srcWalletName, destWalletName, withdrawamount):
|
||||
self.bot.act_PRIVMSG(args[0], "%s .send: %s %s sent to %s. "% (prefix.nick, withdrawamount, client.name, cmd.args[2]))
|
||||
else:
|
||||
self.bot.act_PRIVMSG(args[0], "%s .send: %s %s sent to %s. " %
|
||||
(prefix.nick, withdrawamount, client.name, cmd.args[2]))
|
||||
else:
|
||||
self.bot.act_PRIVMSG(args[0], "%s: uh-oh, something went wrong doing that." % prefix.nick)
|
||||
|
||||
|
||||
def handle_getaddr(self, args, prefix, trailing, cmd):
|
||||
attr,rpc = self.getMods()
|
||||
attr, rpc = self.getMods()
|
||||
usage = ".getaddr <currency>"
|
||||
# Check for args
|
||||
if not len(cmd.args)==1:
|
||||
if not len(cmd.args) == 1:
|
||||
self.bot.act_PRIVMSG(args[0], ".getaddr: usage: %s" % usage)
|
||||
self.bot.act_PRIVMSG(args[0], ".getaddr: usage: .getaddr BTC")
|
||||
return
|
||||
# Check if currency is known
|
||||
if not rpc.isSupported(cmd.args[0]):
|
||||
supportedStr = ', '.join(rpc.getSupported())
|
||||
self.bot.act_PRIVMSG(args[0], ".getaddr: '%s' is not a supported currency. Supported currencies are: %s" % (cmd.args[0], supportedStr))
|
||||
self.bot.act_PRIVMSG(args[0], ".getaddr: '%s' is not a supported currency. Supported currencies are: %s" %
|
||||
(cmd.args[0], supportedStr))
|
||||
return
|
||||
|
||||
|
||||
# Just make sure they have a wallet
|
||||
self.checkUserHasWallet(prefix.nick, cmd.args[0])
|
||||
|
||||
walletaddr = attr.getKey(prefix.nick, "cryptowallet-depoaddr-%s"%cmd.args[0].lower())
|
||||
self.bot.act_PRIVMSG(args[0], "%s: your %s deposit address is: %s" % (prefix.nick, cmd.args[0].upper(), walletaddr))
|
||||
|
||||
|
||||
walletaddr = attr.getKey(prefix.nick, "cryptowallet-depoaddr-%s" % cmd.args[0].lower())
|
||||
self.bot.act_PRIVMSG(args[0], "%s: your %s deposit address is: %s" %
|
||||
(prefix.nick, cmd.args[0].upper(), walletaddr))
|
||||
|
||||
def handle_curinfo(self, args, prefix, trailing, cmd):
|
||||
attr,rpc = self.getMods()
|
||||
usage = ".curinfo [<currency>]"
|
||||
|
||||
attr, rpc = self.getMods()
|
||||
|
||||
# Check for args
|
||||
if len(cmd.args)==0:
|
||||
self.bot.act_PRIVMSG(args[0], ".curinfo: supported currencies: %s. Use '.curinfo BTC' to see details. " % ', '.join([x.upper() for x in rpc.getSupported()]))
|
||||
if len(cmd.args) == 0:
|
||||
self.bot.act_PRIVMSG(args[0], ".curinfo: supported currencies: %s. Use '.curinfo BTC' to see details. " %
|
||||
', '.join([x.upper() for x in rpc.getSupported()]))
|
||||
return
|
||||
else:
|
||||
if not rpc.isSupported(cmd.args[0]):
|
||||
self.bot.act_PRIVMSG(args[0], ".curinfo: '%s' is not a supported currency. Supported currencies are: %s" % (cmd.args[0], ', '.join([x.upper() for x in rpc.getSupported()])))
|
||||
self.bot.act_PRIVMSG(args[0], ".curinfo: '%s' is not a supported currency. Supported currencies are: "
|
||||
"%s" % (cmd.args[0], ', '.join([x.upper() for x in rpc.getSupported()])))
|
||||
return
|
||||
else:
|
||||
info = rpc.getInfo(cmd.args[0])
|
||||
self.bot.act_PRIVMSG(args[0], ".curinfo: %s - %s. More info: %s" % (args[0], info["name"], info["link"]))
|
||||
|
||||
self.bot.act_PRIVMSG(args[0], ".curinfo: %s - %s. More info: %s" %
|
||||
(args[0], info["name"], info["link"]))
|
||||
|
||||
def checkUserHasWallet(self, username, currency):
|
||||
# Ensure the user has a wallet in the client
|
||||
attr,rpc = self.getMods()
|
||||
attr, rpc = self.getMods()
|
||||
currency = currency.lower()
|
||||
username = username.lower()
|
||||
if attr.getKey(username, "cryptowallet-account-%s"%currency)==None:
|
||||
if attr.getKey(username, "cryptowallet-account-%s" % currency) is None:
|
||||
randName = self.md5(str(time.time()))[0:16]
|
||||
attr.setKey(username, "cryptowallet-account-%s"%currency, randName)
|
||||
attr.setKey(username, "cryptowallet-account-%s" % currency, randName)
|
||||
# Generate a deposit addr to nudge the wallet
|
||||
wallet = rpc.getRpc(currency.lower())
|
||||
address = wallet.getAcctAddr(randName)
|
||||
attr.setKey(username, "cryptowallet-depoaddr-%s"%currency, address)
|
||||
elif attr.getKey(username, "cryptowallet-depoaddr-%s"%currency)==None:
|
||||
walletName = attr.getKey(username, "cryptowallet-account-%s"%currency)
|
||||
attr.setKey(username, "cryptowallet-depoaddr-%s" % currency, address)
|
||||
elif attr.getKey(username, "cryptowallet-depoaddr-%s" % currency) is None:
|
||||
walletName = attr.getKey(username, "cryptowallet-account-%s" % currency)
|
||||
wallet = rpc.getRpc(currency.lower())
|
||||
address = wallet.getAcctAddr(walletName)
|
||||
attr.setKey(username, "cryptowallet-depoaddr-%s"%currency, address)
|
||||
|
||||
attr.setKey(username, "cryptowallet-depoaddr-%s" % currency, address)
|
||||
|
||||
def handle_message(self, args, prefix, trailing):
|
||||
prefix = self.bot.decodePrefix(prefix)
|
||||
|
||||
|
||||
# Free commands
|
||||
cmd = self.bot.messageHasCommand(".curinfo", trailing)
|
||||
if cmd:
|
||||
self.handle_curinfo(args, prefix, trailing, cmd)
|
||||
|
||||
|
||||
# Login protected commands
|
||||
cmd = self.bot.messageHasCommand(".setaddr", trailing)
|
||||
if cmd and self.check_login(prefix, args[0]):
|
||||
self.handle_setaddr(args, prefix, trailing, cmd)
|
||||
|
||||
|
||||
cmd = self.bot.messageHasCommand(".getbal", trailing)
|
||||
if cmd and self.check_login(prefix, args[0]):
|
||||
self.handle_getbal(args, prefix, trailing, cmd)
|
||||
|
||||
|
||||
cmd = self.bot.messageHasCommand(".withdraw", trailing)
|
||||
if cmd and self.check_login(prefix, args[0]):
|
||||
self.handle_withdraw(args, prefix, trailing, cmd)
|
||||
|
||||
|
||||
cmd = self.bot.messageHasCommand(".getaddr", trailing)
|
||||
if cmd and self.check_login(prefix, args[0]):
|
||||
self.handle_getaddr(args, prefix, trailing, cmd)
|
||||
|
||||
|
||||
cmd = self.bot.messageHasCommand(".send", trailing)
|
||||
if cmd and self.check_login(prefix, args[0]):
|
||||
self.handle_send(args, prefix, trailing, cmd)
|
||||
|
||||
|
||||
def check_login(self, prefix, replyTo):
|
||||
login = self.bot.getBestModuleForService("login")
|
||||
if not login.check(prefix.nick, prefix.hostname):
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: Please .login to use this command." % prefix.nick)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def md5(self, data):
|
||||
m = hashlib.md5()
|
||||
m.update(data.encode("ascii"))
|
||||
|
||||
@@ -7,31 +7,30 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase
|
||||
from bitcoinrpc.authproxy import AuthServiceProxy
|
||||
from math import floor
|
||||
from threading import Thread
|
||||
from time import sleep
|
||||
|
||||
|
||||
class CryptoWalletRPC(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[]
|
||||
self.services=["bitcoinrpc"]
|
||||
self.loadConfig()
|
||||
self.rpcservices={}
|
||||
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = []
|
||||
self.services = ["bitcoinrpc"]
|
||||
self.rpcservices = {}
|
||||
self.loadrpcservices()
|
||||
|
||||
|
||||
def loadrpcservices(self):
|
||||
# Create a dict of abbreviation=>BitcoinRPC objcet relation
|
||||
self.log.info("CryptoWalletRPC: loadrpcservices: connecting to RPCs")
|
||||
count = len(list(self.config["types"].keys()))
|
||||
num = 0
|
||||
for key in self.config["types"]:
|
||||
self.rpcservices[key.lower()]=BitcoinRPC(self, key, self.config["types"][key]["host"], self.config["types"][key]["port"], self.config["types"][key]["username"], self.config["types"][key]["password"], self.config["types"][key]["precision"], self.config["types"][key]["reserve"])
|
||||
num+=1
|
||||
|
||||
self.rpcservices[key.lower()] = BitcoinRPC(self, key, self.config["types"][key]["host"],
|
||||
self.config["types"][key]["port"],
|
||||
self.config["types"][key]["username"],
|
||||
self.config["types"][key]["password"],
|
||||
self.config["types"][key]["precision"],
|
||||
self.config["types"][key]["reserve"])
|
||||
|
||||
def getRpc(self, currencyAbbr):
|
||||
# Return the rpc for the currency requested
|
||||
# self.getRpc("LTC") -> returns a litecoin rpc instance
|
||||
@@ -39,21 +38,21 @@ class CryptoWalletRPC(ModuleBase):
|
||||
if currencyAbbr in self.rpcservices:
|
||||
return self.rpcservices[currencyAbbr]
|
||||
return None
|
||||
|
||||
|
||||
def getSupported(self):
|
||||
# return a list of (appreviatons of) supported currencies
|
||||
return list(self.rpcservices.keys())
|
||||
|
||||
|
||||
def isSupported(self, abbr):
|
||||
# true/false if currency is supported
|
||||
supported = self.getSupported()
|
||||
return abbr.lower() in supported
|
||||
|
||||
|
||||
def getInfo(self, abbr):
|
||||
# return the coin's info from config
|
||||
if self.isSupported(abbr):
|
||||
return self.config["types"][abbr.upper()]
|
||||
|
||||
|
||||
|
||||
class BitcoinRPC:
|
||||
def __init__(self, parent, name, host, port, username, password, precision, reserve):
|
||||
@@ -67,67 +66,66 @@ class BitcoinRPC:
|
||||
self.precision = precision
|
||||
self.reserve = reserve
|
||||
self.log = self.master.log
|
||||
|
||||
|
||||
# AuthServiceProxy (json client) stored here
|
||||
self.con = None
|
||||
# Connect
|
||||
Thread(target=self.ping).start()
|
||||
|
||||
|
||||
def getBal(self, acct):
|
||||
# get a balance of an address or an account
|
||||
# get a balance of an address or an account
|
||||
return self.getAcctBal(acct)
|
||||
|
||||
|
||||
def getAcctAddr(self, acct):
|
||||
# returns the address for an account. creates if necessary
|
||||
# returns the address for an account. creates if necessary
|
||||
self.ping()
|
||||
addrs = self.con.getaddressesbyaccount(acct)
|
||||
if len(addrs)==0:
|
||||
if len(addrs) == 0:
|
||||
return self.con.getnewaddress(acct)
|
||||
return addrs[0]
|
||||
|
||||
|
||||
def getAcctBal(self, acct):
|
||||
# returns an account's balance
|
||||
self.ping()
|
||||
return float(self.con.getbalance(acct))
|
||||
|
||||
|
||||
def canMove(self, fromAcct, toAcct, amount):
|
||||
# true or false if fromAcct can afford to give toAcct an amount of coins
|
||||
# true or false if fromAcct can afford to give toAcct an amount of coins
|
||||
balfrom = self.getAcctBal(fromAcct)
|
||||
return balfrom >= amount
|
||||
|
||||
|
||||
def move(self, fromAcct, toAcct, amount):
|
||||
# move coins from one account to another
|
||||
# move coins from one account to another
|
||||
self.ping()
|
||||
if self.canMove(fromAcct, toAcct, amount):
|
||||
return self.con.move(fromAcct, toAcct, amount)
|
||||
return False
|
||||
|
||||
|
||||
def send(self, fromAcct, toAddr, amount):
|
||||
# send coins to an external addr
|
||||
# send coins to an external addr
|
||||
self.ping()
|
||||
if self.canMove(fromAcct, toAddr, amount):
|
||||
return self.con.sendfrom(fromAcct, toAddr, amount)
|
||||
return False
|
||||
|
||||
|
||||
def checkPrecision(self, amount):
|
||||
return amount == round(amount, self.precision)
|
||||
|
||||
|
||||
def ping(self):
|
||||
# internal. test connection and connect if necessary
|
||||
try:
|
||||
self.con.getinfo()
|
||||
except:
|
||||
self.connect()
|
||||
|
||||
|
||||
def connect(self):
|
||||
# internal. connect to the service
|
||||
self.log.info("CryptoWalletRPC: %s: Connecting to %s:%s" % (self.name, self.host,self.port))
|
||||
self.log.info("CryptoWalletRPC: %s: Connecting to %s:%s" % (self.name, self.host, self.port))
|
||||
try:
|
||||
self.con = AuthServiceProxy("http://%s:%s@%s:%s" % (self.username, self.password, self.host, self.port))
|
||||
except Exception as e:
|
||||
self.log.info("CryptoWalletRPC: %s: Could not connect to %s:%s: %s" % (self.name, self.host, self.port, str(e)))
|
||||
self.log.error("CryptoWalletRPC: %s: Could not connect to %s:%s: %s" %
|
||||
(self.name, self.host, self.port, str(e)))
|
||||
return
|
||||
|
||||
self.log.info("CryptoWalletRPC: %s: Connected to %s:%s" % (self.name, self.host, self.port))
|
||||
|
||||
|
||||
self.log.info("CryptoWalletRPC: %s: Connected to %s:%s" % (self.name, self.host, self.port))
|
||||
|
||||
@@ -7,57 +7,56 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase ModuleHook
|
||||
import random
|
||||
import os
|
||||
import time
|
||||
import math
|
||||
import hashlib
|
||||
from threading import Timer
|
||||
|
||||
|
||||
class DogeDice(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.gotMsg)]
|
||||
self.loadConfig()
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.gotMsg)]
|
||||
# Load attribute storage
|
||||
self.attr = self.bot.getBestModuleForService("attributes")
|
||||
# Load doge RPC
|
||||
self.doge = self.bot.getBestModuleForService("dogerpc")
|
||||
# Dict of #channel -> game object
|
||||
self.games = {}
|
||||
|
||||
|
||||
def gotMsg(self, args, prefix, trailing):
|
||||
prefixObj = self.bot.decodePrefix(prefix)
|
||||
# Ignore messages from users not logged in
|
||||
loggedinfrom = self.attr.getKey(prefixObj.nick, "loggedinfrom")
|
||||
if loggedinfrom==None:
|
||||
if loggedinfrom is None:
|
||||
# Send them a hint?
|
||||
return
|
||||
elif prefixObj.hostname == loggedinfrom:
|
||||
if args[0][0] == "#":
|
||||
# create a blank game obj if there isn't one (and whitelisted ? )
|
||||
if not args[0] in self.games and (not self.config["channelWhitelistOn"] or (self.config["channelWhitelistOn"] and args[0][1:] in self.config["channelWhitelist"]) ):
|
||||
self.games[args[0]]=gameObj(self, args[0])
|
||||
if not args[0] in self.games and (not self.config["channelWhitelistOn"] or
|
||||
(self.config["channelWhitelistOn"] and args[0][1:] in self.config["channelWhitelist"])):
|
||||
self.games[args[0]] = gameObj(self, args[0])
|
||||
# Channel message
|
||||
self.games[args[0]].gotMsg(args, prefix, trailing)
|
||||
else:
|
||||
# Private message
|
||||
#self.games[args[0].gotPrivMsg(args, prefix, trailing)
|
||||
# self.games[args[0].gotPrivMsg(args, prefix, trailing)
|
||||
pass
|
||||
else:
|
||||
# Ignore potential spoofing
|
||||
pass
|
||||
|
||||
|
||||
def removeGame(self, channel):
|
||||
del self.games[channel]
|
||||
|
||||
|
||||
def ondisable(self):
|
||||
self.log.info("DogeDice: Unload requested, ending games...")
|
||||
while len(self.games)>0:
|
||||
while len(self.games) > 0:
|
||||
first = list(self.games.keys())[0]
|
||||
self.games[first].gameover()
|
||||
|
||||
|
||||
class gameObj:
|
||||
def __init__(self, master, channel):
|
||||
self.master = master
|
||||
@@ -75,7 +74,7 @@ class gameObj:
|
||||
# 4 = determine winner, move doge
|
||||
# - if > 10 doge, house fee?
|
||||
self.step = 0
|
||||
|
||||
|
||||
# Bet amount
|
||||
self.bet = 0.0
|
||||
# players list
|
||||
@@ -88,80 +87,88 @@ class gameObj:
|
||||
self.startCountdownTimer = None
|
||||
# pre-result timer
|
||||
self.endgameResultTimer = None
|
||||
# in-game timeout
|
||||
# in-game timeout
|
||||
self.playTimeout = None
|
||||
# Wallet for this game
|
||||
self.walletName = None
|
||||
|
||||
|
||||
def getPlayer(self, nick):
|
||||
for player in self.players:
|
||||
if player.nick == nick:
|
||||
return player
|
||||
return None
|
||||
|
||||
|
||||
def gotPrivMsg(self, args, prefix, trailing):
|
||||
prefix = self.master.bot.decodePrefix(prefix)
|
||||
pass
|
||||
|
||||
|
||||
def gotMsg(self, args, prefix, trailing):
|
||||
prefix = self.master.bot.decodePrefix(prefix)
|
||||
if self.step == 0 or self.step == 1:
|
||||
# Join game
|
||||
cmd = self.master.bot.messageHasCommand(".join", trailing)
|
||||
if cmd:
|
||||
if len(self.players)-1 < self.maxPlayers:
|
||||
if self.getPlayer(prefix.nick)==None:
|
||||
if len(self.players) - 1 < self.maxPlayers:
|
||||
if self.getPlayer(prefix.nick) is None:
|
||||
userWallet = self.master.attr.getKey(prefix.nick, "dogeaccountname")
|
||||
if userWallet == None:
|
||||
if userWallet is None:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: You don't have enough DOGE!" % (prefix.nick))
|
||||
return
|
||||
balance = self.master.doge.getBal(userWallet)
|
||||
|
||||
|
||||
# check if the room is 'opened' already:
|
||||
if len(self.players)==0:
|
||||
if not self.players:
|
||||
# require an amount
|
||||
if len(cmd.args)==1:
|
||||
if len(cmd.args) == 1:
|
||||
# Check if they have enough coins
|
||||
try:
|
||||
bet = float(cmd.args[0])
|
||||
except:
|
||||
return
|
||||
|
||||
|
||||
if bet < self.master.config["minBet"]:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: Minimum bet is %s DOGE!" % (prefix.nick, self.master.config["minBet"]))
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: Minimum bet is %s DOGE!" %
|
||||
(prefix.nick, self.master.config["minBet"]))
|
||||
return
|
||||
|
||||
if balance>=bet:
|
||||
|
||||
if balance >= bet:
|
||||
newPlayer = playerObj(self, prefix.nick)
|
||||
newPlayer.dogeWalletName = userWallet
|
||||
self.players.append(newPlayer)
|
||||
self.bet = bet
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: You have joined!" % (prefix.nick))
|
||||
else:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: You don't have enough DOGE!" % (prefix.nick))
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: You don't have enough DOGE!" %
|
||||
(prefix.nick))
|
||||
else:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: You need to specify a bet amount: .join 10" % (prefix.nick))
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: You need to specify a bet amount: "
|
||||
".join 10" % (prefix.nick))
|
||||
else:
|
||||
# no amount required
|
||||
if balance>=self.bet:
|
||||
if balance >= self.bet:
|
||||
newPlayer = playerObj(self, prefix.nick)
|
||||
newPlayer.dogeWalletName = userWallet
|
||||
self.players.append(newPlayer)
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: You have joined!" % (prefix.nick))
|
||||
if self.canStart() and self.startCountdownTimer == None:
|
||||
if self.canStart() and self.startCountdownTimer is None:
|
||||
self.initStartCountdown()
|
||||
self.master.bot.act_PRIVMSG(self.channel, "The game will start in %s seconds! Bet is %s DOGE each!" % (self.master.config["lobbyIdleSeconds"], self.bet))
|
||||
self.master.bot.act_PRIVMSG(self.channel, "The game will start in %s seconds! "
|
||||
"Bet is %s DOGE each!" %
|
||||
(self.master.config["lobbyIdleSeconds"], self.bet))
|
||||
else:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: You don't have enough DOGE!" % (prefix.nick))
|
||||
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: You don't have enough DOGE!" %
|
||||
(prefix.nick))
|
||||
|
||||
else:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: you're already in the game. Quit with .leave" % (prefix.nick))
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: you're already in the game. Quit with .leave" %
|
||||
(prefix.nick))
|
||||
else:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: the game is full (%s/%)! Cannot join." % (prefix.nick, len(self.players), self.maxPlayers))
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: the game is full (%s/%)! Cannot join." %
|
||||
(prefix.nick, len(self.players), self.maxPlayers))
|
||||
# Leave game
|
||||
cmd = self.master.bot.messageHasCommand(".leave", trailing)
|
||||
if cmd:
|
||||
if self.getPlayer(prefix.nick)==None:
|
||||
if self.getPlayer(prefix.nick) is None:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: You're not in the game." % (prefix.nick))
|
||||
else:
|
||||
self.removePlayer(prefix.nick)
|
||||
@@ -169,7 +176,7 @@ class gameObj:
|
||||
if not self.canStart() and self.startCountdownTimer:
|
||||
self.clearTimer(self.startCountdownTimer)
|
||||
self.startCountdownTimer = None
|
||||
self.master.bot.act_PRIVMSG(self.channel, "Game start aborted." )
|
||||
self.master.bot.act_PRIVMSG(self.channel, "Game canceled.")
|
||||
self.step = 0
|
||||
elif self.step == 2:
|
||||
pass
|
||||
@@ -178,35 +185,34 @@ class gameObj:
|
||||
player = self.getPlayer(prefix.nick)
|
||||
if not player:
|
||||
return
|
||||
|
||||
|
||||
# handle a .roll
|
||||
cmd = self.master.bot.messageHasCommand(".roll", trailing)
|
||||
if cmd and not player.hasRolled:
|
||||
roll1 = random.randint(1,6)
|
||||
roll2 = random.randint(1,6)
|
||||
roll1 = random.randint(1, 6)
|
||||
roll2 = random.randint(1, 6)
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s rolls %s and %s!" % (prefix.nick, roll1, roll2))
|
||||
player.hasRolled = True
|
||||
player.rollValue = roll1+roll2
|
||||
|
||||
player.rollValue = roll1 + roll2
|
||||
|
||||
# Check if all players have rolled
|
||||
for player in self.players:
|
||||
if not player.hasRolled:
|
||||
return
|
||||
|
||||
|
||||
# start endgame timer
|
||||
self.step = 4
|
||||
self.endgameResultTimer = Timer(2, self.endgameResults)
|
||||
self.endgameResultTimer.start()
|
||||
|
||||
|
||||
elif self.step == 4:
|
||||
pass
|
||||
|
||||
#senderIsOp = self.master.attr.getKey(prefix.nick, "op")=="yes"
|
||||
|
||||
def clearTimer(self, timer):
|
||||
if timer:
|
||||
timer.cancel()
|
||||
timer = None
|
||||
|
||||
|
||||
def removePlayer(self, playerNick):
|
||||
pos = -1
|
||||
for i in range(0, len(self.players)):
|
||||
@@ -215,49 +221,50 @@ class gameObj:
|
||||
break
|
||||
if pos >= 0:
|
||||
self.players.pop(pos)
|
||||
|
||||
|
||||
def canStart(self):
|
||||
# Return true if the step is 'lobby' mode and player count is OK
|
||||
return self.step == 0 and len(self.players)>=self.minPlayers
|
||||
return self.step == 0 and len(self.players) >= self.minPlayers
|
||||
|
||||
def initStartCountdown(self):
|
||||
# Start the game-start countdown
|
||||
self.startCountdownTimer = Timer(self.master.config["lobbyIdleSeconds"], self.lobbyCountdownDone)
|
||||
self.startCountdownTimer.start()
|
||||
self.step = 1
|
||||
|
||||
|
||||
def lobbyCountdownDone(self):
|
||||
self.step = 2
|
||||
self.master.bot.act_PRIVMSG(self.channel, "Collecting DOGE and starting game.. Type .roll !")
|
||||
# Make a wallet for this game
|
||||
self.walletName = "DogeDice-"+self.channel
|
||||
self.walletName = "DogeDice-" + self.channel
|
||||
# Generate an address to 'create' a wallet
|
||||
self.master.doge.getAcctAddr(self.walletName)
|
||||
|
||||
|
||||
# Verify and move funds from each player
|
||||
for player in self.players:
|
||||
playerBalance = self.master.doge.getAcctBal(player.dogeWalletName)
|
||||
if playerBalance < self.bet:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s was dropped from the game!")
|
||||
self.removePlayer(player.nick)
|
||||
|
||||
|
||||
if len(self.players) <= 1:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "1 or players left - game over!")
|
||||
self.resetGame()
|
||||
return
|
||||
|
||||
|
||||
# Take doges
|
||||
for player in self.players:
|
||||
self.master.doge.move(player.dogeWalletName, self.walletName, self.bet)
|
||||
|
||||
|
||||
# Pre-game setup (nothing !)
|
||||
|
||||
|
||||
# Accept game commands
|
||||
self.step = 3
|
||||
|
||||
|
||||
# Start play timeout
|
||||
self.playTimeout = Timer(30, self.gamePlayTimeoutExpired)
|
||||
self.playTimeout.start()
|
||||
|
||||
|
||||
def gamePlayTimeoutExpired(self):
|
||||
# Time out - return doges
|
||||
self.master.bot.act_PRIVMSG(self.channel, "Time expired! Returning all doges.")
|
||||
@@ -267,7 +274,7 @@ class gameObj:
|
||||
for player in self.players:
|
||||
self.master.doge.move(self.walletName, player.dogeWalletName, self.bet)
|
||||
self.resetGame()
|
||||
|
||||
|
||||
def endgameResults(self):
|
||||
maxRollNames = []
|
||||
maxRollValue = 0
|
||||
@@ -277,26 +284,28 @@ class gameObj:
|
||||
maxRollNames.append(player.nick)
|
||||
maxRollValue = player.rollValue
|
||||
if player.rollValue == maxRollValue:
|
||||
if not player.nick in maxRollNames:
|
||||
if player.nick not in maxRollNames:
|
||||
maxRollNames.append(player.nick)
|
||||
|
||||
|
||||
pot = self.master.doge.getAcctBal(self.walletName)
|
||||
DOGEeachDec = pot/len(maxRollNames)
|
||||
DOGEeach = math.floor(DOGEeachDec*100000000) / 100000000
|
||||
|
||||
if len(maxRollNames)==1:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "We have a winner - %s! Winnings are: %s DOGE" % (maxRollNames[0], DOGEeach))
|
||||
DOGEeachDec = pot / len(maxRollNames)
|
||||
DOGEeach = math.floor(DOGEeachDec * 100000000) / 100000000
|
||||
|
||||
if len(maxRollNames) == 1:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "We have a winner - %s! Winnings are: %s DOGE" %
|
||||
(maxRollNames[0], DOGEeach))
|
||||
else:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "We have a tie between %s - The take is %s DOGE each" % (' and '.join(maxRollNames), DOGEeach))
|
||||
|
||||
self.master.bot.act_PRIVMSG(self.channel, "We have a tie between %s - The take is %s DOGE each" %
|
||||
(' and '.join(maxRollNames), DOGEeach))
|
||||
|
||||
# Pay out
|
||||
for nick in maxRollNames:
|
||||
player = self.getPlayer(nick)
|
||||
self.master.doge.move(self.walletName, player.dogeWalletName, DOGEeach)
|
||||
|
||||
|
||||
# the end!
|
||||
self.resetGame()
|
||||
|
||||
|
||||
def resetGame(self):
|
||||
self.clearTimer(self.startCountdownTimer)
|
||||
self.startCountdownTimer = None
|
||||
@@ -305,10 +314,10 @@ class gameObj:
|
||||
self.clearTimer(self.playTimeout)
|
||||
self.playTimeout = None
|
||||
self.master.removeGame(self.channel)
|
||||
|
||||
|
||||
def gameover(self):
|
||||
self.gamePlayTimeoutExpired()
|
||||
|
||||
|
||||
|
||||
class playerObj:
|
||||
def __init__(self, game, nick):
|
||||
@@ -320,4 +329,4 @@ class playerObj:
|
||||
self.hasRolled = False
|
||||
# Sum of their dice
|
||||
self.rollValue = None
|
||||
|
||||
|
||||
|
||||
@@ -7,46 +7,46 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase
|
||||
from bitcoinrpc.authproxy import AuthServiceProxy
|
||||
|
||||
|
||||
class DogeRPC(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[]
|
||||
self.services=["dogerpc"]
|
||||
self.loadConfig()
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = []
|
||||
self.services = ["dogerpc"]
|
||||
self.rpc = DogeController(self)
|
||||
|
||||
|
||||
def getBal(self, acct):
|
||||
"Get a balance of a local address or an account "
|
||||
return self.getAcctBal(acct)
|
||||
|
||||
|
||||
def getAcctAddr(self, acct):
|
||||
"Returns the address for an account. creates if necessary "
|
||||
self.rpc.ping()
|
||||
addrs = self.rpc.con.getaddressesbyaccount(acct)
|
||||
if len(addrs)==0:
|
||||
if len(addrs) == 0:
|
||||
return self.rpc.con.getnewaddress(acct)
|
||||
return addrs[0]
|
||||
|
||||
|
||||
def getAcctBal(self, acct):
|
||||
"Returns an account's balance"
|
||||
self.rpc.ping()
|
||||
return float(self.rpc.con.getbalance(acct))
|
||||
|
||||
|
||||
def canMove(self, fromAcct, toAcct, amount):
|
||||
"True or false if fromAcct can afford to give toAcct an amount of coins "
|
||||
balfrom = self.getAcctBal(fromAcct)
|
||||
return balfrom >= amount
|
||||
|
||||
|
||||
def move(self, fromAcct, toAcct, amount):
|
||||
"Move coins from one account to another "
|
||||
self.rpc.ping()
|
||||
if self.canMove(fromAcct, toAcct, amount):
|
||||
return self.rpc.con.move(fromAcct, toAcct, amount)
|
||||
return False
|
||||
|
||||
|
||||
def send(self, fromAcct, toAddr, amount):
|
||||
"Send coins to an external addr "
|
||||
self.rpc.ping()
|
||||
@@ -54,6 +54,7 @@ class DogeRPC(ModuleBase):
|
||||
return self.rpc.con.sendfrom(fromAcct, toAddr, amount)
|
||||
return False
|
||||
|
||||
|
||||
class DogeController:
|
||||
"RPC instance control class"
|
||||
def __init__(self, master):
|
||||
@@ -61,7 +62,7 @@ class DogeController:
|
||||
self.log = master.log
|
||||
self.con = None
|
||||
self.ping()
|
||||
|
||||
|
||||
def ping(self):
|
||||
"Test connection and re-establish if necessary"
|
||||
if not self.con:
|
||||
@@ -70,10 +71,11 @@ class DogeController:
|
||||
self.con.getinfo()
|
||||
except:
|
||||
self.connect()
|
||||
|
||||
|
||||
def connect(self):
|
||||
"Connect to RPC endpoint"
|
||||
self.log.info("DogeRPC: Connecting to dogecoind")
|
||||
self.con = AuthServiceProxy("http://%s:%s@%s:%s" % (self.config["username"], self.config["password"], self.config["host"], self.config["port"]))
|
||||
self.con = AuthServiceProxy("http://%s:%s@%s:%s" % (self.config["username"], self.config["password"],
|
||||
self.config["host"], self.config["port"]))
|
||||
self.con.getinfo()
|
||||
self.log.info("DogeRPC: Connected to %s:%s" % (self.config["host"], self.config["port"]))
|
||||
|
||||
@@ -7,48 +7,48 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
import random
|
||||
import os
|
||||
import time
|
||||
from threading import Timer
|
||||
|
||||
|
||||
class DogeScramble(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.scramble)]
|
||||
self.loadConfig()
|
||||
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.scramble)]
|
||||
# Load attribute storage
|
||||
self.attr = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("attributes")
|
||||
if len(serviceProviders)==0:
|
||||
if len(serviceProviders) == 0:
|
||||
self.log.error("DogeScramble: Could not find a valid attributes service provider")
|
||||
else:
|
||||
self.log.info("DogeScramble: Selecting attributes service provider: %s" % serviceProviders[0])
|
||||
self.attr = serviceProviders[0]
|
||||
|
||||
|
||||
# Load doge RPC
|
||||
self.doge = self.bot.getBestModuleForService("dogerpc")
|
||||
|
||||
|
||||
# Per channel games
|
||||
self.games = {}
|
||||
|
||||
|
||||
def scramble(self, args, prefix, trailing):
|
||||
channel = args[0]
|
||||
if channel[0] == "#":
|
||||
# Ignore messages from users without a dogewallet password
|
||||
prefixObj = self.bot.decodePrefix(prefix)
|
||||
if self.attr.getKey(prefixObj.nick, "password")==None:
|
||||
if self.attr.getKey(prefixObj.nick, "password") is None:
|
||||
return
|
||||
if not channel in self.games:
|
||||
self.games[channel]=scrambleGame(self, channel)
|
||||
if channel not in self.games:
|
||||
self.games[channel] = scrambleGame(self, channel)
|
||||
self.games[channel].scramble(args, prefix, trailing)
|
||||
|
||||
def ondisable(self):
|
||||
self.log.info("DogeScramble: Unload requested, ending games...")
|
||||
for game in self.games:
|
||||
self.games[game].gameover()
|
||||
|
||||
|
||||
class scrambleGame:
|
||||
def __init__(self, master, channel):
|
||||
self.master = master
|
||||
@@ -68,12 +68,12 @@ class scrambleGame:
|
||||
# Cooldown between words
|
||||
self.nextTimer = None
|
||||
# How many guesses submitted this round
|
||||
self.guesses = 0;
|
||||
self.guesses = 0
|
||||
# How many games in a row where nobody guessed
|
||||
self.gamesWithoutGuesses = 0;
|
||||
self.gamesWithoutGuesses = 0
|
||||
# What file are we using
|
||||
self.category_file = None;
|
||||
# How many words in this category have been used?
|
||||
self.category_file = None
|
||||
# How many words in this category have been used?
|
||||
self.category_count = 0
|
||||
# How long between categories
|
||||
self.change_category_after_words = self.master.config["categoryduration"]
|
||||
@@ -86,30 +86,33 @@ class scrambleGame:
|
||||
# name of last winner for decreasing return
|
||||
self.lastwinner = None
|
||||
self.lastwinvalue = 0
|
||||
|
||||
self.delayHint = self.master.config["hintDelay"];
|
||||
self.delayNext = self.master.config["delayNext"];
|
||||
self.maxHints = self.master.config["maxHints"];
|
||||
self.abortAfterNoGuesses = self.master.config["abortAfterNoGuesses"];
|
||||
|
||||
|
||||
self.delayHint = self.master.config["hintDelay"]
|
||||
self.delayNext = self.master.config["delayNext"]
|
||||
self.maxHints = self.master.config["maxHints"]
|
||||
self.abortAfterNoGuesses = self.master.config["abortAfterNoGuesses"]
|
||||
|
||||
def gameover(self):
|
||||
self.clearTimers();
|
||||
self.clearTimers()
|
||||
self.running = False
|
||||
|
||||
def clearTimers(self):
|
||||
self.clearTimer(self.nextTimer)
|
||||
self.clearTimer(self.hintTimer)
|
||||
|
||||
def clearTimer(self, timer):
|
||||
if timer:
|
||||
timer.cancel()
|
||||
|
||||
def scramble(self, args, prefix, trailing):
|
||||
prefix = self.master.bot.decodePrefix(prefix)
|
||||
sender = prefix.nick
|
||||
|
||||
senderIsOp = self.master.attr.getKey(prefix.nick, "op")=="yes"
|
||||
|
||||
|
||||
senderIsOp = self.master.attr.getKey(prefix.nick, "op") == "yes"
|
||||
|
||||
cmd = self.master.bot.messageHasCommand(".scramble", trailing)
|
||||
if cmd and not self.running:
|
||||
#and senderIsOp
|
||||
# and senderIsOp
|
||||
self.running = True
|
||||
self.startScramble()
|
||||
return
|
||||
@@ -118,100 +121,105 @@ class scrambleGame:
|
||||
self.gameover()
|
||||
self.running = False
|
||||
return
|
||||
|
||||
|
||||
if self.currentWord and trailing.strip().lower() == self.currentWord:
|
||||
# Get winner withdraw address
|
||||
useraddr = self.master.attr.getKey(prefix.nick, "dogeaddr")
|
||||
userwallet = self.master.attr.getKey(prefix.nick, "dogeaccountname")
|
||||
|
||||
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s got the word - %s!" % (sender, self.currentWord))
|
||||
|
||||
|
||||
if not useraddr:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: to win DOGE, you must set an wallet address by PMing me \".setdogeaddr\". Next word in %s seconds." % (prefix.nick, self.delayNext))
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: to win DOGE, you must set an wallet address by PMing me "
|
||||
"\".setdogeaddr\". Next word in %s seconds." %
|
||||
(prefix.nick, self.delayNext))
|
||||
else:
|
||||
winamount = float(self.master.config["winAmount"])
|
||||
if self.lastwinner == prefix.nick:
|
||||
winamount = self.lastwinvalue * self.master.config["decreaseFactor"]
|
||||
self.lastwinvalue = winamount
|
||||
self.lastwinner = prefix.nick
|
||||
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s won %s DOGE! Next word in %s seconds." % (prefix.nick, round(winamount, 8), self.delayNext))
|
||||
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s won %s DOGE! Next word in %s seconds." %
|
||||
(prefix.nick, round(winamount, 8), self.delayNext))
|
||||
self.master.doge.move('', userwallet, winamount)
|
||||
|
||||
|
||||
self.currentWord = None
|
||||
self.clearTimers()
|
||||
self.hintsGiven = 0
|
||||
self.nextTimer = Timer(self.delayNext, self.startNewWord)
|
||||
self.nextTimer.start()
|
||||
self.guesses=0
|
||||
self.category_count+=1
|
||||
self.guesses = 0
|
||||
self.category_count += 1
|
||||
self.master.log.info("DogeScramble: category_count is: %s" % (self.category_count))
|
||||
if self.category_count >= self.change_category_after_words:
|
||||
self.should_change_category = True
|
||||
else:
|
||||
self.guesses+=1
|
||||
|
||||
self.guesses += 1
|
||||
|
||||
def startScramble(self):
|
||||
self.clearTimer(self.nextTimer)
|
||||
self.nextTimer = Timer(0, self.startNewWord)
|
||||
self.nextTimer.start()
|
||||
|
||||
|
||||
def startNewWord(self):
|
||||
self.currentWord = self.pickWord()
|
||||
self.scrambled = self.scrambleWord(self.currentWord)
|
||||
self.master.bot.act_PRIVMSG(self.channel, "[Category: %s] Unscramble this: %s " % (self.category_name, self.scrambled))
|
||||
|
||||
self.master.bot.act_PRIVMSG(self.channel, "[Category: %s] Unscramble this: %s " %
|
||||
(self.category_name, self.scrambled))
|
||||
|
||||
self.clearTimer(self.hintTimer)
|
||||
self.hintTimer = Timer(self.delayHint, self.giveHint)
|
||||
self.hintTimer.start()
|
||||
|
||||
|
||||
def giveHint(self):
|
||||
self.hintsGiven+=1
|
||||
|
||||
if self.hintsGiven>=len(self.currentWord) or self.hintsGiven > self.maxHints:
|
||||
self.hintsGiven += 1
|
||||
|
||||
if self.hintsGiven >= len(self.currentWord) or self.hintsGiven > self.maxHints:
|
||||
self.abortWord()
|
||||
return
|
||||
|
||||
|
||||
blanks = ""
|
||||
for letter in list(self.currentWord):
|
||||
if letter == " ":
|
||||
blanks+=" "
|
||||
blanks += " "
|
||||
else:
|
||||
blanks+="_"
|
||||
blanks += "_"
|
||||
partFromWord = self.currentWord[0:self.hintsGiven]
|
||||
partFromBlanks = blanks[self.hintsGiven:]
|
||||
hintstr = partFromWord+partFromBlanks
|
||||
|
||||
hintstr = partFromWord + partFromBlanks
|
||||
|
||||
self.master.bot.act_PRIVMSG(self.channel, "Hint: - %s" % (hintstr))
|
||||
|
||||
|
||||
self.clearTimer(self.hintTimer)
|
||||
self.hintTimer = Timer(self.delayHint, self.giveHint)
|
||||
self.hintTimer.start()
|
||||
|
||||
|
||||
def abortWord(self):
|
||||
cur = self.currentWord
|
||||
self.currentWord = None
|
||||
self.master.bot.act_PRIVMSG(self.channel, "Word expired - the answer was '%s'. Next word in %s seconds." % (cur, self.delayNext))
|
||||
self.master.bot.act_PRIVMSG(self.channel, "Word expired - the answer was '%s'. Next word in %s seconds." %
|
||||
(cur, self.delayNext))
|
||||
self.hintsGiven = 0
|
||||
self.clearTimer(self.nextTimer)
|
||||
|
||||
if self.guesses==0:
|
||||
self.gamesWithoutGuesses+=1
|
||||
|
||||
if self.guesses == 0:
|
||||
self.gamesWithoutGuesses += 1
|
||||
if self.gamesWithoutGuesses >= self.abortAfterNoGuesses:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "No one seems to be playing - type .scramble to start again.")
|
||||
self.gameover()
|
||||
return
|
||||
else:
|
||||
self.gamesWithoutGuesses=0
|
||||
|
||||
self.gamesWithoutGuesses = 0
|
||||
|
||||
self.nextTimer = Timer(self.delayNext, self.startNewWord)
|
||||
self.nextTimer.start()
|
||||
|
||||
|
||||
def catFileNameToStr(self, s):
|
||||
s=s.split(".")[0]
|
||||
s=s.replace("_", " ")
|
||||
s = s.split(".")[0]
|
||||
s = s.replace("_", " ")
|
||||
return s.title()
|
||||
|
||||
|
||||
def pickWord(self):
|
||||
if self.should_change_category:
|
||||
# clear flags
|
||||
@@ -231,34 +239,33 @@ class scrambleGame:
|
||||
f = open(self.master.getFilePath(self.category_file), "r")
|
||||
lines = 0
|
||||
while True:
|
||||
lines+=1
|
||||
lines += 1
|
||||
if f.readline() == "":
|
||||
break
|
||||
f.close()
|
||||
# change category
|
||||
picked = ""
|
||||
while picked == "" or picked in self.lastwords:
|
||||
|
||||
|
||||
skip = random.randint(0, lines)
|
||||
f = open(self.master.getFilePath(self.category_file), "r")
|
||||
while skip>=0:
|
||||
while skip >= 0:
|
||||
f.readline()
|
||||
skip-=1
|
||||
skip -= 1
|
||||
picked = f.readline().strip().lower()
|
||||
f.close()
|
||||
|
||||
self.master.log.info("DogeScramble: picked %s for %s" % (picked, self.channel))
|
||||
self.lastwords.append(picked)
|
||||
if len(self.lastwords) > 5:
|
||||
self.lastwords.pop(0)
|
||||
return picked
|
||||
|
||||
|
||||
def scrambleWord(self, word):
|
||||
scrambled = ""
|
||||
for subword in word.split(" "):
|
||||
scrambled+=self.scrambleIndividualWord(subword)+ " "
|
||||
scrambled += self.scrambleIndividualWord(subword) + " "
|
||||
return scrambled.strip()
|
||||
|
||||
|
||||
def scrambleIndividualWord(self, word):
|
||||
scrambled = list(word)
|
||||
random.shuffle(scrambled)
|
||||
|
||||
@@ -7,19 +7,20 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
import time
|
||||
import hashlib
|
||||
|
||||
|
||||
class DogeWallet(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.gotmsg)]
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.gotmsg)]
|
||||
# Load attribute storage
|
||||
self.attr = self.bot.getBestModuleForService("attributes")
|
||||
# Load doge RPC
|
||||
self.doge = self.bot.getBestModuleForService("dogerpc")
|
||||
|
||||
|
||||
def gotmsg(self, args, prefix, trailing):
|
||||
channel = args[0]
|
||||
if channel[0] == "#":
|
||||
@@ -27,107 +28,116 @@ class DogeWallet(ModuleBase):
|
||||
pass
|
||||
else:
|
||||
self.handlePm(args, prefix, trailing)
|
||||
|
||||
|
||||
def handlePm(self, args, prefix, trailing):
|
||||
prefix = self.bot.decodePrefix(prefix)
|
||||
cmd = self.bot.messageHasCommand(".setpass", trailing)
|
||||
if cmd:
|
||||
if len(cmd.args)==0:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setpass: usage: \".setpass newpass\" or \".setpass oldpass newpass\"")
|
||||
if len(cmd.args) == 0:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setpass: usage: \".setpass newpass\" or "
|
||||
"\".setpass oldpass newpass\"")
|
||||
else:
|
||||
oldpass = self.attr.getKey(prefix.nick, "password")
|
||||
if oldpass == None:
|
||||
if oldpass is None:
|
||||
self.attr.setKey(prefix.nick, "password", cmd.args[0])
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setpass: Your password has been set to \"%s\"." % cmd.args[0])
|
||||
else:
|
||||
if len(cmd.args)==2:
|
||||
if len(cmd.args) == 2:
|
||||
if cmd.args[0] == oldpass:
|
||||
self.attr.setKey(prefix.nick, "password", cmd.args[1])
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setpass: Your password has been set to \"%s\"." % cmd.args[1])
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setpass: Your password has been set to \"%s\"." %
|
||||
cmd.args[1])
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setpass: Old password incorrect.")
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setpass: You must provide the old password when setting a new one.")
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setpass: You must provide the old password when setting a "
|
||||
"new one.")
|
||||
cmd = self.bot.messageHasCommand(".setdogeaddr", trailing)
|
||||
if cmd:
|
||||
userpw = self.attr.getKey(prefix.nick, "password")
|
||||
if userpw==None:
|
||||
if userpw is None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setdogeaddr: You must first set a password with .setpass")
|
||||
else:
|
||||
if len(cmd.args)==2:
|
||||
if len(cmd.args) == 2:
|
||||
if userpw == cmd.args[0]:
|
||||
self.attr.setKey(prefix.nick, "dogeaddr", cmd.args[1])
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setdogeaddr: Your doge address has been set to \"%s\"." % cmd.args[1])
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setdogeaddr: Your doge address has been set to \"%s\"." %
|
||||
cmd.args[1])
|
||||
# if they don't have a wallet name, we'll make one now
|
||||
if self.attr.getKey(prefix.nick, "dogeaccountname")==None:
|
||||
if self.attr.getKey(prefix.nick, "dogeaccountname") is None:
|
||||
randName = self.md5(str(time.time()))[0:10]
|
||||
self.attr.setKey(prefix.nick, "dogeaccountname", randName)
|
||||
|
||||
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setdogeaddr: incorrect password.")
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setdogeaddr: usage: \".setdogeaddr password address\" or \".setdogeaddr mypassword D8VNy3zkMGspffcFSWWqsxx7GrtVsmF2up\"")
|
||||
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setdogeaddr: usage: \".setdogeaddr password address\" or "
|
||||
"\".setdogeaddr mypassword D8VNy3zkMGspffcFSWWqsxx7GrtVsmF2up\"")
|
||||
|
||||
cmd = self.bot.messageHasCommand(".getdogebal", trailing)
|
||||
if cmd:
|
||||
userpw = self.attr.getKey(prefix.nick, "password")
|
||||
if userpw==None:
|
||||
if userpw is None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getdogebal: You must first set a password with .setpass")
|
||||
else:
|
||||
if len(cmd.args)==1:
|
||||
if len(cmd.args) == 1:
|
||||
if userpw == cmd.args[0]:
|
||||
#################
|
||||
walletname = self.attr.getKey(prefix.nick, "dogeaccountname")
|
||||
amount = 0.0
|
||||
if walletname:
|
||||
amount = self.doge.getBal(walletname)
|
||||
|
||||
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getdogebal: Your balance is: %s DOGE" % amount)
|
||||
|
||||
|
||||
#################
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getdogebal: incorrect password.")
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getdogebal: usage: \".getdogebal password\"")
|
||||
|
||||
|
||||
cmd = self.bot.messageHasCommand(".withdrawdoge", trailing)
|
||||
if cmd:
|
||||
userpw = self.attr.getKey(prefix.nick, "password")
|
||||
useraddr = self.attr.getKey(prefix.nick, "dogeaddr")
|
||||
if userpw==None:
|
||||
if userpw is None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: You must first set a password with .setpass")
|
||||
elif useraddr==None:
|
||||
elif useraddr is None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: You must first set a withdraw address .setdogeaddr")
|
||||
else:
|
||||
if len(cmd.args)==2:
|
||||
if len(cmd.args) == 2:
|
||||
if userpw == cmd.args[0]:
|
||||
#################
|
||||
walletname = self.attr.getKey(prefix.nick, "dogeaccountname")
|
||||
walletbal = self.doge.getBal(walletname)
|
||||
|
||||
|
||||
desiredAmount = float(cmd.args[1])
|
||||
|
||||
|
||||
if walletbal >= desiredAmount:
|
||||
txn = self.doge.send(walletname, useraddr, desiredAmount)
|
||||
if txn:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: %s DOGE sent to %s. Transaction ID: %s"% (desiredAmount, useraddr, txn))
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: %s DOGE sent to %s. Transaction ID: "
|
||||
"%s" % (desiredAmount, useraddr, txn))
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: Unable to create transaction. Please contact an Operator.")
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: Unable to create transaction. "
|
||||
"Please contact an Operator.")
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: You only have %s DOGE. You cannot withdraw %s DOGE." % (walletbal, desiredAmount))
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: You only have %s DOGE. You cannot "
|
||||
"withdraw %s DOGE." % (walletbal, desiredAmount))
|
||||
#################
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: incorrect password.")
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: usage: \".withdrawdoge password amount\" - \".withdrawdoge mypassword 5.0\" - ")
|
||||
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: usage: \".withdrawdoge password amount\" - "
|
||||
"\".withdrawdoge mypassword 5.0\" - ")
|
||||
|
||||
cmd = self.bot.messageHasCommand(".getdepositaddr", trailing)
|
||||
if cmd:
|
||||
userpw = self.attr.getKey(prefix.nick, "password")
|
||||
if userpw==None:
|
||||
if userpw is None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getdepositaddr: You must first set a password with .setpass")
|
||||
else:
|
||||
if len(cmd.args)==1:
|
||||
if len(cmd.args) == 1:
|
||||
if userpw == cmd.args[0]:
|
||||
#################
|
||||
walletname = self.attr.getKey(prefix.nick, "dogeaccountname")
|
||||
@@ -138,16 +148,14 @@ class DogeWallet(ModuleBase):
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getdepositaddr: incorrect password.")
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".getdepositaddr: usage: \".getdepositaddr password\"")
|
||||
|
||||
|
||||
|
||||
|
||||
cmd = self.bot.messageHasCommand(".login", trailing)
|
||||
if cmd:
|
||||
userpw = self.attr.getKey(prefix.nick, "password")
|
||||
if userpw==None:
|
||||
if userpw is None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".login: You must first set a password with .setpass")
|
||||
else:
|
||||
if len(cmd.args)==1:
|
||||
if len(cmd.args) == 1:
|
||||
if userpw == cmd.args[0]:
|
||||
#################
|
||||
self.attr.setKey(prefix.nick, "loggedinfrom", prefix.hostname)
|
||||
@@ -160,12 +168,12 @@ class DogeWallet(ModuleBase):
|
||||
cmd = self.bot.messageHasCommand(".logout", trailing)
|
||||
if cmd:
|
||||
loggedin = self.attr.getKey(prefix.nick, "loggedinfrom")
|
||||
if loggedin == None:
|
||||
if loggedin is None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".logout: You must first be logged in")
|
||||
else:
|
||||
self.attr.setKey(prefix.nick, "loggedinfrom", None)
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".logout: You have been logged out.")
|
||||
|
||||
|
||||
def md5(self, data):
|
||||
m = hashlib.md5()
|
||||
m.update(data.encode("ascii"))
|
||||
|
||||
@@ -7,36 +7,36 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
import time
|
||||
import json
|
||||
import random
|
||||
from threading import Timer
|
||||
import os
|
||||
|
||||
|
||||
class DuckHunt(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.hunt)]
|
||||
self.loadConfig()
|
||||
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.hunt)]
|
||||
|
||||
self.jsonPath = self.getFilePath("scores.json")
|
||||
|
||||
|
||||
self.timer = None
|
||||
self.isDuckOut = False
|
||||
self.outStart = 0
|
||||
self.misses = {}
|
||||
|
||||
|
||||
self.startHunt()
|
||||
|
||||
|
||||
def hunt(self, args, prefix, trailing):
|
||||
prefixObj = self.bot.decodePrefix(prefix)
|
||||
fromWho = prefixObj.nick
|
||||
|
||||
|
||||
cmd = self.bot.messageHasCommand("!huntscore", trailing, False)
|
||||
if cmd:
|
||||
scores = self.loadScores()
|
||||
if not fromWho in scores:
|
||||
if fromWho not in scores:
|
||||
self.bot.act_PRIVMSG(fromWho, "You have no points :(")
|
||||
else:
|
||||
scores = scores[fromWho]
|
||||
@@ -48,121 +48,123 @@ class DuckHunt(ModuleBase):
|
||||
misses = 0
|
||||
for kill in scores:
|
||||
if kill["prime"]:
|
||||
prime+=1
|
||||
prime += 1
|
||||
if kill["runt"]:
|
||||
runts+=1
|
||||
kills+=1
|
||||
weight+=kill["weight"]
|
||||
shots+=1
|
||||
shots+=kill["misses"]
|
||||
misses+=kill["misses"]
|
||||
|
||||
self.bot.act_PRIVMSG(fromWho, "You've shot %s %s for a total weight of %s lbs." % (kills, self.config["animalSpeciesPlural"], weight))
|
||||
self.bot.act_PRIVMSG(fromWho, "%s prime catches, %s runts, %s bullets used and %s misses." % (prime, runts, shots, misses))
|
||||
#self.bot.act_PRIVMSG(fromWho, "More info & highscores: http://duckhunt.xmopx.net/")
|
||||
runts += 1
|
||||
kills += 1
|
||||
weight += kill["weight"]
|
||||
shots += 1
|
||||
shots += kill["misses"]
|
||||
misses += kill["misses"]
|
||||
|
||||
self.bot.act_PRIVMSG(fromWho, "You've shot %s %s for a total weight of %s lbs." %
|
||||
(kills, self.config["animalSpeciesPlural"], weight))
|
||||
self.bot.act_PRIVMSG(fromWho, "%s prime catches, %s runts, %s bullets used and %s misses." %
|
||||
(prime, runts, shots, misses))
|
||||
# self.bot.act_PRIVMSG(fromWho, "More info & highscores: http://duckhunt.xmopx.net/")
|
||||
self.log.info("DuckHunt: %s used !huntscore" % fromWho)
|
||||
return
|
||||
|
||||
|
||||
# Channel only
|
||||
if not args[0][0]=="#":
|
||||
if not args[0][0] == "#":
|
||||
return
|
||||
|
||||
|
||||
cmd = self.bot.messageHasCommand("!shoot", trailing, False)
|
||||
if cmd:
|
||||
if self.isDuckOut:
|
||||
|
||||
if not fromWho in self.misses:
|
||||
self.misses[fromWho]=0
|
||||
|
||||
|
||||
if fromWho not in self.misses:
|
||||
self.misses[fromWho] = 0
|
||||
|
||||
shotIn = round(time.time() - self.outStart, 2)
|
||||
|
||||
|
||||
if random.randint(0, 100) <= self.config["missChance"]:
|
||||
self.bot.act_PRIVMSG(self.config["activeChannel"], "%s fires after %s seconds and misses!" % (fromWho, shotIn))
|
||||
self.misses[fromWho]+=1
|
||||
self.bot.act_PRIVMSG(self.config["activeChannel"], "%s fires after %s seconds and misses!" %
|
||||
(fromWho, shotIn))
|
||||
self.misses[fromWho] += 1
|
||||
return
|
||||
|
||||
|
||||
self.isDuckOut = False
|
||||
|
||||
|
||||
bagged = {
|
||||
"species":self.config["animalSpecies"],
|
||||
"gender":"M" if random.randint(0,1)==1 else "F",
|
||||
"time":shotIn,
|
||||
"prime":False,
|
||||
"runt":False,
|
||||
"weight":0.0,
|
||||
"date":time.time(),
|
||||
"misses":self.misses[fromWho]
|
||||
"species": self.config["animalSpecies"],
|
||||
"gender": "M" if random.randint(0, 1) == 1 else "F",
|
||||
"time": shotIn,
|
||||
"prime": False,
|
||||
"runt": False,
|
||||
"weight": 0.0,
|
||||
"date": time.time(),
|
||||
"misses": self.misses[fromWho]
|
||||
}
|
||||
|
||||
|
||||
message = "%s %s " % (fromWho, "bags")
|
||||
|
||||
|
||||
if random.randint(0, 100) <= self.config["primeChance"]:
|
||||
bagged["prime"]=True
|
||||
bagged["weight"]=self.getRandWeight(self.config["weightMax"], self.config["weightFat"])
|
||||
bagged["prime"] = True
|
||||
bagged["weight"] = self.getRandWeight(self.config["weightMax"], self.config["weightFat"])
|
||||
message += "a prime catch, a "
|
||||
elif random.randint(0, 100) <= self.config["runtChance"]:
|
||||
bagged["runt"]=True
|
||||
bagged["weight"]=self.getRandWeight(self.config["weightRunt"], self.config["weightMin"])
|
||||
bagged["runt"] = True
|
||||
bagged["weight"] = self.getRandWeight(self.config["weightRunt"], self.config["weightMin"])
|
||||
message += "a runt of a catch, a "
|
||||
else:
|
||||
bagged["weight"]=self.getRandWeight(self.config["weightMin"], self.config["weightMax"])
|
||||
bagged["weight"] = self.getRandWeight(self.config["weightMin"], self.config["weightMax"])
|
||||
message += "a "
|
||||
|
||||
|
||||
message += "%s lb " % (bagged["weight"])
|
||||
if bagged["gender"]=="M":
|
||||
message += self.config["animalNameMale"]+" "
|
||||
if bagged["gender"] == "M":
|
||||
message += self.config["animalNameMale"] + " "
|
||||
else:
|
||||
message += self.config["animalNameFemale"]+" "
|
||||
|
||||
message += self.config["animalNameFemale"] + " "
|
||||
|
||||
message += "in %s seconds!" % shotIn
|
||||
self.bot.act_PRIVMSG(self.config["activeChannel"], message)
|
||||
|
||||
|
||||
self.addKillFor(fromWho, bagged)
|
||||
|
||||
|
||||
self.misses = {}
|
||||
|
||||
self.startHunt();
|
||||
|
||||
|
||||
|
||||
self.startHunt()
|
||||
|
||||
def startHunt(self):
|
||||
" Creates a timer that waits a certain amount of time then sends out a bird \\_o< quack"
|
||||
delay = self.config["delayMin"] + random.randint(0, self.config["delayMax"]-self.config["delayMin"])
|
||||
delay = self.config["delayMin"] + random.randint(0, self.config["delayMax"] - self.config["delayMin"])
|
||||
self.timer = Timer(delay, self.duckOut)
|
||||
self.timer.start()
|
||||
print("DuckHunt: Sending out animal in %s seconds" % delay)
|
||||
|
||||
|
||||
def duckOut(self):
|
||||
self.isDuckOut = True
|
||||
self.bot.act_PRIVMSG(self.config["activeChannel"], self.config["animal"])
|
||||
self.outStart = time.time()
|
||||
|
||||
|
||||
def getRandWeight(self, minW, maxW):
|
||||
weight = maxW-minW;
|
||||
weight = float(weight)*random.random()
|
||||
return round(weight+minW, 2)
|
||||
|
||||
weight = maxW - minW
|
||||
weight = float(weight) * random.random()
|
||||
return round(weight + minW, 2)
|
||||
|
||||
def getScoreFor(self, playername):
|
||||
return 1
|
||||
|
||||
|
||||
def getScoresFor(self, playername):
|
||||
return 1
|
||||
|
||||
|
||||
def addKillFor(self, playername, kill):
|
||||
scores = self.loadScores()
|
||||
if scores==None:
|
||||
if scores is None:
|
||||
scores = {}
|
||||
if not playername in scores:
|
||||
scores[playername]=[]
|
||||
if playername not in scores:
|
||||
scores[playername] = []
|
||||
scores[playername].append(kill)
|
||||
self.saveScores(scores)
|
||||
|
||||
|
||||
def loadScores(self):
|
||||
if not os.path.exists(self.jsonPath):
|
||||
json.dump({}, open(self.jsonPath, 'w'))
|
||||
return json.load(open(self.jsonPath, 'r'))
|
||||
|
||||
|
||||
def saveScores(self, scores):
|
||||
json.dump(scores, open(self.jsonPath, 'w'))
|
||||
|
||||
|
||||
def ondisable(self):
|
||||
self.timer.cancel()
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
"""
|
||||
.. module:: Error
|
||||
:synopsis: Module to deliberately cause an error for testing handling.
|
||||
@@ -6,17 +7,17 @@
|
||||
|
||||
"""
|
||||
|
||||
#!/usr/bin/env python
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
|
||||
|
||||
class Error(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.error)]
|
||||
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.error)]
|
||||
|
||||
def error(self, args, prefix, trailing):
|
||||
"""If the message recieved from IRC has the string "error" in it, cause a ZeroDivisionError
|
||||
|
||||
|
||||
:param args: IRC args received
|
||||
:type args: list
|
||||
:param prefix: IRC prefix of sender
|
||||
@@ -24,5 +25,5 @@ class Error(ModuleBase):
|
||||
:param trailing: IRC message body
|
||||
:type trailing: str"""
|
||||
if "error" in trailing:
|
||||
print(10/0)
|
||||
print(10 / 0)
|
||||
|
||||
|
||||
@@ -7,66 +7,64 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
import random
|
||||
import os
|
||||
import time
|
||||
from threading import Timer
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
|
||||
|
||||
class GameBase(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.gotMsg)]
|
||||
self.loadConfig()
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.gotMsg)]
|
||||
# Load attribute storage
|
||||
self.attr = self.bot.getBestModuleForService("attributes")
|
||||
# Load doge RPC
|
||||
self.doge = self.bot.getBestModuleForService("dogerpc")
|
||||
# Dict of #channel -> game object
|
||||
self.games = {}
|
||||
|
||||
|
||||
def gotMsg(self, args, prefix, trailing):
|
||||
prefixObj = self.bot.decodePrefix(prefix)
|
||||
# Ignore messages from users not logged in
|
||||
if self.attr.getKey(prefixObj.nick, "loggedinfrom")==None:
|
||||
# Send them a hint?
|
||||
if not self.attr.getKey(prefixObj.nick, "loggedinfrom"):
|
||||
# TODO Send them a hint?
|
||||
return
|
||||
else:
|
||||
if args[0][0] == "#":
|
||||
# create a blank game obj if there isn't one (and whitelisted ? )
|
||||
if not args[0] in self.games and (not self.config["channelWhitelistOn"] or (self.config["channelWhitelistOn"] and args[0][1:] in self.config["channelWhitelist"]) ):
|
||||
self.games[args[0]]=gameObj(self, args[0])
|
||||
if not args[0] in self.games and (not self.config["channelWhitelistOn"] or
|
||||
(self.config["channelWhitelistOn"] and args[0][1:] in self.config["channelWhitelist"])):
|
||||
self.games[args[0]] = gameObj(self, args[0])
|
||||
# Channel message
|
||||
self.games[args[0]].gotMsg(args, prefix, trailing)
|
||||
else:
|
||||
# Private message
|
||||
#self.games[args[0]].gotPrivMsg(args, prefix, trailing)
|
||||
# self.games[args[0]].gotPrivMsg(args, prefix, trailing)
|
||||
pass
|
||||
|
||||
|
||||
def ondisable(self):
|
||||
self.log.info("GameBase: Unload requested, ending games...")
|
||||
for game in self.games:
|
||||
self.games[game].gameover()
|
||||
|
||||
|
||||
class gameObj:
|
||||
def __init__(self, master, channel):
|
||||
self.master = master
|
||||
self.channel = channel
|
||||
|
||||
|
||||
def gotPrivMsg(self, args, prefix, trailing):
|
||||
prefix = self.master.bot.decodePrefix(prefix)
|
||||
pass
|
||||
|
||||
|
||||
def gotMsg(self, args, prefix, trailing):
|
||||
prefix = self.master.bot.decodePrefix(prefix)
|
||||
pass
|
||||
|
||||
#senderIsOp = self.master.attr.getKey(prefix.nick, "op")=="yes"
|
||||
|
||||
# senderIsOp = self.master.attr.getKey(prefix.nick, "op")=="yes"
|
||||
def gameover(self):
|
||||
pass
|
||||
|
||||
|
||||
class playerObj:
|
||||
def __init__(self, game, nick):
|
||||
self.game = game
|
||||
self.nick = nick
|
||||
|
||||
|
||||
@@ -7,21 +7,22 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class Inventory(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[]
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = []
|
||||
self.db = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("sqlite")
|
||||
if len(serviceProviders)==0:
|
||||
if not serviceProviders:
|
||||
self.log.error("Inventory: Could not find a valid sqlite service provider")
|
||||
else:
|
||||
self.log.info("Inventory: Selecting sqlite service provider: %s" % serviceProviders[0])
|
||||
self.db = serviceProviders[0].opendb("inventory.db")
|
||||
|
||||
|
||||
if not self.db.tableExists("inventory"):
|
||||
self.log.info("Inventory: Creating table: inventory")
|
||||
c = self.db.query("""CREATE TABLE IF NOT EXISTS `inventory` (
|
||||
@@ -31,77 +32,76 @@ class Inventory(ModuleBase):
|
||||
`item` varchar(64)
|
||||
) ;""")
|
||||
c.close()
|
||||
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.checkInv)]
|
||||
|
||||
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.checkInv)]
|
||||
|
||||
def checkInv(self, args, prefix, trailing):
|
||||
if not args[0][0]=="#":
|
||||
if not args[0][0] == "#":
|
||||
return
|
||||
prefixObj = self.bot.decodePrefix(prefix)
|
||||
cmd = self.bot.messageHasCommand([".have"], trailing, True)
|
||||
if cmd:
|
||||
if len(cmd.args)<1:
|
||||
if len(cmd.args) < 1:
|
||||
return
|
||||
adjective = None
|
||||
if cmd.args[0] in self.config["adjectives"]:
|
||||
cmd.args_str = cmd.args_str[len(cmd.args[0]):].strip()
|
||||
adjective = cmd.args[0]
|
||||
newItem = cmd.args_str
|
||||
|
||||
|
||||
if self.has_item(newItem):
|
||||
self.bot.act_PRIVMSG(args[0], self.config["dupe_msg"] %
|
||||
{"item":newItem,})
|
||||
self.bot.act_PRIVMSG(args[0], self.config["dupe_msg"] % {"item": newItem})
|
||||
return
|
||||
|
||||
|
||||
dropped = self.add_item(prefixObj.nick, newItem)
|
||||
if len(dropped) > 0:
|
||||
self.bot.act_PRIVMSG(args[0], self.config["swap_msg"] %
|
||||
{"adjective":(adjective+" ") if adjective else "", "recv_item":newItem, "drop_item":", ".join(dropped)})
|
||||
self.bot.act_PRIVMSG(args[0], self.config["swap_msg"] %
|
||||
{"adjective": (adjective + " ") if adjective else "",
|
||||
"recv_item": newItem, "drop_item": ", ".join(dropped)})
|
||||
else:
|
||||
self.bot.act_PRIVMSG(args[0], self.config["recv_msg"] %
|
||||
{"item":newItem, "adjective":"these " if newItem[-1:]=="s" else "this "})
|
||||
|
||||
self.bot.act_PRIVMSG(args[0], self.config["recv_msg"] %
|
||||
{"item": newItem, "adjective": "these " if newItem[-1:] == "s" else "this "})
|
||||
|
||||
cmd = self.bot.messageHasCommand([".inventory", ".inv"], trailing)
|
||||
if cmd:
|
||||
inv = self.getinventory()
|
||||
if len(inv)==0:
|
||||
self.bot.act_PRIVMSG(args[0], self.config["inv_msg"] % {"itemlist":"nothing!"})
|
||||
if len(inv) == 0:
|
||||
self.bot.act_PRIVMSG(args[0], self.config["inv_msg"] % {"itemlist": "nothing!"})
|
||||
else:
|
||||
self.bot.act_PRIVMSG(args[0], self.config["inv_msg"] % {"itemlist":", ".join(inv)})
|
||||
|
||||
|
||||
self.bot.act_PRIVMSG(args[0], self.config["inv_msg"] % {"itemlist": ", ".join(inv)})
|
||||
|
||||
def has_item(self, itemName):
|
||||
c = self.db.query("SELECT COUNT(*) as `num` FROM `inventory` WHERE `item`=? COLLATE NOCASE", (itemName,)) #
|
||||
c = self.db.query("SELECT COUNT(*) as `num` FROM `inventory` WHERE `item`=? COLLATE NOCASE", (itemName,))
|
||||
row = c.fetchone()
|
||||
c.close()
|
||||
return row["num"]>0
|
||||
|
||||
return row["num"] > 0
|
||||
|
||||
def add_item(self, donor, itemName):
|
||||
dropped = []
|
||||
c = self.db.query("SELECT * FROM `inventory` ORDER BY RANDOM() LIMIT %s,1000000" % self.config["limit"])
|
||||
while True:
|
||||
row = c.fetchone()
|
||||
if row == None:
|
||||
if row is None:
|
||||
break
|
||||
dropped.append(row["item"])
|
||||
self.db.query("DELETE FROM `inventory` WHERE `id`=?", (row["id"],)).close()
|
||||
c.close()
|
||||
|
||||
|
||||
self.db.query("INSERT INTO `inventory` (`date`, `donor`, `item`) VALUES (?, ?, ?)",
|
||||
(int(datetime.now().timestamp()), donor, itemName)).close()
|
||||
(int(datetime.now().timestamp()), donor, itemName)).close()
|
||||
return dropped
|
||||
|
||||
|
||||
def getinventory(self):
|
||||
inv = []
|
||||
c = self.db.query("SELECT * FROM `inventory`")
|
||||
while True:
|
||||
row = c.fetchone()
|
||||
if row == None:
|
||||
if row is None:
|
||||
break
|
||||
inv.append(row["item"])
|
||||
c.close()
|
||||
return inv
|
||||
|
||||
|
||||
def ondisable(self):
|
||||
self.db.close()
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
|
||||
BASE_URL = "http://lmgtfy.com/?q="
|
||||
|
||||
|
||||
class LMGTFY(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
@@ -24,7 +25,7 @@ class LMGTFY(ModuleBase):
|
||||
message = trailing.split(" ")[1:]
|
||||
link = self.createLink(message)
|
||||
self.bot.act_PRIVMSG(channel, "%s: %s" % (prefix.nick, link))
|
||||
|
||||
|
||||
def createLink(self, message):
|
||||
finalUrl = BASE_URL
|
||||
if type(message) == str:
|
||||
@@ -33,6 +34,6 @@ class LMGTFY(ModuleBase):
|
||||
for word in message:
|
||||
finalUrl += urllib.parse.quote(word)
|
||||
if word != message[-1]:
|
||||
finalUrl+="+"
|
||||
finalUrl += "+"
|
||||
|
||||
return finalUrl
|
||||
|
||||
@@ -7,90 +7,93 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
from requests import get
|
||||
import re
|
||||
import time
|
||||
import praw #TODO: enable/disable modules
|
||||
import praw # TODO: enable/disable modules
|
||||
import datetime
|
||||
from requests import get,head
|
||||
from requests import head
|
||||
import html.parser
|
||||
from threading import Thread
|
||||
|
||||
|
||||
class LinkTitler(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.REQUEST_SIZE_LIMIT = 10*1024
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.searches)]
|
||||
|
||||
self.REQUEST_SIZE_LIMIT = 10 * 1024
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.searches)]
|
||||
|
||||
def searches(self, args, prefix, trailing):
|
||||
t = Thread(target=self.doLinkTitle, args=(args, prefix, trailing))
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
|
||||
def doLinkTitle(self, args, prefix, trailing):
|
||||
sender = self.bot.decodePrefix(prefix)
|
||||
|
||||
|
||||
# Youtube
|
||||
matches = re.compile(r'(?:youtube.*?(?:v=|/v/)|youtu\.be/|yooouuutuuube.*?id=)([-_a-z0-9]+)', re.I).findall(trailing)
|
||||
if len(matches)>0:
|
||||
matches = re.compile(r'(?:youtube.*?(?:v=|/v/)|youtu\.be/|yooouuutuuube.*?id=)([-_a-z0-9]+)', re.I) \
|
||||
.findall(trailing)
|
||||
if matches:
|
||||
done = []
|
||||
for item in matches:
|
||||
if not item in done:
|
||||
vidinfo = self.get_video_description(item)
|
||||
if item not in done:
|
||||
vidinfo = self.get_video_description(item)
|
||||
if vidinfo:
|
||||
self.bot.act_PRIVMSG(args[0], vidinfo)
|
||||
done.append(item)
|
||||
return
|
||||
|
||||
|
||||
# reddit threads
|
||||
matches = re.compile(r'(?:reddit\.com/.*?comments/([a-zA-Z0-9]+)/|https?://(www\.)?redd.it/([a-zA-Z0-9]+))').findall(trailing)
|
||||
matches = re.compile(r'(?:reddit\.com/.*?comments/([a-zA-Z0-9]+)/|https?://(www\.)?redd.it/([a-zA-Z0-9]+))') \
|
||||
.findall(trailing)
|
||||
# Either [('', '', '2ibrz7')] or [('2ibrz7', '', '')]
|
||||
if len(matches)>0:
|
||||
if matches:
|
||||
done = []
|
||||
for match in matches:
|
||||
submissionId = match[0]
|
||||
if submissionId=="":
|
||||
if submissionId == "":
|
||||
submissionId = match[-1]
|
||||
if submissionId in done:
|
||||
continue
|
||||
done.append(submissionId)
|
||||
# TODO configurable user agent
|
||||
r = praw.Reddit(self.config["agent"])
|
||||
submission = r.get_submission(submission_id = submissionId)
|
||||
#for i in range(0,18):
|
||||
# self.bot.act_PRIVMSG(args[0], "\x031,%sTEST%s\x0f" %(i,i))
|
||||
msg = "👽 \x02\x031,15REDDIT\x0f\x02 :: %(title)s \x02on \x02%(domain)s%(nsfw)s\x02 - points \x02%(points)s\x02 (%(percent)s↑) - comments \x02%(comments)s\x02 - by \x02%(author)s\x02 on \x02%(date)s\x02" % {
|
||||
"title":submission.title,
|
||||
"domain":submission.domain,
|
||||
"nsfw": "[NSFW]" if submission.over_18 else "",
|
||||
"points":submission.ups,
|
||||
"percent":"%s%%" % int(submission.upvote_ratio*100),
|
||||
"comments":submission.num_comments,
|
||||
"author":submission.author.name,
|
||||
"date":datetime.datetime.fromtimestamp(submission.created).strftime("%Y.%m.%d")
|
||||
}
|
||||
submission = r.get_submission(submission_id=submissionId)
|
||||
msg = "👽 \x02\x031,15REDDIT\x0f\x02 :: %(title)s \x02on \x02%(domain)s%(nsfw)s\x02 - points " \
|
||||
"\x02%(points)s\x02 (%(percent)s↑) - comments \x02%(comments)s\x02 - by \x02%(author)s\x02 on " \
|
||||
"\x02%(date)s\x02" % {
|
||||
"title": submission.title,
|
||||
"domain": submission.domain,
|
||||
"nsfw": "[NSFW]" if submission.over_18 else "",
|
||||
"points": submission.ups,
|
||||
"percent": "%s%%" % int(submission.upvote_ratio *100),
|
||||
"comments": submission.num_comments,
|
||||
"author": submission.author.name,
|
||||
"date": datetime.datetime.fromtimestamp(submission.created).strftime("%Y.%m.%d")
|
||||
}
|
||||
self.bot.act_PRIVMSG(args[0], msg)
|
||||
return
|
||||
# reddit subscribers
|
||||
|
||||
|
||||
# subreddits
|
||||
|
||||
|
||||
# generic <title>
|
||||
matches = re.compile(r'(https?://([a-zA-Z0-9_\-\.]+/([^ ]+)?))').findall(trailing)
|
||||
if len(matches)>0:
|
||||
done=[]
|
||||
if matches:
|
||||
done = []
|
||||
for match in matches:
|
||||
if match[0] in done:
|
||||
continue
|
||||
done.append(match[0])
|
||||
|
||||
|
||||
headers = self.url_headers(match[0])
|
||||
|
||||
|
||||
# Don't mess with unknown content types
|
||||
if not "Content-Type" in headers:
|
||||
if "Content-Type" not in headers:
|
||||
continue
|
||||
|
||||
|
||||
if "text/html" in headers["Content-Type"]:
|
||||
# Fetch HTML title
|
||||
title = self.url_htmltitle(match[0])
|
||||
@@ -98,23 +101,29 @@ class LinkTitler(ModuleBase):
|
||||
self.bot.act_PRIVMSG(args[0], "%s: \x02%s\x02" % (sender.nick, title))
|
||||
else:
|
||||
# Unknown types, just print type and size
|
||||
self.bot.act_PRIVMSG(args[0], "%s: \x02%s\x02, %s" % (sender.nick, headers["Content-Type"], self.nicesize(int(headers["Content-Length"])) if "Content-Length" in headers else "unknown size"))
|
||||
|
||||
self.bot.act_PRIVMSG(args[0], "%s: \x02%s\x02, %s" %
|
||||
(sender.nick, headers["Content-Type"],
|
||||
self.nicesize(int(headers["Content-Length"])) if
|
||||
"Content-Length" in headers else "unknown size"))
|
||||
|
||||
return
|
||||
|
||||
|
||||
def nicesize(self, numBytes):
|
||||
"Return kb or plain bytes"
|
||||
if numBytes > 1024:
|
||||
return "%skb" % str(int(numBytes/1024))
|
||||
return "%skb" % str(int(numBytes / 1024))
|
||||
else:
|
||||
return "<1kb"
|
||||
|
||||
|
||||
def url_headers(self, url):
|
||||
"HEAD requests a url to check content type & length, returns something like: {'type': 'image/jpeg', 'size': '90583'}"
|
||||
"""
|
||||
HEAD requests a url to check content type & length.
|
||||
Returns something like: {'type': 'image/jpeg', 'size': '90583'}"
|
||||
"""
|
||||
self.log.info("url_headers(%s)" % (url,))
|
||||
resp = head(url=url, allow_redirects=True)
|
||||
return resp.headers
|
||||
|
||||
|
||||
def url_htmltitle(self, url):
|
||||
"Requests page html and returns title in a safe way"
|
||||
self.log.info("url_htmltitle(%s)" % (url,))
|
||||
@@ -126,61 +135,63 @@ class LinkTitler(ModuleBase):
|
||||
data += chunk
|
||||
if len(data) > self.REQUEST_SIZE_LIMIT:
|
||||
break
|
||||
|
||||
|
||||
data = data.decode('utf-8', "ignore")
|
||||
|
||||
|
||||
titleMatches = re.findall(r'<title>([^<]+)</title>', data, re.I)
|
||||
if len(titleMatches)>0:# and resp.status_code==200:
|
||||
if len(titleMatches) > 0: # and resp.status_code==200:
|
||||
h = html.parser.HTMLParser()
|
||||
title = h.unescape(titleMatches[0]).strip()
|
||||
if len(title)>0:
|
||||
if len(title) > 0:
|
||||
return title
|
||||
return None
|
||||
|
||||
|
||||
# For youtube
|
||||
def getISOdurationseconds(self, stamp):
|
||||
ISO_8601_period_rx = re.compile(
|
||||
'P' # designates a period
|
||||
'(?:(?P<years>\d+)Y)?' # years
|
||||
'(?:(?P<months>\d+)M)?' # months
|
||||
'(?:(?P<weeks>\d+)W)?' # weeks
|
||||
'(?:(?P<days>\d+)D)?' # days
|
||||
'(?:T' # time part must begin with a T
|
||||
'(?:(?P<hours>\d+)H)?' # hours
|
||||
'(?:(?P<minutes>\d+)M)?' # minutes
|
||||
'(?:(?P<seconds>\d+)S)?' # seconds
|
||||
'P' # designates a period
|
||||
'(?:(?P<years>\d+)Y)?' # years
|
||||
'(?:(?P<months>\d+)M)?' # months
|
||||
'(?:(?P<weeks>\d+)W)?' # weeks
|
||||
'(?:(?P<days>\d+)D)?' # days
|
||||
'(?:T' # time part must begin with a T
|
||||
'(?:(?P<hours>\d+)H)?' # hours
|
||||
'(?:(?P<minutes>\d+)M)?' # minutes
|
||||
'(?:(?P<seconds>\d+)S)?' # seconds
|
||||
')?' # end of time part
|
||||
) # http://stackoverflow.com/a/16742742
|
||||
) # http://stackoverflow.com/a/16742742
|
||||
return ISO_8601_period_rx.match(stamp).groupdict()
|
||||
|
||||
def get_video_description(self, vid_id):
|
||||
apidata = get('https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails,statistics&id=%s&key=%s' % (vid_id, self.config["youtube_api_key"])).json()
|
||||
|
||||
apidata = get('https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails,statistics&id=%s'
|
||||
'&key=%s' % (vid_id, self.config["youtube_api_key"])).json()
|
||||
|
||||
if not apidata['pageInfo']['totalResults']:
|
||||
return
|
||||
|
||||
|
||||
video = apidata['items'][0]
|
||||
snippet = video["snippet"]
|
||||
duration = self.getISOdurationseconds(video["contentDetails"]["duration"])
|
||||
|
||||
|
||||
out = '\x02\x031,0You\x0f\x030,4Tube\x02\x0f :: \x02%s\x02' % snippet["title"]
|
||||
|
||||
|
||||
out += ' - length \x02'
|
||||
if duration["hours"]!=None:
|
||||
if duration["hours"] is not None:
|
||||
out += '%dh ' % int(duration["hours"])
|
||||
if duration["minutes"]!=None:
|
||||
if duration["minutes"] is not None:
|
||||
out += '%dm ' % int(duration["minutes"])
|
||||
if duration["seconds"]!=None:
|
||||
if duration["seconds"] is not None:
|
||||
out += "%ds\x02" % int(duration["seconds"])
|
||||
|
||||
totalvotes = float(video["statistics"]["dislikeCount"])+float(video["statistics"]["likeCount"])
|
||||
|
||||
totalvotes = float(video["statistics"]["dislikeCount"]) + float(video["statistics"]["likeCount"])
|
||||
rating = float(video["statistics"]["likeCount"]) / totalvotes
|
||||
out += ' - rated \x02%.2f/5\x02' % round(rating*5,1)
|
||||
out += ' - rated \x02%.2f/5\x02' % round(rating * 5, 1)
|
||||
out += ' - \x02%s\x02 views' % self.group_int_digits(video["statistics"]["viewCount"])
|
||||
upload_time = time.strptime(snippet['publishedAt'], "%Y-%m-%dT%H:%M:%S.000Z")
|
||||
out += ' - by \x02%s\x02 on \x02%s\x02' % (snippet['channelTitle'], time.strftime("%Y.%m.%d", upload_time))
|
||||
|
||||
|
||||
return out
|
||||
|
||||
|
||||
def group_int_digits(self, number, delimiter=',', grouping=3):
|
||||
base = str(number).strip()
|
||||
builder = []
|
||||
|
||||
@@ -7,79 +7,79 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase
|
||||
import sys
|
||||
|
||||
try:
|
||||
import MySQLdb #python 2.x
|
||||
import MySQLdb # python 2.x
|
||||
except:
|
||||
import pymysql as MySQLdb #python 3.x
|
||||
import pymysql as MySQLdb # python 3.x
|
||||
|
||||
|
||||
class MySQL(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[]
|
||||
self.services=["mysql"]
|
||||
self.loadConfig()
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = []
|
||||
self.services = ["mysql"]
|
||||
self.connection = self.getConnection()
|
||||
|
||||
|
||||
def getConnection(self):
|
||||
return Connection(self)
|
||||
|
||||
|
||||
|
||||
class Connection:
|
||||
def __init__(self, master):
|
||||
self.config = master.config
|
||||
self.log = master.log
|
||||
self._connect()
|
||||
|
||||
|
||||
# Check if the table requested exists
|
||||
def tableExists(self, tablename):
|
||||
c = self.getCursor()
|
||||
c.execute("SHOW TABLES;")
|
||||
tables = c.fetchall()
|
||||
if len(tables)==0:
|
||||
return False;
|
||||
if len(tables) == 0:
|
||||
return False
|
||||
key = list(tables[0].keys())[0]
|
||||
for table in tables:
|
||||
if table[key]==tablename:
|
||||
return True;
|
||||
if table[key] == tablename:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def query(self, queryText, args=()):
|
||||
"""Execute a MySQL query and return the cursor
|
||||
|
||||
|
||||
:param queryText: the mysql query as a string, using '%s' for token replacement
|
||||
:type queryText: str
|
||||
:param args: arguments to be escaped into the query
|
||||
:type args: tuple
|
||||
:returns: cursor -- the sql cursor"""
|
||||
c = self.getCursor()
|
||||
if len(args)==0:
|
||||
if len(args) == 0:
|
||||
c.execute(queryText)
|
||||
else:
|
||||
c.execute(queryText, args)
|
||||
return c
|
||||
|
||||
|
||||
# Returns a cusor object, after checking for connectivity
|
||||
def getCursor(self):
|
||||
self.ensureConnected()
|
||||
if sys.version_info > (3,0):
|
||||
if sys.version_info > (3, 0):
|
||||
c = self.connection.cursor(MySQLdb.cursors.DictCursor)
|
||||
else:
|
||||
c = self.connection.cursor(cursorclass=MySQLdb.cursors.DictCursor)
|
||||
c.execute("USE `%s`;" % self.config["database"])
|
||||
return c
|
||||
|
||||
|
||||
def escape(self, s):
|
||||
"""Escape a string using the mysql server
|
||||
|
||||
|
||||
:param s: the string to escape
|
||||
:type s: str
|
||||
:returns: str -- the escaped string"""
|
||||
self.ensureConnected()
|
||||
return self.connection.escape_string(s)
|
||||
|
||||
|
||||
def ensureConnected(self):
|
||||
try:
|
||||
self.connection.ping()
|
||||
@@ -90,27 +90,28 @@ class Connection:
|
||||
pass
|
||||
del self.connection
|
||||
self._connect()
|
||||
|
||||
|
||||
def ondisable(self):
|
||||
self.connection.close()
|
||||
|
||||
|
||||
# Connects to the database server, and selects a database (Or attempts to create it if it doesn't exist yet)
|
||||
def _connect(self):
|
||||
self.log.info("MySQL: Connecting to db host at %s" % self.config["host"])
|
||||
self.connection = MySQLdb.connect(host=self.config["host"],user=self.config["username"] ,passwd=self.config["password"])
|
||||
self.connection = MySQLdb.connect(host=self.config["host"], user=self.config["username"],
|
||||
passwd=self.config["password"])
|
||||
self.log.info("MySQL: Connected.")
|
||||
self.connection.autocommit(True)
|
||||
c = None
|
||||
if sys.version_info > (3,0):
|
||||
if sys.version_info > (3, 0):
|
||||
c = self.connection.cursor(MySQLdb.cursors.DictCursor)
|
||||
else:
|
||||
c = self.connection.cursor(cursorclass=MySQLdb.cursors.DictCursor)
|
||||
|
||||
|
||||
c.execute("SHOW DATABASES")
|
||||
dblist = c.fetchall()
|
||||
found = False
|
||||
for row in dblist:
|
||||
if row["Database"]==self.config["database"]:
|
||||
if row["Database"] == self.config["database"]:
|
||||
found = True
|
||||
if not found:
|
||||
c.execute("CREATE DATABASE `%s`;" % self.config["database"])
|
||||
|
||||
@@ -6,90 +6,91 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
from time import time
|
||||
from requests import get
|
||||
from lxml import etree
|
||||
from datetime import datetime,timedelta
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
class NFLLive(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.cache = None
|
||||
self.cacheAge=0
|
||||
|
||||
self.hooks=[ModuleHook(["PRIVMSG"], self.nflitup)]
|
||||
|
||||
self.cacheAge = 0
|
||||
|
||||
self.hooks = [ModuleHook(["PRIVMSG"], self.nflitup)]
|
||||
|
||||
def nflitup(self, args, prefix, trailing):
|
||||
prefix = self.bot.decodePrefix(prefix)
|
||||
replyTo = prefixObj.nick if not "#" in args[0] else args[0]
|
||||
|
||||
replyTo = prefix.nick if "#" not in args[0] else args[0]
|
||||
|
||||
cmd = self.bot.messageHasCommand(".nfl", trailing)
|
||||
if cmd:
|
||||
games = self.getNflGamesCached()
|
||||
msg = []
|
||||
|
||||
|
||||
liveGames = []
|
||||
gamesLaterToday = []
|
||||
gamesToday = []
|
||||
gamesUpcoming = []
|
||||
gamesEarlierWeek = []
|
||||
|
||||
|
||||
# sort games
|
||||
for game in games["games"]:
|
||||
if not game["time"]==None:
|
||||
if game["time"] is not None:
|
||||
liveGames.append(game)
|
||||
elif game["quarter"]=="P" and game["startdate"].day==datetime.now().day:
|
||||
elif game["quarter"] == "P" and game["startdate"].day == datetime.now().day:
|
||||
gamesLaterToday.append(game)
|
||||
elif game["startdate"].day==datetime.now().day:
|
||||
elif game["startdate"].day == datetime.now().day:
|
||||
gamesToday.append(game)
|
||||
elif game["startdate"].day > datetime.now().day:
|
||||
gamesUpcoming.append(game)
|
||||
else:
|
||||
gamesEarlierWeek.append(game)
|
||||
|
||||
|
||||
# create list of formatted games
|
||||
liveGamesStr = []
|
||||
for game in liveGames:
|
||||
liveGamesStr.append(self.formatGameLive(game))
|
||||
liveGamesStr = ", ".join(liveGamesStr)
|
||||
|
||||
|
||||
gamesLaterTodayStr = []
|
||||
for game in gamesLaterToday:
|
||||
gamesLaterTodayStr.append(self.formatGameFuture(game))
|
||||
gamesLaterTodayStr = ", ".join(gamesLaterTodayStr)
|
||||
|
||||
|
||||
gamesTodayStr = []
|
||||
for game in gamesToday:
|
||||
gamesTodayStr.append(self.formatGamePast(game))
|
||||
gamesTodayStr = ", ".join(gamesTodayStr)
|
||||
|
||||
|
||||
gamesUpcomingStr = []
|
||||
for game in gamesUpcoming:
|
||||
gamesUpcomingStr.append(self.formatGameFuture(game))
|
||||
gamesUpcomingStr = ", ".join(gamesUpcomingStr)
|
||||
|
||||
|
||||
gamesEarlierWeekStr = []
|
||||
for game in gamesEarlierWeek:
|
||||
gamesEarlierWeekStr.append(self.formatGamePast(game))
|
||||
gamesEarlierWeekStr = ", ".join(gamesEarlierWeekStr)
|
||||
|
||||
|
||||
msgPieces = []
|
||||
|
||||
|
||||
msgPieces.append("\x02NFL week %s\x02:" % (games["season"]["week"]))
|
||||
|
||||
|
||||
# Depending on args build the respon pieces
|
||||
if len(cmd.args)>0 and cmd.args[0]=="today":
|
||||
if len(cmd.args) > 0 and cmd.args[0] == "today":
|
||||
if not liveGamesStr == "":
|
||||
msgPieces.append("\x02Playing now:\x02 %s" % liveGamesStr)
|
||||
if not gamesLaterTodayStr == "":
|
||||
msgPieces.append("\x02Later today:\x02 %s" % gamesLaterTodayStr)
|
||||
if not gamesTodayStr == "":
|
||||
msgPieces.append("\x02Earlier today:\x02 %s" % gamesTodayStr)
|
||||
elif len(cmd.args)>0 and cmd.args[0]=="live":
|
||||
elif len(cmd.args) > 0 and cmd.args[0] == "live":
|
||||
if not liveGamesStr == "":
|
||||
msgPieces.append("\x02Playing now:\x02 %s" % liveGamesStr)
|
||||
elif len(cmd.args)>0 and cmd.args[0]=="scores":
|
||||
elif len(cmd.args) > 0 and cmd.args[0] == "scores":
|
||||
if not liveGamesStr == "":
|
||||
msgPieces.append("\x02Playing now:\x02 %s" % liveGamesStr)
|
||||
if not gamesTodayStr == "":
|
||||
@@ -107,28 +108,28 @@ class NFLLive(ModuleBase):
|
||||
msgPieces.append("\x02Earlier this week: \x02 %s" % gamesEarlierWeekStr)
|
||||
if not gamesUpcomingStr == "":
|
||||
msgPieces.append("\x02Upcoming:\x02 %s" % gamesUpcomingStr)
|
||||
|
||||
|
||||
# Collaspe the list into a repsonse string. Fix grammar
|
||||
msg = ", ".join(msgPieces).replace(":, ", ": ")
|
||||
|
||||
|
||||
# Nothing means there were probably no games
|
||||
if len(msgPieces)==1:
|
||||
if len(msgPieces) == 1:
|
||||
msg = "No games!"
|
||||
|
||||
if len(msg)>0:
|
||||
|
||||
if len(msg) > 0:
|
||||
# The message can be long so chunk it into pieces splitting at commas
|
||||
while len(msg)>0:
|
||||
while len(msg) > 0:
|
||||
piece = msg[0:330]
|
||||
msg = msg[330:]
|
||||
while not piece[-1:]=="," and len(msg)>0:
|
||||
piece+=msg[0:1]
|
||||
while not piece[-1:] == "," and len(msg) > 0:
|
||||
piece += msg[0:1]
|
||||
msg = msg[1:]
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: %s" % (prefix.nick, piece.strip()))
|
||||
|
||||
|
||||
def formatGameLive(self, game):
|
||||
c_vis = 3 if int(game["visitor_score"]) > int(game["home_score"]) else 4
|
||||
c_home = 4 if int(game["visitor_score"]) > int(game["home_score"]) else 3
|
||||
|
||||
|
||||
return "\x03%s%s(%s)\x03 @ \x03%s%s(%s)\x03 Q%s %s" % (
|
||||
c_vis,
|
||||
game["visitor"],
|
||||
@@ -139,17 +140,17 @@ class NFLLive(ModuleBase):
|
||||
game["quarter"],
|
||||
game["time"]
|
||||
)
|
||||
|
||||
|
||||
def formatGameFuture(self, game):
|
||||
return "\x02%s\x02@\x02%s\x02" % (
|
||||
game["visitor"],
|
||||
game["home"]
|
||||
)
|
||||
|
||||
|
||||
def formatGamePast(self, game):
|
||||
c_vis = 3 if int(game["visitor_score"]) > int(game["home_score"]) else 4
|
||||
c_home = 4 if int(game["visitor_score"]) > int(game["home_score"]) else 3
|
||||
|
||||
|
||||
return "\x03%s%s(%s)\x03@\x03%s%s(%s)\x03" % (
|
||||
c_vis,
|
||||
game["visitor"],
|
||||
@@ -158,68 +159,70 @@ class NFLLive(ModuleBase):
|
||||
game["home"],
|
||||
game["home_score"]
|
||||
)
|
||||
|
||||
|
||||
def getNflGamesCached(self):
|
||||
if time()-self.cacheAge > self.config["cache"]:
|
||||
if time() - self.cacheAge > self.config["cache"]:
|
||||
self.cache = NFLLive.getNflGames()
|
||||
self.cacheAge = time()
|
||||
return self.cache
|
||||
|
||||
|
||||
@staticmethod
|
||||
def getNflGames():
|
||||
result = {}
|
||||
|
||||
|
||||
# Fetch NFL information as XML
|
||||
nflxml = get("http://www.nfl.com/liveupdate/scorestrip/ss.xml?random=1413140448433")
|
||||
doc = etree.fromstring(nflxml.content)
|
||||
games = doc.xpath("/ss/gms")[0]
|
||||
|
||||
result["season"]={
|
||||
"week":games.attrib["w"],
|
||||
"year":games.attrib["y"],
|
||||
"type":NFLLive.translateSeasonType(games.attrib["t"]), # R for regular season, probably P for pre (?)
|
||||
"gameday":int(games.attrib["gd"]), # 1 or 0 for gameday or not (?)
|
||||
"bph":games.attrib["bph"] # not sure
|
||||
|
||||
result["season"] = {
|
||||
"week": games.attrib["w"],
|
||||
"year": games.attrib["y"],
|
||||
"type": NFLLive.translateSeasonType(games.attrib["t"]), # R for regular season, probably P for pre (?)
|
||||
"gameday": int(games.attrib["gd"]), # 1 or 0 for gameday or not (?)
|
||||
"bph": games.attrib["bph"] # not sure
|
||||
}
|
||||
result["games"]=[]
|
||||
|
||||
result["games"] = []
|
||||
|
||||
for game in games.getchildren():
|
||||
gameblob = {
|
||||
"home":game.attrib["h"],
|
||||
"home_name":game.attrib["hnn"],
|
||||
"home_score":game.attrib["hs"],
|
||||
|
||||
"visitor":game.attrib["v"],
|
||||
"visitor_name":game.attrib["vnn"],
|
||||
"visitor_score":game.attrib["vs"],
|
||||
|
||||
"gametype":game.attrib["gt"], # REGular season, probably P for preseason (?)
|
||||
"quarter":game.attrib["q"], # P if not started, 1-4, F is finished
|
||||
"time":game.attrib["k"] if "k" in game.attrib else None,
|
||||
"id":game.attrib["eid"],
|
||||
"gamenum":game.attrib["gsis"],
|
||||
|
||||
"starttime":game.attrib["t"],
|
||||
"startdate":datetime.strptime(game.attrib["eid"][0:-2]+" "+game.attrib["t"], "%Y%m%d %I:%M")+timedelta(hours=12) # NHL provides a 12 hour EST clock with all times PM. Add 12 hours so the datetime obj is PM instead of AM.
|
||||
"home": game.attrib["h"],
|
||||
"home_name": game.attrib["hnn"],
|
||||
"home_score": game.attrib["hs"],
|
||||
|
||||
"visitor": game.attrib["v"],
|
||||
"visitor_name": game.attrib["vnn"],
|
||||
"visitor_score": game.attrib["vs"],
|
||||
|
||||
"gametype": game.attrib["gt"], # REGular season, probably P for preseason (?)
|
||||
"quarter": game.attrib["q"], # P if not started, 1-4, F is finished
|
||||
"time": game.attrib["k"] if "k" in game.attrib else None,
|
||||
"id": game.attrib["eid"],
|
||||
"gamenum": game.attrib["gsis"],
|
||||
|
||||
"starttime": game.attrib["t"],
|
||||
"startdate": datetime.strptime(game.attrib["eid"][0:-2] + " " + game.attrib["t"], "%Y%m%d %I:%M") + \
|
||||
timedelta(hours=12) # NHL provides a 12 hour EST clock with all times PM.
|
||||
# Add 12 hours so the datetime obj is PM instead of AM.
|
||||
}
|
||||
|
||||
|
||||
# Add 4 more hours to make it GMT
|
||||
gameblob["startdate_gmt"]=gameblob["startdate"]+timedelta(hours=4)
|
||||
gameblob["nfl_link"]="http://www.nfl.com/gamecenter/%s/%s/%s%s/%s@%s" % (
|
||||
gameblob["startdate_gmt"] = gameblob["startdate"] + timedelta(hours=4)
|
||||
gameblob["nfl_link"] = "http://www.nfl.com/gamecenter/%s/%s/%s%s/%s@%s" % (
|
||||
gameblob["id"],
|
||||
result["season"]["year"],
|
||||
gameblob["gametype"],
|
||||
result["season"]["week"],
|
||||
gameblob["visitor_name"],
|
||||
gameblob["home_name"])
|
||||
|
||||
|
||||
result["games"].append(gameblob)
|
||||
return result
|
||||
|
||||
|
||||
@staticmethod
|
||||
def translateSeasonType(season):
|
||||
if season=="R":
|
||||
if season == "R":
|
||||
return "Regular"
|
||||
if season=="P":
|
||||
if season == "P":
|
||||
return "Pre"
|
||||
return season
|
||||
|
||||
@@ -7,27 +7,27 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
import time
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
import hashlib
|
||||
|
||||
|
||||
class NickUser(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.gotmsg)]
|
||||
self.services=["login"]
|
||||
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.gotmsg)]
|
||||
self.services = ["login"]
|
||||
|
||||
def check(self, nick, hostname):
|
||||
attr = self.bot.getBestModuleForService("attributes")
|
||||
loggedin = attr.getKey(nick, "loggedinfrom")
|
||||
if hostname==loggedin:
|
||||
if hostname == loggedin:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def ondisable(self):
|
||||
pass
|
||||
# TODO: log out all users
|
||||
|
||||
|
||||
def gotmsg(self, args, prefix, trailing):
|
||||
channel = args[0]
|
||||
if channel[0] == "#":
|
||||
@@ -35,37 +35,40 @@ class NickUser(ModuleBase):
|
||||
pass
|
||||
else:
|
||||
self.handlePm(args, prefix, trailing)
|
||||
|
||||
|
||||
def handlePm(self, args, prefix, trailing):
|
||||
prefix = self.bot.decodePrefix(prefix)
|
||||
cmd = self.bot.messageHasCommand(".setpass", trailing)
|
||||
if cmd:
|
||||
if len(cmd.args)==0:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setpass: usage: \".setpass newpass\" or \".setpass oldpass newpass\"")
|
||||
if len(cmd.args) == 0:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setpass: usage: \".setpass newpass\" or "
|
||||
"\".setpass oldpass newpass\"")
|
||||
else:
|
||||
attr = self.bot.getBestModuleForService("attributes")
|
||||
oldpass = attr.getKey(prefix.nick, "password")
|
||||
if oldpass == None:
|
||||
if oldpass is None:
|
||||
attr.setKey(prefix.nick, "password", cmd.args[0])
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setpass: Your password has been set to \"%s\"." % cmd.args[0])
|
||||
else:
|
||||
if len(cmd.args)==2:
|
||||
if len(cmd.args) == 2:
|
||||
if cmd.args[0] == oldpass:
|
||||
attr.setKey(prefix.nick, "password", cmd.args[1])
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setpass: Your password has been set to \"%s\"." % cmd.args[1])
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setpass: Your password has been set to \"%s\"." %
|
||||
cmd.args[1])
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setpass: Old password incorrect.")
|
||||
else:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".setpass: You must provide the old password when setting a new one.")
|
||||
|
||||
self.bot.act_PRIVMSG(prefix.nick,
|
||||
".setpass: You must provide the old password when setting a new one.")
|
||||
|
||||
cmd = self.bot.messageHasCommand(".login", trailing)
|
||||
if cmd:
|
||||
attr = self.bot.getBestModuleForService("attributes")
|
||||
userpw = attr.getKey(prefix.nick, "password")
|
||||
if userpw==None:
|
||||
if userpw is None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".login: You must first set a password with .setpass")
|
||||
else:
|
||||
if len(cmd.args)==1:
|
||||
if len(cmd.args) == 1:
|
||||
if userpw == cmd.args[0]:
|
||||
#################
|
||||
attr.setKey(prefix.nick, "loggedinfrom", prefix.hostname)
|
||||
@@ -79,12 +82,12 @@ class NickUser(ModuleBase):
|
||||
if cmd:
|
||||
attr = self.bot.getBestModuleForService("attributes")
|
||||
loggedin = attr.getKey(prefix.nick, "loggedinfrom")
|
||||
if loggedin == None:
|
||||
if loggedin is None:
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".logout: You must first be logged in")
|
||||
else:
|
||||
attr.setKey(prefix.nick, "loggedinfrom", None)
|
||||
self.bot.act_PRIVMSG(prefix.nick, ".logout: You have been logged out.")
|
||||
|
||||
|
||||
def md5(self, data):
|
||||
m = hashlib.md5()
|
||||
m.update(data.encode("ascii"))
|
||||
|
||||
@@ -7,37 +7,34 @@
|
||||
|
||||
"""
|
||||
|
||||
from time import time,sleep
|
||||
from time import time, sleep
|
||||
from threading import Thread
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
|
||||
|
||||
class PingResponder(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.timer = PingRespondTimer(self)
|
||||
self.hooks=[
|
||||
self.hooks = [
|
||||
ModuleHook("PING", self.pingrespond),
|
||||
ModuleHook("_RECV", self.resettimer)
|
||||
]
|
||||
|
||||
|
||||
def pingrespond(self, args, prefix, trailing):
|
||||
"""Respond to the PING command"""
|
||||
# got a ping? send it right back
|
||||
self.bot.act_PONG(trailing)
|
||||
self.log.info("%s Responded to a ping: %s" % (self.bot.get_nick(), trailing))
|
||||
|
||||
|
||||
def resettimer(self, msg):
|
||||
"""Resets the connection failure timer"""
|
||||
self.timer.reset()
|
||||
|
||||
|
||||
def ondisable(self):
|
||||
self.timer.disable()
|
||||
|
||||
|
||||
|
||||
class PingRespondTimer(Thread):
|
||||
"Tracks last ping from server, and reconnects if over a threshold"
|
||||
def __init__(self, master):
|
||||
@@ -47,20 +44,20 @@ class PingRespondTimer(Thread):
|
||||
self.master = master
|
||||
self.reset()
|
||||
self.start()
|
||||
|
||||
|
||||
def reset(self):
|
||||
"Reset the internal ping timeout counter"
|
||||
self.lastping = time()
|
||||
|
||||
|
||||
def disable(self):
|
||||
"Allow the thread to die"
|
||||
self.alive = False
|
||||
|
||||
|
||||
def run(self):
|
||||
while self.alive:
|
||||
sleep(5)
|
||||
if time() - self.lastping > 300: #TODO: configurable timeout
|
||||
if time() - self.lastping > 300: # TODO: configurable timeout
|
||||
self.master.log.info("No pings in %s seconds. Reconnecting" % str(time() - self.lastping))
|
||||
self.master.bot.disconnect("Reconnecting...")
|
||||
self.reset()
|
||||
|
||||
|
||||
|
||||
@@ -7,21 +7,22 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class RandQuote(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[]
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = []
|
||||
self.db = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("sqlite")
|
||||
if len(serviceProviders)==0:
|
||||
if not serviceProviders:
|
||||
self.log.error("RandQuote: Could not find a valid sqlite service provider")
|
||||
else:
|
||||
self.log.info("RandQuote: Selecting sqlite service provider: %s" % serviceProviders[0])
|
||||
self.db = serviceProviders[0].opendb("randquote.db")
|
||||
|
||||
|
||||
if not self.db.tableExists("chat"):
|
||||
self.log.info("RandQuote: Creating table: chat")
|
||||
c = self.db.query("""CREATE TABLE IF NOT EXISTS `chat` (
|
||||
@@ -31,13 +32,13 @@ class RandQuote(ModuleBase):
|
||||
`message` varchar(2048)
|
||||
) ;""")
|
||||
c.close()
|
||||
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.logquote),ModuleHook("PRIVMSG", self.fetchquotes)]
|
||||
|
||||
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.logquote),
|
||||
ModuleHook("PRIVMSG", self.fetchquotes)]
|
||||
|
||||
def fetchquotes(self, args, prefix, trailing):
|
||||
if not args[0][0]=="#":
|
||||
if not args[0][0] == "#":
|
||||
return
|
||||
prefixObj = self.bot.decodePrefix(prefix)
|
||||
cmd = self.bot.messageHasCommand([".randomquote", ".randquote", ".rq"], trailing)
|
||||
if cmd:
|
||||
c = self.db.query("SELECT * FROM `chat` ORDER BY RANDOM() LIMIT 1;")
|
||||
@@ -45,15 +46,14 @@ class RandQuote(ModuleBase):
|
||||
c.close()
|
||||
if row:
|
||||
self.bot.act_PRIVMSG(args[0], "<%s> %s" % (row["sender"], row["message"],))
|
||||
|
||||
|
||||
def logquote(self, args, prefix, trailing):
|
||||
if not args[0][0]=="#":
|
||||
if not args[0][0] == "#":
|
||||
return
|
||||
prefixObj = self.bot.decodePrefix(prefix)
|
||||
self.db.query("INSERT INTO `chat` (`date`, `sender`, `message`) VALUES (?, ?, ?)",
|
||||
(int(datetime.now().timestamp()), prefixObj.nick, trailing)).close()
|
||||
# Trim quotes
|
||||
deleteIds = []
|
||||
(int(datetime.now().timestamp()), prefixObj.nick, trailing)).close()
|
||||
# Trim quotes
|
||||
c = self.db.query("SELECT * FROM `chat` ORDER BY `date` DESC LIMIT %s, 1000000;" % self.config["limit"])
|
||||
while True:
|
||||
row = c.fetchone()
|
||||
@@ -61,7 +61,7 @@ class RandQuote(ModuleBase):
|
||||
break
|
||||
self.db.query("DELETE FROM `chat` WHERE id=?", (row["id"],)).close()
|
||||
c.close()
|
||||
|
||||
|
||||
def ondisable(self):
|
||||
self.db.close()
|
||||
|
||||
|
||||
|
||||
@@ -6,25 +6,26 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from datetime import datetime,timedelta
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
from datetime import datetime, timedelta
|
||||
from threading import Thread
|
||||
from time import sleep
|
||||
import re
|
||||
import pytz
|
||||
|
||||
|
||||
class Remind(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
|
||||
self.db = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("sqlite")
|
||||
if len(serviceProviders)==0:
|
||||
if not serviceProviders:
|
||||
self.log.error("Remind: Could not find a valid sqlite service provider")
|
||||
else:
|
||||
self.log.info("Remind: Selecting sqlite service provider: %s" % serviceProviders[0])
|
||||
self.db = serviceProviders[0].opendb("remind.db")
|
||||
|
||||
|
||||
if not self.db.tableExists("reminders"):
|
||||
self.log.info("Remind: Creating table: reminders")
|
||||
c = self.db.query("""CREATE TABLE IF NOT EXISTS `reminders` (
|
||||
@@ -35,142 +36,144 @@ class Remind(ModuleBase):
|
||||
`message` varchar(2048)
|
||||
) ;""")
|
||||
c.close()
|
||||
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.remindin),ModuleHook("PRIVMSG", self.remindat)]
|
||||
|
||||
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.remindin),
|
||||
ModuleHook("PRIVMSG", self.remindat)]
|
||||
|
||||
self.disabled = False
|
||||
|
||||
|
||||
# Start monitor thread
|
||||
self.t = Thread(target=self.monitor_thread)
|
||||
self.t.daemon=True
|
||||
self.t.daemon = True
|
||||
self.t.start()
|
||||
|
||||
|
||||
|
||||
def monitor_thread(self):
|
||||
while True:
|
||||
sleep(self.config["precision"])
|
||||
if self.disabled:
|
||||
break
|
||||
self.monitor()
|
||||
|
||||
|
||||
def monitor(self):
|
||||
remindPeople = self.db.query("SELECT * FROM `reminders` WHERE `when` < ?", (datetime.now(),))
|
||||
reminders = remindPeople.fetchall()
|
||||
remindPeople.close()
|
||||
|
||||
|
||||
byrecip = {}
|
||||
|
||||
|
||||
for reminder in reminders:
|
||||
if not reminder["sender"] in byrecip:
|
||||
byrecip[reminder["sender"]]=[]
|
||||
|
||||
byrecip[reminder["sender"]] = []
|
||||
|
||||
byrecip[reminder["sender"]].append(reminder)
|
||||
|
||||
|
||||
reminders_bych = {}
|
||||
|
||||
|
||||
for recip in byrecip:
|
||||
reminders_pm = []
|
||||
|
||||
|
||||
for reminder in byrecip[recip]:
|
||||
if reminder["senderch"]=="":
|
||||
if reminder["senderch"] == "":
|
||||
reminders_pm.append(reminder)
|
||||
else:
|
||||
if not reminder["senderch"] in reminders_bych:
|
||||
reminders_bych[reminder["senderch"]] = []
|
||||
reminders_bych[reminder["senderch"]].append(reminder)
|
||||
self.sendReminders(reminders_pm, recip, recip)
|
||||
|
||||
|
||||
for channel in reminders_bych:
|
||||
channelpms_bysender = {}
|
||||
|
||||
|
||||
for chreminder in reminders_bych[channel]:
|
||||
if not chreminder["sender"] in channelpms_bysender:
|
||||
channelpms_bysender[chreminder["sender"]]=[]
|
||||
channelpms_bysender[chreminder["sender"]] = []
|
||||
channelpms_bysender[chreminder["sender"]].append(chreminder)
|
||||
|
||||
|
||||
for recip in channelpms_bysender:
|
||||
self.sendReminders(channelpms_bysender[recip], channel, recip)
|
||||
|
||||
|
||||
# Delete now that it's sent
|
||||
for item in reminders:
|
||||
self.db.query("DELETE FROM `reminders` WHERE `id`=?", (item["id"],)).close()
|
||||
|
||||
|
||||
def sendReminders(self, reminders, target, nick):
|
||||
" Send a set of reminders of the same recipient, to them. Collapse down into one message."
|
||||
reminder_str = []
|
||||
for reminder in reminders:
|
||||
reminder_str.append(reminder["message"])
|
||||
reminder_str = ", ".join(reminder_str)
|
||||
if len(reminder_str)>0:
|
||||
if len(reminder_str) > 0:
|
||||
self.bot.act_PRIVMSG(target, "%s: Reminder: %s" % (nick, reminder_str))
|
||||
|
||||
|
||||
def ondisable(self):
|
||||
self.disabled = True
|
||||
|
||||
|
||||
def remindat(self, args, prefix, trailing):
|
||||
prefixObj = self.bot.decodePrefix(prefix)
|
||||
|
||||
replyTo = prefixObj.nick if not "#" in args[0] else args[0]
|
||||
|
||||
|
||||
replyTo = prefixObj.nick if "#" not in args[0] else args[0]
|
||||
|
||||
# Lots of code borrowed from https://github.com/embolalia/willie/blob/master/willie/modules/remind.py
|
||||
cmd = self.bot.messageHasCommand([".at", ".remind"], trailing, True)
|
||||
if cmd:
|
||||
regex = re.compile(r'(\d+):(\d+)(?::(\d+))?([^\s\d]+)? (.*)')
|
||||
match = regex.match(cmd.args_str)
|
||||
|
||||
|
||||
try:
|
||||
hour, minute, second, tz, message = match.groups()
|
||||
message = message.strip()
|
||||
|
||||
|
||||
assert not message == ""
|
||||
|
||||
|
||||
hour = int(hour)
|
||||
minute = int(minute)
|
||||
if not second == None:
|
||||
if second is not None:
|
||||
second = int(second)
|
||||
|
||||
|
||||
except:
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: .at - Remind at a time. Example: .at 20:45EST Do your homework!" % prefixObj.nick)
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: .at - Remind at a time. Example: .at 20:45EST Do your homework!" %
|
||||
prefixObj.nick)
|
||||
return
|
||||
|
||||
|
||||
now = datetime.now()
|
||||
remindAt = datetime.now()
|
||||
|
||||
|
||||
# if there was timezone, make sure the time we're reminding them at is relative to their timezone
|
||||
if not tz == None:
|
||||
if tz is not None:
|
||||
try:
|
||||
theirzone = pytz.timezone(Remind.translateZoneStr(tz))
|
||||
except:
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: I don't recognize the timezone '%s'." % (prefixObj.nick, tz))
|
||||
return
|
||||
remindAt = theirzone.localize(remindAt, is_dst=Remind.is_dst(theirzone))
|
||||
|
||||
# Set the hour and minute we'll remind them at today. If the ends up being in the past, we'll add a day alter
|
||||
|
||||
# Set the hour and minute we'll remind them at today.
|
||||
# If the ends up being in the past, we'll add a day alter
|
||||
remindAt = remindAt.replace(hour=hour).replace(minute=minute).replace(microsecond=0)
|
||||
|
||||
|
||||
# Set seconds
|
||||
if second == None:
|
||||
if second is None:
|
||||
remindAt = remindAt.replace(second=0)
|
||||
else:
|
||||
remindAt = remindAt.replace(second=second)
|
||||
|
||||
|
||||
# if there was timezone, convert remindAt to our zone
|
||||
if not tz == None:
|
||||
if tz is not None:
|
||||
try:
|
||||
theirzone = pytz.timezone(Remind.translateZoneStr(tz))
|
||||
except:
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: I don't recognize the timezone '%s'." % (prefixObj.nick, tz))
|
||||
return
|
||||
remindAt = remindAt.astimezone(pytz.timezone(self.config["mytimezone"])).replace(tzinfo=None)
|
||||
|
||||
|
||||
# Advance it a day if the time would have been earlier today
|
||||
while remindAt<now:
|
||||
while remindAt < now:
|
||||
remindAt += timedelta(days=1)
|
||||
|
||||
timediff = remindAt-datetime.now()
|
||||
#self.bot.act_PRIVMSG(replyTo, "Time: %s" % str(remindAt))
|
||||
#self.bot.act_PRIVMSG(replyTo, "Diff: %s" % (timediff))
|
||||
|
||||
|
||||
timediff = remindAt - datetime.now()
|
||||
# self.bot.act_PRIVMSG(replyTo, "Time: %s" % str(remindAt))
|
||||
# self.bot.act_PRIVMSG(replyTo, "Diff: %s" % (timediff))
|
||||
|
||||
# Save the reminder
|
||||
c = self.db.query("INSERT INTO `reminders` (`sender`, `senderch`, `when`, `message`) VALUES (?, ?, ?, ?)", (
|
||||
prefixObj.nick,
|
||||
@@ -179,67 +182,69 @@ class Remind(ModuleBase):
|
||||
message
|
||||
))
|
||||
c.close()
|
||||
|
||||
|
||||
diffHours = int(timediff.seconds / 60 / 60)
|
||||
diffMins= int((timediff.seconds-diffHours*60*60)/60)
|
||||
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: Ok, will do. Approx %sh%sm to go." % (prefixObj.nick, diffHours, diffMins))
|
||||
|
||||
diffMins = int((timediff.seconds - diffHours * 60 * 60) / 60)
|
||||
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: Ok, will do. Approx %sh%sm to go." %
|
||||
(prefixObj.nick, diffHours, diffMins))
|
||||
|
||||
@staticmethod
|
||||
def is_dst(tz):
|
||||
now = pytz.utc.localize(datetime.utcnow())
|
||||
return now.astimezone(tz).dst() != timedelta(0)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def translateZoneStr(zonestr):
|
||||
translations = {
|
||||
"EDT":"US/Eastern",
|
||||
"PDT":"America/Los_Angeles"
|
||||
"EDT": "US/Eastern",
|
||||
"PDT": "America/Los_Angeles"
|
||||
}
|
||||
if zonestr in translations:
|
||||
return translations[zonestr]
|
||||
else:
|
||||
return zonestr
|
||||
|
||||
|
||||
def remindin(self, args, prefix, trailing):
|
||||
prefixObj = self.bot.decodePrefix(prefix)
|
||||
replyTo = prefixObj.nick if not "#" in args[0] else args[0]
|
||||
|
||||
replyTo = prefixObj.nick if "#" not in args[0] else args[0]
|
||||
|
||||
cmd = self.bot.messageHasCommand([".in", ".after"], trailing, True)
|
||||
if cmd:
|
||||
if len(cmd.args)==0:
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: .in - Remind after x amount of time. Example: .in 1week5d2h1m Go fuck yourself" %
|
||||
(prefixObj.nick, diffHours, diffMins))
|
||||
if not cmd.args:
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: .in - Remind after x amount of time. Example: .in 1week5d2h1m Go "
|
||||
"fuck yourself" % prefixObj.nick)
|
||||
return
|
||||
|
||||
|
||||
timepieces = re.compile(r'([0-9]+)([a-zA-Z]+)').findall(cmd.args[0])
|
||||
if len(timepieces)==0:
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: .in - Remind after x amount of time. Example: .in 1week5d2h1m Go fuck yourself" %
|
||||
(prefixObj.nick, diffHours, diffMins))
|
||||
if not timepieces:
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: .in - Remind after x amount of time. Example: .in 1week5d2h1m Go "
|
||||
"fuck yourself" % prefixObj.nick)
|
||||
return
|
||||
|
||||
|
||||
delaySeconds = 0
|
||||
for match in timepieces:
|
||||
# ('30', 'm')
|
||||
if not match[1] in Remind.scaling:
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: Sorry, I don't understand the time unit '%s'" % (prefixObj.nick, match[1]))
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: Sorry, I don't understand the time unit '%s'" %
|
||||
(prefixObj.nick, match[1]))
|
||||
return
|
||||
|
||||
delaySeconds+=(Remind.scaling[match[1]] * int(match[0]))
|
||||
|
||||
remindAt = datetime.now()+timedelta(seconds=delaySeconds)
|
||||
|
||||
|
||||
delaySeconds += (Remind.scaling[match[1]] * int(match[0]))
|
||||
|
||||
remindAt = datetime.now() + timedelta(seconds=delaySeconds)
|
||||
|
||||
self.db.query("INSERT INTO `reminders` (`sender`, `senderch`, `when`, `message`) VALUES (?, ?, ?, ?)", (
|
||||
prefixObj.nick,
|
||||
args[0] if "#" in args[0] else "",
|
||||
remindAt,
|
||||
cmd.args_str[len(cmd.args[0]):].strip()
|
||||
)).close()
|
||||
|
||||
hours = int(delaySeconds/60/60)
|
||||
minutes = int((delaySeconds-(hours*60*60))/60)
|
||||
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: Ok, talk to you in approx %sh%sm" % (prefixObj.nick, hours,minutes))
|
||||
|
||||
hours = int(delaySeconds / 60 / 60)
|
||||
minutes = int((delaySeconds - (hours * 60 * 60)) / 60)
|
||||
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: Ok, talk to you in approx %sh%sm" % (prefixObj.nick, hours, minutes))
|
||||
|
||||
scaling = {
|
||||
"years": 365.25 * 24 * 3600,
|
||||
|
||||
@@ -8,19 +8,18 @@
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase
|
||||
import sys
|
||||
import sqlite3
|
||||
|
||||
|
||||
class SQLite(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[]
|
||||
self.services=["sqlite"]
|
||||
self.loadConfig()
|
||||
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = []
|
||||
self.services = ["sqlite"]
|
||||
|
||||
def opendb(self, dbname):
|
||||
return Connection(self, dbname)
|
||||
|
||||
|
||||
|
||||
class Connection:
|
||||
def __init__(self, master, dbname):
|
||||
@@ -29,16 +28,16 @@ class Connection:
|
||||
self.dbname = dbname
|
||||
self.connection = None
|
||||
self._connect()
|
||||
|
||||
|
||||
# Check if the table requested exists
|
||||
def tableExists(self, tablename):
|
||||
c = self.getCursor()
|
||||
c.execute("SELECT * FROM SQLITE_MASTER WHERE `type`='table' AND `name`=?", (tablename,))
|
||||
tables = c.fetchall()
|
||||
if len(tables)==0:
|
||||
return False;
|
||||
if len(tables) == 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@staticmethod
|
||||
def dict_factory(cursor, row):
|
||||
d = {}
|
||||
@@ -48,30 +47,30 @@ class Connection:
|
||||
|
||||
def query(self, queryText, args=()):
|
||||
"""Execute a Sqlite query and return the cursor
|
||||
|
||||
|
||||
:param queryText: the sqlite query as a string, using '%s' for token replacement
|
||||
:type queryText: str
|
||||
:param args: arguments to be escaped into the query
|
||||
:type args: tuple
|
||||
:returns: cursor -- the sql cursor"""
|
||||
c = self.getCursor()
|
||||
if len(args)==0:
|
||||
if len(args) == 0:
|
||||
c.execute(queryText)
|
||||
else:
|
||||
c.execute(queryText, args)
|
||||
return c
|
||||
|
||||
|
||||
# Returns a cusor object, after checking for connectivity
|
||||
def getCursor(self):
|
||||
c=self.connection.cursor()
|
||||
c = self.connection.cursor()
|
||||
return c
|
||||
|
||||
|
||||
def escape(self, s):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def ondisable(self):
|
||||
self.connection.close()
|
||||
|
||||
|
||||
# Connects to the database server, and selects a database (Or attempts to create it if it doesn't exist yet)
|
||||
def _connect(self):
|
||||
self.log.info("Sqlite: opening database %s" % self.master.getFilePath(self.dbname))
|
||||
@@ -79,11 +78,11 @@ class Connection:
|
||||
self.connection.row_factory = Connection.dict_factory
|
||||
self.connection.isolation_level = None
|
||||
self.log.info("Sqlite: Connected.")
|
||||
|
||||
|
||||
# Test the connection
|
||||
c = self.connection.cursor()
|
||||
derp=c.execute("SELECT * FROM SQLITE_MASTER")
|
||||
derp = c.execute("SELECT * FROM SQLITE_MASTER") # NOQA
|
||||
c.close()
|
||||
|
||||
|
||||
def close(self):
|
||||
self.connection.close()
|
||||
|
||||
@@ -6,75 +6,75 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
import random
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
from threading import Timer
|
||||
from operator import itemgetter
|
||||
|
||||
|
||||
class Scramble(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
# init the base module
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.scramble)]
|
||||
self.loadConfig()
|
||||
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.scramble)]
|
||||
|
||||
# Dictionary
|
||||
self.wordsCount=0;
|
||||
self.wordsCount = 0
|
||||
self.wordsFile = self.getFilePath("words.txt")
|
||||
print(self.wordsFile)
|
||||
wordsF = open(self.wordsFile, "r")
|
||||
while True:
|
||||
word = wordsF.readline()
|
||||
if word=="":
|
||||
if not word:
|
||||
break
|
||||
self.wordsCount+=1
|
||||
self.wordsCount += 1
|
||||
wordsF.close
|
||||
self.log.info("Scramble: Loaded %s words" % str(self.wordsCount))
|
||||
# Load scores
|
||||
self.scoresFile = self.getFilePath("scores.json")
|
||||
if not os.path.exists(self.scoresFile):
|
||||
if not os.path.exists(self.scoresFile):
|
||||
json.dump({}, open(self.scoresFile, 'w'))
|
||||
self.scores = json.load(open(self.scoresFile, 'r'))
|
||||
# Per channel games
|
||||
self.games = {}
|
||||
# Hook in
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.scramble)]
|
||||
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.scramble)]
|
||||
|
||||
def scramble(self, args, prefix, trailing):
|
||||
channel = args[0]
|
||||
if channel[0] == "#":
|
||||
if not channel in self.games:
|
||||
self.games[channel]=scrambleGame(self, channel)
|
||||
if channel not in self.games:
|
||||
self.games[channel] = scrambleGame(self, channel)
|
||||
self.games[channel].scramble(args, prefix, trailing)
|
||||
|
||||
|
||||
def saveScores(self):
|
||||
json.dump(self.scores, open(self.scoresFile, 'w'))
|
||||
|
||||
|
||||
def getScore(self, player, add=0):
|
||||
player = player.lower()
|
||||
if not player in self.scores:
|
||||
if player not in self.scores:
|
||||
self.scores[player] = 0
|
||||
if not add == 0:
|
||||
self.scores[player]+=add
|
||||
self.scores[player] += add
|
||||
self.saveScores()
|
||||
|
||||
|
||||
return self.scores[player]
|
||||
|
||||
|
||||
def getScoreNoWrite(self, player):
|
||||
if not player.lower() in self.scores:
|
||||
return 0
|
||||
else:
|
||||
return self.getScore(player)
|
||||
|
||||
|
||||
def ondisable(self):
|
||||
self.log.info("Scramble: Unload requested, ending games...")
|
||||
for game in self.games:
|
||||
self.games[game].gameover()
|
||||
self.saveScores()
|
||||
|
||||
|
||||
class scrambleGame:
|
||||
def __init__(self, master, channel):
|
||||
self.master = master
|
||||
@@ -94,24 +94,27 @@ class scrambleGame:
|
||||
# Cooldown between words
|
||||
self.nextTimer = None
|
||||
# How many gamesWithoutGuesses submitted this round
|
||||
self.guesses = 0;
|
||||
self.guesses = 0
|
||||
# How many games in a row where nobody guessed
|
||||
self.gamesWithoutGuesses = 0;
|
||||
|
||||
self.delayHint = self.master.config["hintDelay"];
|
||||
self.delayNext = self.master.config["delayNext"];
|
||||
self.maxHints = self.master.config["maxHints"];
|
||||
self.abortAfterNoGuesses = self.master.config["abortAfterNoGuesses"];
|
||||
|
||||
self.gamesWithoutGuesses = 0
|
||||
|
||||
self.delayHint = self.master.config["hintDelay"]
|
||||
self.delayNext = self.master.config["delayNext"]
|
||||
self.maxHints = self.master.config["maxHints"]
|
||||
self.abortAfterNoGuesses = self.master.config["abortAfterNoGuesses"]
|
||||
|
||||
def gameover(self):
|
||||
self.clearTimers();
|
||||
self.clearTimers()
|
||||
self.running = False
|
||||
|
||||
def clearTimers(self):
|
||||
self.clearTimer(self.nextTimer)
|
||||
self.clearTimer(self.hintTimer)
|
||||
|
||||
def clearTimer(self, timer):
|
||||
if timer:
|
||||
timer.cancel()
|
||||
|
||||
def scramble(self, args, prefix, trailing):
|
||||
prefix = self.master.bot.decodePrefix(prefix)
|
||||
sender = prefix.nick
|
||||
@@ -129,111 +132,115 @@ class scrambleGame:
|
||||
if cmd:
|
||||
sortedscores = []
|
||||
for player in self.master.scores:
|
||||
sortedscores.append({'name':player, 'score':self.master.scores[player]})
|
||||
sortedscores.append({'name': player, 'score': self.master.scores[player]})
|
||||
sortedscores = sorted(sortedscores, key=itemgetter('score'))
|
||||
sortedscores.reverse()
|
||||
numScores = len(sortedscores)
|
||||
if numScores>3:
|
||||
numScores=3
|
||||
if numScores > 3:
|
||||
numScores = 3
|
||||
resp = "Top %s: " % str(numScores)
|
||||
which = 1
|
||||
while which<=numScores:
|
||||
resp+="%s: %s, " % (sortedscores[which-1]["name"], sortedscores[which-1]["score"])
|
||||
which+=1
|
||||
while which <= numScores:
|
||||
resp += "%s: %s, " % (sortedscores[which - 1]["name"], sortedscores[which - 1]["score"])
|
||||
which += 1
|
||||
self.master.bot.act_PRIVMSG(self.channel, resp[:-2])
|
||||
cmd = self.master.bot.messageHasCommand(".scramble score", trailing)
|
||||
if cmd:
|
||||
someone = cmd.args.strip()
|
||||
if len(someone) > 0:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: %s has a score of %s" % (sender, someone, self.master.getScoreNoWrite(someone)))
|
||||
else:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: %s has a score of %s" %
|
||||
(sender, someone, self.master.getScoreNoWrite(someone)))
|
||||
else:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s: %s" % (sender, self.master.getScore(sender)))
|
||||
if self.currentWord and trailing.strip().lower() == self.currentWord:
|
||||
playerScore = self.master.getScore(sender, 1)
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s guessed the word - %s! %s now has %s points. Next word in %s seconds." % (sender, self.currentWord, sender, playerScore, self.delayNext))
|
||||
self.master.bot.act_PRIVMSG(self.channel, "%s guessed the word - %s! %s now has %s points. Next word in %s "
|
||||
"seconds." % (sender, self.currentWord, sender, playerScore, self.delayNext))
|
||||
self.currentWord = None
|
||||
self.clearTimers()
|
||||
self.hintsGiven = 0
|
||||
self.nextTimer = Timer(self.delayNext, self.startNewWord)
|
||||
self.nextTimer.start()
|
||||
self.guesses=0
|
||||
self.guesses = 0
|
||||
else:
|
||||
self.guesses+=1
|
||||
|
||||
self.guesses += 1
|
||||
|
||||
def startScramble(self):
|
||||
self.clearTimer(self.nextTimer)
|
||||
self.nextTimer = Timer(0, self.startNewWord)
|
||||
self.nextTimer.start()
|
||||
|
||||
|
||||
def startNewWord(self):
|
||||
self.currentWord = self.pickWord()
|
||||
self.master.log.info("Scramble: New word for %s: %s" % (self.channel, self.currentWord))
|
||||
self.scrambled = self.scrambleWord(self.currentWord)
|
||||
self.master.bot.act_PRIVMSG(self.channel, "New word - %s " % (self.scrambled))
|
||||
|
||||
|
||||
self.clearTimer(self.hintTimer)
|
||||
self.hintTimer = Timer(self.delayHint, self.giveHint)
|
||||
self.hintTimer.start()
|
||||
|
||||
|
||||
def giveHint(self):
|
||||
self.hintsGiven+=1
|
||||
|
||||
if self.hintsGiven>=len(self.currentWord) or self.hintsGiven > self.maxHints:
|
||||
self.hintsGiven += 1
|
||||
|
||||
if self.hintsGiven >= len(self.currentWord) or self.hintsGiven > self.maxHints:
|
||||
self.abortWord()
|
||||
return
|
||||
|
||||
|
||||
blanks = ""
|
||||
for letter in list(self.currentWord):
|
||||
if letter == " ":
|
||||
blanks+=" "
|
||||
blanks += " "
|
||||
else:
|
||||
blanks+="_"
|
||||
blanks += "_"
|
||||
partFromWord = self.currentWord[0:self.hintsGiven]
|
||||
partFromBlanks = blanks[self.hintsGiven:]
|
||||
hintstr = partFromWord+partFromBlanks
|
||||
|
||||
hintstr = partFromWord + partFromBlanks
|
||||
|
||||
self.master.bot.act_PRIVMSG(self.channel, "Hint: - %s" % (hintstr))
|
||||
|
||||
|
||||
self.clearTimer(self.hintTimer)
|
||||
self.hintTimer = Timer(self.delayHint, self.giveHint)
|
||||
self.hintTimer.start()
|
||||
|
||||
|
||||
def abortWord(self):
|
||||
cur = self.currentWord
|
||||
self.currentWord = None
|
||||
self.master.bot.act_PRIVMSG(self.channel, "Word expired - the answer was %s. Next word in %s seconds." % (cur, self.delayNext))
|
||||
self.master.bot.act_PRIVMSG(self.channel, "Word expired - the answer was %s. Next word in %s seconds." %
|
||||
(cur, self.delayNext))
|
||||
self.hintsGiven = 0
|
||||
self.clearTimer(self.nextTimer)
|
||||
|
||||
if self.guesses==0:
|
||||
self.gamesWithoutGuesses+=1
|
||||
|
||||
if self.guesses == 0:
|
||||
self.gamesWithoutGuesses += 1
|
||||
if self.gamesWithoutGuesses >= self.abortAfterNoGuesses:
|
||||
self.master.bot.act_PRIVMSG(self.channel, "No one seems to be playing - type .scrambleon to start again.")
|
||||
self.master.bot.act_PRIVMSG(self.channel, "No one seems to be playing - type .scrambleon to "
|
||||
"start again.")
|
||||
self.gameover()
|
||||
return
|
||||
else:
|
||||
self.gamesWithoutGuesses=0
|
||||
|
||||
self.gamesWithoutGuesses = 0
|
||||
|
||||
self.nextTimer = Timer(self.delayNext, self.startNewWord)
|
||||
self.nextTimer.start()
|
||||
|
||||
|
||||
def pickWord(self):
|
||||
f = open(self.master.wordsFile, "r")
|
||||
skip = random.randint(0, self.master.wordsCount)
|
||||
while skip>=0:
|
||||
while skip >= 0:
|
||||
f.readline()
|
||||
skip-=1
|
||||
skip -= 1
|
||||
picked = f.readline().strip().lower()
|
||||
f.close()
|
||||
return picked
|
||||
|
||||
|
||||
def scrambleWord(self, word):
|
||||
scrambled = ""
|
||||
for subword in word.split(" "):
|
||||
scrambled+=self.scrambleIndividualWord(subword)+ " "
|
||||
scrambled += self.scrambleIndividualWord(subword) + " "
|
||||
return scrambled.strip()
|
||||
|
||||
|
||||
def scrambleIndividualWord(self, word):
|
||||
scrambled = list(word)
|
||||
random.shuffle(scrambled)
|
||||
return ''.join(scrambled).lower()
|
||||
return ''.join(scrambled).lower()
|
||||
|
||||
@@ -7,66 +7,68 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
import sqlite3
|
||||
import time
|
||||
|
||||
|
||||
class Seen(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.lastSeen)]
|
||||
self.loadConfig()
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.lastSeen)]
|
||||
# if the database doesnt exist, it will be created
|
||||
sql = self.getSql()
|
||||
c=sql.cursor()
|
||||
c = sql.cursor()
|
||||
# check if our table exists
|
||||
c.execute("SELECT * FROM SQLITE_MASTER WHERE `type`='table' AND `name`='seen'")
|
||||
if len(c.fetchall())==0:
|
||||
if len(c.fetchall()) == 0:
|
||||
self.log.info("Seen: Creating database")
|
||||
# if no, create it.
|
||||
c.execute("CREATE TABLE `seen` (`nick` VARCHAR(32), `date` INTEGER, PRIMARY KEY(`nick`))");
|
||||
c.execute("CREATE TABLE `seen` (`nick` VARCHAR(32), `date` INTEGER, PRIMARY KEY(`nick`))")
|
||||
self.x = "asdf"
|
||||
|
||||
|
||||
def lastSeen(self, args, prefix, trailing):
|
||||
# using a message to update last seen, also, the .seen query
|
||||
prefixObj = self.bot.decodePrefix(prefix)
|
||||
nick = prefixObj.nick
|
||||
sql=self.getSql()
|
||||
sql = self.getSql()
|
||||
c = sql.cursor()
|
||||
# update or add the user's row
|
||||
datest=str( time.time()+(int(self.config["add_hours"])*60*60))
|
||||
c.execute("REPLACE INTO `seen` (`nick`, `date`) VALUES (?, ?)", (nick.lower(), datest ))
|
||||
#self.log.info("Seen: %s on %s" % (nick.lower(), datest))
|
||||
datest = str(time.time() + (int(self.config["add_hours"]) * 60 * 60))
|
||||
c.execute("REPLACE INTO `seen` (`nick`, `date`) VALUES (?, ?)", (nick.lower(), datest))
|
||||
# self.log.info("Seen: %s on %s" % (nick.lower(), datest))
|
||||
sql.commit()
|
||||
if trailing.startswith(".seen"):
|
||||
cmdargs = trailing.split(" ");
|
||||
cmdargs = trailing.split(" ")
|
||||
# query the DB for the user
|
||||
if len(cmdargs)>=2:
|
||||
searchnic = cmdargs[1].lower();
|
||||
if len(cmdargs) >= 2:
|
||||
searchnic = cmdargs[1].lower()
|
||||
c.execute("SELECT * FROM `seen` WHERE `nick`= ? ", [searchnic])
|
||||
rows = c.fetchall()
|
||||
if len(rows)==1:
|
||||
self.bot.act_PRIVMSG(args[0], "I last saw %s on %s (%s)."% (cmdargs[1], time.strftime("%m/%d/%y at %I:%M %p", time.localtime(rows[0]['date'])), self.config["timezone"]));
|
||||
if len(rows) == 1:
|
||||
self.bot.act_PRIVMSG(args[0], "I last saw %s on %s (%s)." %
|
||||
(cmdargs[1], time.strftime("%m/%d/%y at %I:%M %p",
|
||||
time.localtime(rows[0]['date'])), self.config["timezone"]))
|
||||
else:
|
||||
self.bot.act_PRIVMSG(args[0], "Sorry, I haven't seen %s!" % cmdargs[1])
|
||||
c.close()
|
||||
|
||||
|
||||
def getSql(self):
|
||||
# return a SQL reference to the database
|
||||
path = self.getFilePath('database.sql3')
|
||||
sql = sqlite3.connect(path);
|
||||
sql = sqlite3.connect(path)
|
||||
sql.row_factory = self.dict_factory
|
||||
return sql
|
||||
|
||||
|
||||
def dict_factory(self, cursor, row):
|
||||
# because Lists suck for database results
|
||||
d = {}
|
||||
for idx, col in enumerate(cursor.description):
|
||||
d[col[0]] = row[idx]
|
||||
return d
|
||||
|
||||
|
||||
def test(self, arg):
|
||||
print("TEST: %s" % arg)
|
||||
print("self.x = %s" % self.x)
|
||||
return arg
|
||||
|
||||
|
||||
|
||||
@@ -7,26 +7,31 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
from time import sleep
|
||||
|
||||
|
||||
class Services(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = [ModuleHook("_CONNECT", self.doConnect), ModuleHook("433", self.nickTaken), ModuleHook("001", self.initservices), ModuleHook("INVITE", self.invited), ]
|
||||
self.hooks = [ModuleHook("_CONNECT", self.doConnect),
|
||||
ModuleHook("433", self.nickTaken),
|
||||
ModuleHook("001", self.initservices),
|
||||
ModuleHook("INVITE", self.invited), ]
|
||||
self.current_nick = 0
|
||||
self.do_ghost = False
|
||||
|
||||
def doConnect(self, args, prefix, trailing):
|
||||
"""Hook for when the IRC conneciton is opened"""
|
||||
self.bot.act_NICK(self.config["user"]["nick"][0])
|
||||
self.bot.act_USER(self.config["user"]["username"], self.config["user"]["hostname"], self.config["user"]["realname"])
|
||||
self.bot.act_USER(self.config["user"]["username"], self.config["user"]["hostname"],
|
||||
self.config["user"]["realname"])
|
||||
|
||||
def nickTaken(self, args, prefix, trailing):
|
||||
"""Hook that responds to 433, meaning our nick is taken"""
|
||||
if self.config["ident"]["ghost"]:
|
||||
self.do_ghost = True
|
||||
self.current_nick+=1
|
||||
self.current_nick += 1
|
||||
if self.current_nick >= len(self.config["user"]["nick"]):
|
||||
self.log.critical("Ran out of usernames while selecting backup username!")
|
||||
return
|
||||
@@ -35,7 +40,8 @@ class Services(ModuleBase):
|
||||
def initservices(self, args, prefix, trailing):
|
||||
"""Hook that sets our initial nickname"""
|
||||
if self.do_ghost:
|
||||
self.bot.act_PRIVMSG(self.config["ident"]["ghost_to"], self.config["ident"]["ghost_cmd"] % {"nick":self.config["user"]["nick"][0], "password":self.config["user"]["password"]})
|
||||
self.bot.act_PRIVMSG(self.config["ident"]["ghost_to"], self.config["ident"]["ghost_cmd"] %
|
||||
{"nick": self.config["user"]["nick"][0], "password": self.config["user"]["password"]})
|
||||
sleep(2)
|
||||
self.bot.act_NICK(self.config["user"]["nick"][0])
|
||||
self.do_initservices()
|
||||
@@ -50,7 +56,8 @@ class Services(ModuleBase):
|
||||
"""Identify with nickserv and join startup channels"""
|
||||
" id to nickserv "
|
||||
if self.config["ident"]["enable"]:
|
||||
self.bot.act_PRIVMSG(self.config["ident"]["to"], self.config["ident"]["command"] % {"password":self.config["user"]["password"]})
|
||||
self.bot.act_PRIVMSG(self.config["ident"]["to"], self.config["ident"]["command"] %
|
||||
{"password": self.config["user"]["password"]})
|
||||
|
||||
" join plain channels "
|
||||
for channel in self.config["channels"]:
|
||||
@@ -60,5 +67,6 @@ class Services(ModuleBase):
|
||||
" request invite for private message channels "
|
||||
for channel in self.config["privatechannels"]["list"]:
|
||||
self.log.info("Requesting invite to %s" % channel)
|
||||
self.bot.act_PRIVMSG(self.config["privatechannels"]["to"], self.config["privatechannels"]["command"] % {"channel":channel})
|
||||
self.bot.act_PRIVMSG(self.config["privatechannels"]["to"], self.config["privatechannels"]["command"] %
|
||||
{"channel": channel})
|
||||
|
||||
|
||||
@@ -6,25 +6,26 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
import datetime
|
||||
from time import mktime
|
||||
|
||||
|
||||
class Tell(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
|
||||
self.db = None
|
||||
serviceProviders = self.bot.getmodulesbyservice("sqlite")
|
||||
if len(serviceProviders)==0:
|
||||
if len(serviceProviders) == 0:
|
||||
self.log.error("Tell: Could not find a valid sqlite service provider")
|
||||
else:
|
||||
self.log.info("Tell: Selecting sqlite service provider: %s" % serviceProviders[0])
|
||||
self.db = serviceProviders[0].opendb("tell.db")
|
||||
|
||||
|
||||
if not self.db.tableExists("tells"):
|
||||
self.log.info("Remind: Creating table: tells")
|
||||
c = self.db.query("""CREATE TABLE IF NOT EXISTS `tells` (
|
||||
self.db.query("""CREATE TABLE IF NOT EXISTS `tells` (
|
||||
`id` INTEGER PRIMARY KEY,
|
||||
`sender` varchar(64),
|
||||
`channel` varchar(64),
|
||||
@@ -32,19 +33,19 @@ class Tell(ModuleBase):
|
||||
`recip` varchar(64),
|
||||
`message` varchar(2048)
|
||||
) ;""").close()
|
||||
|
||||
|
||||
# Purge expired tells
|
||||
self.db.query("DELETE FROM `tells` WHERE `when`<?", (int(mktime(datetime.datetime.now().timetuple()))-self.config["maxage"],)).close()
|
||||
|
||||
self.hooks=[
|
||||
self.db.query("DELETE FROM `tells` WHERE `when`<?",
|
||||
(int(mktime(datetime.datetime.now().timetuple())) - self.config["maxage"],)).close()
|
||||
|
||||
self.hooks = [
|
||||
ModuleHook(["JOIN", "PRIVMSG"], self.showtell),
|
||||
ModuleHook(["PRIVMSG"], self.tellcmds)
|
||||
]
|
||||
|
||||
|
||||
def showtell(self, args, prefix, trailing):
|
||||
#print("%s - %s - %s" % (args, prefix, trailing))
|
||||
prefix = self.bot.decodePrefix(prefix)
|
||||
|
||||
|
||||
# Look for tells for this person
|
||||
c = self.db.query("SELECT * FROM `tells` WHERE `recip`=?", (prefix.nick,))
|
||||
tells = c.fetchall()
|
||||
@@ -52,7 +53,7 @@ class Tell(ModuleBase):
|
||||
for tell in tells:
|
||||
agostr = Tell.timesince(datetime.datetime.fromtimestamp(tell["when"]))
|
||||
recip = None
|
||||
if tell["channel"]=="":
|
||||
if tell["channel"] == "":
|
||||
recip = prefix.nick
|
||||
else:
|
||||
recip = tell["channel"]
|
||||
@@ -64,36 +65,36 @@ class Tell(ModuleBase):
|
||||
))
|
||||
# Delete
|
||||
self.db.query("DELETE FROM `tells` WHERE `id`=?", (tell["id"],))
|
||||
|
||||
|
||||
def tellcmds(self, args, prefix, trailing):
|
||||
prefixObj = self.bot.decodePrefix(prefix)
|
||||
replyTo = prefixObj.nick if not "#" in args[0] else args[0]
|
||||
|
||||
replyTo = prefixObj.nick if "#" not in args[0] else args[0]
|
||||
|
||||
cmd = self.bot.messageHasCommand(".tell", trailing)
|
||||
if cmd:
|
||||
if len(cmd.args)<2:
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: .tell <person> <message> - Tell someone something the next time they're seen. Example: .tell antiroach Do your homework!" % prefixObj.nick)
|
||||
if len(cmd.args) < 2:
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: .tell <person> <message> - Tell someone something the next time "
|
||||
"they're seen. Example: .tell antiroach Do your homework!" % prefixObj.nick)
|
||||
return
|
||||
|
||||
|
||||
recip = cmd.args[0]
|
||||
message = ' '.join(cmd.args[1:]).strip()
|
||||
|
||||
if message=="":
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: .tell <person> <message> - Tell someone something the next time they're seen. Example: .tell antiroach Do your homework!" % prefixObj.nick)
|
||||
|
||||
if not message:
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: .tell <person> <message> - Tell someone something the next time "
|
||||
"they're seen. Example: .tell antiroach Do your homework!" %
|
||||
prefixObj.nick)
|
||||
return
|
||||
|
||||
self.db.query("INSERT INTO `tells` (`sender`, `channel`, `when`, `recip`, `message`) VALUES (?, ?, ?, ?, ?);",
|
||||
(
|
||||
prefixObj.nick,
|
||||
args[0] if "#" in args[0] else "",
|
||||
int(mktime(datetime.datetime.now().timetuple())),
|
||||
recip,
|
||||
message
|
||||
)
|
||||
).close()
|
||||
|
||||
|
||||
self.db.query("INSERT INTO `tells` (`sender`, `channel`, `when`, `recip`, `message`) VALUES "
|
||||
"(?, ?, ?, ?, ?);", (prefixObj.nick,
|
||||
args[0] if "#" in args[0] else "",
|
||||
int(mktime(datetime.datetime.now().timetuple())),
|
||||
recip,
|
||||
message)).close()
|
||||
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: I'll pass that along." % prefixObj.nick)
|
||||
|
||||
|
||||
# Copyright (c) Django Software Foundation and individual contributors.
|
||||
# All rights reserved.
|
||||
#
|
||||
@@ -121,43 +122,41 @@ class Tell(ModuleBase):
|
||||
#ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
#(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
#SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
@staticmethod
|
||||
def timesince(d, now=None):
|
||||
"""
|
||||
Takes two datetime objects and returns the time between d and now
|
||||
as a nicely formatted string, e.g. "10 minutes". If d occurs after now,
|
||||
then "0 minutes" is returned.
|
||||
|
||||
|
||||
Units used are years, months, weeks, days, hours, and minutes.
|
||||
Seconds and microseconds are ignored. Up to two adjacent units will be
|
||||
displayed. For example, "2 weeks, 3 days" and "1 year, 3 months" are
|
||||
possible outputs, but "2 weeks, 3 hours" and "1 year, 5 days" are not.
|
||||
|
||||
|
||||
Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since
|
||||
"""
|
||||
chunks = (
|
||||
(60 * 60 * 24 * 365, ('year', 'years')),
|
||||
(60 * 60 * 24 * 30, ('month', 'months')),
|
||||
(60 * 60 * 24 * 7, ('week', 'weeks')),
|
||||
(60 * 60 * 24, ('day', 'days')),
|
||||
(60 * 60, ('hour', 'hours')),
|
||||
(60, ('minute', 'minutes'))
|
||||
)
|
||||
|
||||
chunks = ((60 * 60 * 24 * 365, ('year', 'years')),
|
||||
(60 * 60 * 24 * 30, ('month', 'months')),
|
||||
(60 * 60 * 24 * 7, ('week', 'weeks')),
|
||||
(60 * 60 * 24, ('day', 'days')),
|
||||
(60 * 60, ('hour', 'hours')),
|
||||
(60, ('minute', 'minutes')))
|
||||
|
||||
# Convert int or float (unix epoch) to datetime.datetime for comparison
|
||||
if isinstance(d, int) or isinstance(d, float):
|
||||
d = datetime.datetime.fromtimestamp(d)
|
||||
|
||||
|
||||
# Convert datetime.date to datetime.datetime for comparison.
|
||||
if not isinstance(d, datetime.datetime):
|
||||
d = datetime.datetime(d.year, d.month, d.day)
|
||||
if now and not isinstance(now, datetime.datetime):
|
||||
now = datetime.datetime(now.year, now.month, now.day)
|
||||
|
||||
|
||||
if not now:
|
||||
now = datetime.datetime.now()
|
||||
|
||||
|
||||
# ignore microsecond part of 'd' since we removed it from 'now'
|
||||
delta = now - (d - datetime.timedelta(0, 0, d.microsecond))
|
||||
since = delta.days * 24 * 60 * 60 + delta.seconds
|
||||
@@ -168,12 +167,12 @@ class Tell(ModuleBase):
|
||||
count = since // seconds
|
||||
if count != 0:
|
||||
break
|
||||
|
||||
|
||||
if count == 1:
|
||||
s = '%(number)d %(type)s' % {'number': count, 'type': name[0]}
|
||||
else:
|
||||
s = '%(number)d %(type)s' % {'number': count, 'type': name[1]}
|
||||
|
||||
|
||||
if i + 1 < len(chunks):
|
||||
# Now get the second item
|
||||
seconds2, name2 = chunks[i + 1]
|
||||
@@ -184,13 +183,13 @@ class Tell(ModuleBase):
|
||||
else:
|
||||
s += ', %d %s' % (count2, name2[1])
|
||||
return s
|
||||
|
||||
|
||||
@staticmethod
|
||||
def timeuntil(d, now=None):
|
||||
def timeuntil(d, now=None): # not used?
|
||||
"""
|
||||
Like timesince, but returns a string measuring the time until
|
||||
the given time.
|
||||
"""
|
||||
if not now:
|
||||
now = datetime.datetime.now()
|
||||
return timesince(now, d)
|
||||
return Tell.timesince(now, d)
|
||||
|
||||
@@ -7,12 +7,13 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
|
||||
|
||||
class Test(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.dotest)]
|
||||
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.dotest)]
|
||||
|
||||
def dotest(self, args):
|
||||
print("DOTEST(%s)"%(args,))
|
||||
print("DOTEST(%s)" % (args,))
|
||||
|
||||
@@ -13,33 +13,34 @@ from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
|
||||
COMMAND_PREFIX = ".text-"
|
||||
|
||||
|
||||
class TextCDC(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks.append(ModuleHook("PRIVMSG",self.handleMessage))
|
||||
self.loadConfig()
|
||||
self.hooks.append(ModuleHook("PRIVMSG", self.handleMessage))
|
||||
self.prefixes = [person for person in self.config["people"]]
|
||||
self.bot = bot
|
||||
self.timer = None
|
||||
self.setupTimer()
|
||||
|
||||
def ondisable(self):
|
||||
if self.timer != None:
|
||||
if self.timer is not None:
|
||||
self.timer.cancel()
|
||||
|
||||
def handleMessage(self, args, prefix, trailing):
|
||||
channel = args[0]
|
||||
p = self.bot.decodePrefix(prefix)
|
||||
if self.bot.messageHasCommand(".textstatus", trailing):
|
||||
#self.bot.act_PRIVMSG(channel, "POP: %s" % "Good" if setupPop() != None else "Failed.")
|
||||
self.bot.act_PRIVMSG(channel, "SMTP: %s" % "Good" if setupSMTP() != None else "Failed.")
|
||||
# self.bot.act_PRIVMSG(channel, "POP: %s" % "Good" if setupPop() != None else "Failed.")
|
||||
self.bot.act_PRIVMSG(channel, "SMTP: %s" % "Good" if self.setupSMTP() is not None else "Failed.")
|
||||
for prefix in self.prefixes:
|
||||
if self.bot.messageHasCommand(COMMAND_PREFIX + prefix, trailing):
|
||||
email = self.config["people"][prefix]["email-addr"]
|
||||
message = ' '.join(trailing.split(" ")[1:])
|
||||
smtp = self.setupSMTP()
|
||||
try:
|
||||
smtp.sendmail(self.config["account"]["auth"]["username"], email, "Subject:\n\n%s -%s" % (message, p.nick))
|
||||
smtp.sendmail(self.config["account"]["auth"]["username"], email, "Subject:\n\n%s -%s" %
|
||||
(message, p.nick))
|
||||
smtp.quit()
|
||||
self.bot.act_PRIVMSG(channel, "Message sent.")
|
||||
except Exception as e:
|
||||
@@ -62,7 +63,7 @@ class TextCDC(ModuleBase):
|
||||
def setupSMTP(self):
|
||||
smtpObj = None
|
||||
if self.config["account"]["smtp"]["ssl"]:
|
||||
smtpObj = smtplib.SMTP_SSL(self.config["account"]["smtp"]["host"], self.config["account"]["smtp"]["port"])
|
||||
smtpObj = smtplib.SMTP_SSL(self.config["account"]["smtp"]["host"], self.config["account"]["smtp"]["port"])
|
||||
else:
|
||||
smtpObj = smtplib.SMTP_SSL(self.config["account"]["smtp"]["host"], self.config["account"]["smtp"]["port"])
|
||||
if self.config["account"]["smtp"]["authentication"]:
|
||||
@@ -77,14 +78,15 @@ class TextCDC(ModuleBase):
|
||||
return smtpObj
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def setupTimer(self):
|
||||
self.timer = Timer(self.config["interval"], self.checkMail, [self.bot, self.config["people"], self.config["output-channels"]],{})
|
||||
self.timer = Timer(self.config["interval"], self.checkMail, [self.bot, self.config["people"],
|
||||
self.config["output-channels"]], {})
|
||||
self.timer.start()
|
||||
|
||||
def checkMail(self, bot, people, channels, imapObj = None):
|
||||
|
||||
def checkMail(self, bot, people, channels, imapObj=None):
|
||||
try:
|
||||
if imapObj == None:
|
||||
if imapObj is None:
|
||||
imapObj = self.setupIMAP()
|
||||
for person in people:
|
||||
emailAddr = people[person]["email-addr"]
|
||||
@@ -96,8 +98,9 @@ class TextCDC(ModuleBase):
|
||||
for messageId in messageIds:
|
||||
message = imapObj.fetch(messageId, "BODY[TEXT]")
|
||||
if (message[0] == "OK"):
|
||||
messageText = message[1][0][1].decode("utf-8").split("-----Original Message-----")[0].rstrip()
|
||||
for channel in channels:
|
||||
messageText = message[1][0][1].decode("utf-8").split("-----Original Message-----")[0] \
|
||||
.rstrip()
|
||||
for channel in channels:
|
||||
bot.act_PRIVMSG(channel, "Message from %s: %s" % (person, messageText))
|
||||
imapObj.store(messageId, "+FLAGS", "\\Deleted")
|
||||
else:
|
||||
@@ -105,7 +108,7 @@ class TextCDC(ModuleBase):
|
||||
imapObj.logout()
|
||||
self.setupTimer()
|
||||
except Exception as e:
|
||||
if imapObj != None:
|
||||
if imapObj is not None:
|
||||
imapObj.logout()
|
||||
self.setupTimer()
|
||||
raise e
|
||||
raise e
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
"""
|
||||
|
||||
from threading import Thread
|
||||
from time import sleep,time
|
||||
from time import sleep, time
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
from random import randrange,choice
|
||||
from random import randrange, choice
|
||||
|
||||
|
||||
class Triggered(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.loadConfig()
|
||||
self.quietuntil = time()
|
||||
self.hooks.append(ModuleHook("PRIVMSG", self.check))
|
||||
|
||||
@@ -22,21 +22,21 @@ class Triggered(ModuleBase):
|
||||
return
|
||||
if not args.args[0].lower() in self.config["channels"]:
|
||||
return
|
||||
|
||||
|
||||
message = args.trailing.lower()
|
||||
triggered = False
|
||||
for word in self.config["words"]:
|
||||
if word.lower() in message:
|
||||
triggered = True
|
||||
break
|
||||
|
||||
|
||||
if not triggered:
|
||||
return
|
||||
|
||||
|
||||
msg = Thread(target=self.scream, args=(args.args[0],))
|
||||
msg.daemon = True
|
||||
msg.start()
|
||||
|
||||
|
||||
self.quietuntil = time() + self.config["quiet"]
|
||||
|
||||
def scream(self, channel):
|
||||
|
||||
@@ -18,7 +18,6 @@ class UnoPlay(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.servicesModule = self.bot.getmodulebyname("Services")
|
||||
self.mynick = self.servicesModule.config["user"]["nick"][0]
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.unoplay),
|
||||
ModuleHook("PRIVMSG", self.trigger),
|
||||
ModuleHook("NOTICE", self.decklisten)]
|
||||
@@ -30,6 +29,8 @@ class UnoPlay(ModuleBase):
|
||||
self.cards = []
|
||||
|
||||
def trigger(self, args, prefix, trailing):
|
||||
if trailing.startswith("["): # anti-znc buffer playback
|
||||
return
|
||||
if self.config["enable_trigger"] and "!jo" in trailing:
|
||||
self.bot.act_PRIVMSG(self.config["unochannel"], "jo")
|
||||
elif trailing == "jo":
|
||||
@@ -44,10 +45,10 @@ class UnoPlay(ModuleBase):
|
||||
self.bot.act_PRIVMSG(self.config["unochannel"], "jo")
|
||||
|
||||
def unoplay(self, args, prefix, trailing):
|
||||
ogtrailing = trailing
|
||||
if trailing.startswith("["): # anti-znc buffer playback
|
||||
return
|
||||
|
||||
trailing = self.stripcolors(trailing)
|
||||
self.log.debug("> %s" % ogtrailing)
|
||||
self.log.debug("> %s" % trailing)
|
||||
|
||||
if self.config["unobot"] not in prefix:
|
||||
return
|
||||
@@ -60,15 +61,15 @@ class UnoPlay(ModuleBase):
|
||||
self.current_card = self.parsecard(message)
|
||||
self.log.debug(">> top card: %s" % str(self.current_card))
|
||||
|
||||
if self.mynick in trailing:
|
||||
if self.bot.get_nick() in trailing:
|
||||
self.shouldgo = True
|
||||
|
||||
# See if someone passed to us
|
||||
if "passes" in trailing and self.mynick in trailing:
|
||||
if "passes" in trailing and self.bot.get_nick() in trailing:
|
||||
self.shouldgo = True
|
||||
|
||||
# Play after someone was droppped
|
||||
if "continuing with" in trailing and self.mynick in trailing:
|
||||
if "continuing with" in trailing and self.bot.get_nick() in trailing:
|
||||
self.shouldgo = True
|
||||
|
||||
# Parse misc played cards
|
||||
@@ -79,7 +80,7 @@ class UnoPlay(ModuleBase):
|
||||
self.log.debug(">> current card: %s" % str(self.current_card))
|
||||
|
||||
# After someone plays to us
|
||||
if "to %s" % self.mynick in trailing:
|
||||
if "to %s" % self.bot.get_nick() in trailing:
|
||||
self.shouldgo = True
|
||||
|
||||
# After color change
|
||||
@@ -98,15 +99,15 @@ class UnoPlay(ModuleBase):
|
||||
self.current_card[2]['number'] = -1
|
||||
self.current_card[2]['type'] = None
|
||||
self.log.debug("Color changed to %s " % self.current_card[2]['color'])
|
||||
if "urrent player %s" % self.mynick in trailing:
|
||||
if "urrent player %s" % self.bot.get_nick() in trailing:
|
||||
self.shouldgo = True
|
||||
|
||||
# After color change to us
|
||||
if "play continues with %s" % self.mynick in trailing:
|
||||
if "play continues with %s" % self.bot.get_nick() in trailing:
|
||||
self.shouldgo = True
|
||||
|
||||
# We need to choose a color
|
||||
if "hoose a color %s" % self.mynick in trailing:
|
||||
if "hoose a color %s" % self.bot.get_nick() in trailing:
|
||||
self.pickcolor()
|
||||
|
||||
# Reset
|
||||
@@ -225,13 +226,12 @@ class UnoPlay(ModuleBase):
|
||||
self.bot.act_PRIVMSG(self.config["unochannel"], "pl %s" % card)
|
||||
|
||||
def decklisten(self, args, prefix, trailing):
|
||||
if trailing.startswith("["): # anti-znc buffer playback
|
||||
return
|
||||
if self.config["unobot"] not in prefix:
|
||||
return
|
||||
|
||||
ogtrailing = trailing
|
||||
trailing = self.stripcolors(trailing)
|
||||
self.log.debug("> %s" % (ogtrailing, ))
|
||||
self.log.debug("> %s" % (trailing, ))
|
||||
|
||||
cards = []
|
||||
|
||||
|
||||
@@ -7,29 +7,30 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
import json
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
from requests import get
|
||||
|
||||
|
||||
class Urban(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.urban)]
|
||||
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.urban)]
|
||||
|
||||
def urban(self, args, prefix, trailing):
|
||||
cmd = self.bot.messageHasCommand(".urban", trailing)
|
||||
if not cmd:
|
||||
cmd = self.bot.messageHasCommand(".u", trailing)
|
||||
if cmd and args[0][0:1]=="#":
|
||||
if cmd.args_str.strip() =="":
|
||||
if cmd and args[0][0:1] == "#":
|
||||
if cmd.args_str.strip() == "":
|
||||
self.bot.act_PRIVMSG(args[0], ".u/.urban <phrase> -- looks up <phrase> on urbandictionary.com")
|
||||
return
|
||||
definitions = get("http://www.urbandictionary.com/iphone/search/define", params={"term":cmd.args_str}).json()["list"]
|
||||
definitions = get("http://www.urbandictionary.com/iphone/search/define",
|
||||
params={"term": cmd.args_str}).json()["list"]
|
||||
if len(definitions) == 0:
|
||||
self.bot.act_PRIVMSG(args[0], "Urban definition: no results!")
|
||||
else:
|
||||
defstr = definitions[0]['definition'].replace('\n', ' ').replace('\r', '')
|
||||
if len(defstr)>360:
|
||||
defstr = defstr[0:360]+"..."
|
||||
self.bot.act_PRIVMSG(args[0], "Urban definition: %s - http://urbanup.com/%s" % (defstr, definitions[0]['defid']))
|
||||
|
||||
if len(defstr) > 360:
|
||||
defstr = defstr[0:360] + "..."
|
||||
self.bot.act_PRIVMSG(args[0], "Urban definition: %s - http://urbanup.com/%s" %
|
||||
(defstr, definitions[0]['defid']))
|
||||
|
||||
@@ -7,110 +7,114 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
from requests import get
|
||||
from urllib.parse import urlencode
|
||||
|
||||
|
||||
class Weather(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
|
||||
assert not "get an API key" in self.config["apikey"]
|
||||
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
|
||||
assert "get an API key" not in self.config["apikey"]
|
||||
|
||||
self.login = self.bot.getBestModuleForService("login")
|
||||
try:
|
||||
assert not self.login == None
|
||||
assert self.login is not None
|
||||
except AssertionError as _ae:
|
||||
self.log.error("Weather: A 'login' service is required")
|
||||
return
|
||||
|
||||
|
||||
self.attr = self.bot.getBestModuleForService("attributes")
|
||||
try:
|
||||
assert not self.attr == None
|
||||
except AssertionError as _ae:
|
||||
assert self.attr is not None
|
||||
except AssertionError as _ae: # NOQA
|
||||
self.log.error("Weather: An 'attributes' service is required")
|
||||
return
|
||||
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.weather)]
|
||||
|
||||
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.weather)]
|
||||
|
||||
def weather(self, args, prefix, trailing):
|
||||
prefixObj = self.bot.decodePrefix(prefix)
|
||||
fromWho = prefixObj.nick
|
||||
|
||||
|
||||
replyTo = args[0] if "#" in args[0] else fromWho
|
||||
|
||||
|
||||
hasUnit = self.attr.get(fromWho, "weather-unit")
|
||||
if hasUnit:
|
||||
hasUnit = hasUnit.upper()
|
||||
|
||||
|
||||
cmd = self.bot.messageHasCommand([".w", ".weather"], trailing)
|
||||
if cmd:
|
||||
if len(cmd.args_str)>0:
|
||||
if len(cmd.args_str) > 0:
|
||||
self.send_weather(replyTo, fromWho, cmd.args_str, hasUnit)
|
||||
return
|
||||
|
||||
|
||||
weatherZip = self.attr.get(fromWho, "weather-zip")
|
||||
if weatherZip == None:
|
||||
if weatherZip is None:
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: you must set a location with .setloc" % (fromWho,))
|
||||
return
|
||||
|
||||
|
||||
self.bot.act_PRIVMSG(replyTo, "%s: %s" % (fromWho, self.getWeather(weatherZip, hasUnit)))
|
||||
|
||||
|
||||
cmd = self.bot.messageHasCommand(".setloc", trailing)
|
||||
if cmd and not args[0]=="#":
|
||||
|
||||
if len(cmd.args)==0:
|
||||
self.bot.act_PRIVMSG(fromWho, ".setloc: set your location for weather lookup. Example: .setloc Rochester, NY")
|
||||
if cmd and not args[0] == "#":
|
||||
|
||||
if not cmd.args:
|
||||
self.bot.act_PRIVMSG(fromWho, ".setloc: set your location for weather lookup. Example: "
|
||||
".setloc Rochester, NY")
|
||||
return
|
||||
|
||||
|
||||
weatherLoc = cmd.args_str
|
||||
|
||||
|
||||
try:
|
||||
result = self.getWeather(weatherLoc)
|
||||
result = self.getWeather(weatherLoc) # NOQA
|
||||
except LocationNotSpecificException as lnse:
|
||||
self.bot.act_PRIVMSG(fromWho, "'%s': location not specific enough. Did you mean: %s" % (weatherLoc, self.alternates_to_str(lnse.alternates)))
|
||||
self.bot.act_PRIVMSG(fromWho, "'%s': location not specific enough. Did you mean: %s" %
|
||||
(weatherLoc, self.alternates_to_str(lnse.alternates)))
|
||||
return
|
||||
except LocationException as le:
|
||||
self.bot.act_PRIVMSG(fromWho, "'%s': location not found" % weatherLoc)
|
||||
self.bot.act_PRIVMSG(fromWho, "'%s': location not found: %s" % (weatherLoc, le))
|
||||
return
|
||||
|
||||
|
||||
if not self.login.check(prefixObj.nick, prefixObj.hostname):
|
||||
self.bot.act_PRIVMSG(fromWho, ".setloc: you need to be logged in to do that (try .login)")
|
||||
return
|
||||
|
||||
|
||||
self.attr.set(fromWho, "weather-zip", weatherLoc)
|
||||
self.bot.act_PRIVMSG(fromWho, "Saved your location as %s" % self.attr.get(fromWho, "weather-zip"))
|
||||
if self.attr.get(fromWho, "weather-zip")==None:
|
||||
if self.attr.get(fromWho, "weather-zip") is None:
|
||||
self.bot.act_PRIVMSG(fromWho, "Tip: choose C or F with .wunit <C/F>")
|
||||
|
||||
|
||||
cmd = self.bot.messageHasCommand(".wunit", trailing)
|
||||
if cmd and not args[0]=="#":
|
||||
if cmd and not args[0] == "#":
|
||||
unit = None
|
||||
try:
|
||||
assert cmd.args[0].lower() in ['c', 'f']
|
||||
unit = cmd.args[0]
|
||||
except:
|
||||
pass
|
||||
|
||||
if unit == None:
|
||||
|
||||
if unit is None:
|
||||
self.bot.act_PRIVMSG(fromWho, ".wunit: set your preferred temperature unit to C or F")
|
||||
return
|
||||
|
||||
|
||||
if not self.login.check(prefixObj.nick, prefixObj.hostname):
|
||||
self.bot.act_PRIVMSG(fromWho, ".wunit: you need to be logged in to do that (try .login)")
|
||||
return
|
||||
|
||||
|
||||
self.attr.set(fromWho, "weather-unit", unit.lower())
|
||||
self.bot.act_PRIVMSG(fromWho, "Saved your preferred unit as %s" % self.attr.get(fromWho, "weather-unit").upper())
|
||||
|
||||
self.bot.act_PRIVMSG(fromWho, "Saved your preferred unit as %s" %
|
||||
self.attr.get(fromWho, "weather-unit").upper())
|
||||
|
||||
def send_weather(self, target, hilight, location, units=None):
|
||||
try:
|
||||
self.bot.act_PRIVMSG(target, "%s: %s" % (hilight, self.getWeather(location, units)))
|
||||
except LocationNotSpecificException as lnse:
|
||||
self.bot.act_PRIVMSG(target, "'%s': location not specific enough. Did you mean: %s" % (location, self.alternates_to_str(lnse.alternates)))
|
||||
self.bot.act_PRIVMSG(target, "'%s': location not specific enough. Did you mean: %s" %
|
||||
(location, self.alternates_to_str(lnse.alternates)))
|
||||
except LocationException as le:
|
||||
self.bot.act_PRIVMSG(target, "'%s': location not found" % location)
|
||||
|
||||
self.bot.act_PRIVMSG(target, "'%s': location not found: %s" % (location, le))
|
||||
|
||||
def alternates_to_str(self, alternates):
|
||||
pieces = []
|
||||
for item in alternates:
|
||||
@@ -120,51 +124,54 @@ class Weather(ModuleBase):
|
||||
item_pieces.append(item[key])
|
||||
pieces.append(', '.join(item_pieces))
|
||||
return ' -- '.join(pieces)
|
||||
|
||||
|
||||
def getWeather(self, zipcode, unit=None):
|
||||
if unit==None:
|
||||
if unit is None:
|
||||
unit = self.config["defaultUnit"]
|
||||
unit = unit.lower()
|
||||
# Get data
|
||||
data = get("http://api.wunderground.com/api/%s/geolookup/conditions/forecast10day/q/%s.json" % (self.config["apikey"], zipcode)).json()
|
||||
|
||||
data = get("http://api.wunderground.com/api/%s/geolookup/conditions/forecast10day/q/%s.json" %
|
||||
(self.config["apikey"], zipcode)).json()
|
||||
|
||||
if "results" in data["response"]:
|
||||
raise LocationNotSpecificException(data["response"]["results"])
|
||||
if "error" in data["response"] and data["response"]["error"]["type"]=="querynotfound":
|
||||
if "error" in data["response"] and data["response"]["error"]["type"] == "querynotfound":
|
||||
raise LocationException
|
||||
|
||||
|
||||
# Build 5day
|
||||
fiveday = ""
|
||||
for item in data["forecast"]["simpleforecast"]["forecastday"][1:6]:
|
||||
fiveday += "%(day)s %(icon)s %(low)s-%(high)s°%(unit)s • " % {
|
||||
"unit":unit.upper(),
|
||||
"high":item["high"]["fahrenheit" if unit=="f" else "celsius"],
|
||||
"low":item["low"]["fahrenheit" if unit=="f" else "celsius"],
|
||||
"icon":self.icon2emoji(item["icon"]),
|
||||
"day":item["date"]["weekday_short"]
|
||||
"unit": unit.upper(),
|
||||
"high": item["high"]["fahrenheit" if unit == "f" else "celsius"],
|
||||
"low": item["low"]["fahrenheit" if unit == "f" else "celsius"],
|
||||
"icon": self.icon2emoji(item["icon"]),
|
||||
"day": item["date"]["weekday_short"]
|
||||
}
|
||||
fiveday=fiveday[0:-3]
|
||||
|
||||
# build wind speed
|
||||
wind_speed = data["current_observation"]["wind_mph"] if unit=="f" else data["current_observation"]["wind_kph"]
|
||||
wind_speed_gust = data["current_observation"]["wind_gust_mph"] if unit=="f" else data["current_observation"]["wind_gust_mph"]
|
||||
if not wind_speed==wind_speed_gust and float(wind_speed_gust)>0:
|
||||
fiveday = fiveday[0:-3]
|
||||
|
||||
# build wind speed
|
||||
wind_speed = data["current_observation"]["wind_mph"] if unit == "f" else data["current_observation"]["wind_kph"]
|
||||
wind_speed_gust = data["current_observation"]["wind_gust_mph"] if unit == "f" \
|
||||
else data["current_observation"]["wind_gust_mph"]
|
||||
if not wind_speed == wind_speed_gust and float(wind_speed_gust) > 0:
|
||||
wind_speed = "%s-%s" % (wind_speed, wind_speed_gust)
|
||||
else:
|
||||
wind_speed = "%s" % (wind_speed,)
|
||||
# return message
|
||||
return "\x02%(city)s, %(state)s:\x02 %(sky)s, \x02%(temp)s°%(unit)s\x02. %(wind_str)s %(wind_speed)smph (%(wind_dir)s). \x02Next 5 days:\x02 %(fiveday)s" % {
|
||||
"city": data["current_observation"]["display_location"]["city"],
|
||||
"state": data["current_observation"]["display_location"]["state"],
|
||||
"sky": data["forecast"]["simpleforecast"]["forecastday"][0]["conditions"],
|
||||
"temp": int(data["current_observation"]["temp_f"]) if unit=="f" else int(data["current_observation"]["temp_c"]),
|
||||
"unit": unit.upper(),
|
||||
"wind_str": self.shorten_windstr(data["current_observation"]["wind_string"].lower()),
|
||||
"wind_speed": wind_speed,
|
||||
"wind_dir": self.deg_to_arrow(int(data["current_observation"]["wind_degrees"])),
|
||||
"fiveday":fiveday
|
||||
}
|
||||
|
||||
return "\x02%(city)s, %(state)s:\x02 %(sky)s, \x02%(temp)s°%(unit)s\x02. %(wind_str)s %(wind_speed)smph " \
|
||||
"(%(wind_dir)s). \x02Next 5 days:\x02 %(fiveday)s" % {
|
||||
"city": data["current_observation"]["display_location"]["city"],
|
||||
"state": data["current_observation"]["display_location"]["state"],
|
||||
"sky": data["forecast"]["simpleforecast"]["forecastday"][0]["conditions"],
|
||||
"temp": int(data["current_observation"]["temp_f"]) if unit == "f"
|
||||
else int(data["current_observation"]["temp_c"]),
|
||||
"unit": unit.upper(),
|
||||
"wind_str": self.shorten_windstr(data["current_observation"]["wind_string"].lower()),
|
||||
"wind_speed": wind_speed,
|
||||
"wind_dir": self.deg_to_arrow(int(data["current_observation"]["wind_degrees"])),
|
||||
"fiveday": fiveday}
|
||||
|
||||
def shorten_windstr(self, windstr):
|
||||
if "gusting" in windstr:
|
||||
return "Gusting"
|
||||
@@ -173,9 +180,7 @@ class Weather(ModuleBase):
|
||||
if "from the" in windstr.lower():
|
||||
return "Varying"
|
||||
return windstr[0:12]
|
||||
|
||||
|
||||
|
||||
|
||||
def icon2emoji(self,icon):
|
||||
if "partlycloudy" in icon or "mostlycloudy" in icon:
|
||||
return "⛅️"
|
||||
@@ -189,7 +194,7 @@ class Weather(ModuleBase):
|
||||
return "❄️"
|
||||
else:
|
||||
return "(%s)" % icon
|
||||
|
||||
|
||||
def deg_to_arrow(self, deg):
|
||||
if deg > 335 or deg < 0:
|
||||
return "↑"
|
||||
@@ -208,10 +213,12 @@ class Weather(ModuleBase):
|
||||
elif deg > 22:
|
||||
return "⇗"
|
||||
|
||||
|
||||
class LocationException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class LocationNotSpecificException(LocationException):
|
||||
def __init__(self, alternates):
|
||||
self.alternates = alternates
|
||||
pass
|
||||
pass
|
||||
|
||||
@@ -7,78 +7,81 @@
|
||||
|
||||
"""
|
||||
|
||||
from pyircbot.modulebase import ModuleBase,ModuleHook
|
||||
from pyircbot.modulebase import ModuleBase, ModuleHook
|
||||
from requests import get
|
||||
import time
|
||||
import re
|
||||
|
||||
|
||||
class Youtube(ModuleBase):
|
||||
def __init__(self, bot, moduleName):
|
||||
ModuleBase.__init__(self, bot, moduleName);
|
||||
self.hooks=[ModuleHook("PRIVMSG", self.youtube)]
|
||||
|
||||
ModuleBase.__init__(self, bot, moduleName)
|
||||
self.hooks = [ModuleHook("PRIVMSG", self.youtube)]
|
||||
|
||||
def getISOdurationseconds(self, stamp):
|
||||
ISO_8601_period_rx = re.compile(
|
||||
'P' # designates a period
|
||||
'(?:(?P<years>\d+)Y)?' # years
|
||||
'(?:(?P<months>\d+)M)?' # months
|
||||
'(?:(?P<weeks>\d+)W)?' # weeks
|
||||
'(?:(?P<days>\d+)D)?' # days
|
||||
'(?:T' # time part must begin with a T
|
||||
'(?:(?P<hours>\d+)H)?' # hours
|
||||
'(?:(?P<minutes>\d+)M)?' # minutes
|
||||
'(?:(?P<seconds>\d+)S)?' # seconds
|
||||
'(?:(?P<years>\d+)Y)?' # years
|
||||
'(?:(?P<months>\d+)M)?' # months
|
||||
'(?:(?P<weeks>\d+)W)?' # weeks
|
||||
'(?:(?P<days>\d+)D)?' # days
|
||||
'(?:T' # time part begins with a T
|
||||
'(?:(?P<hours>\d+)H)?' # hours
|
||||
'(?:(?P<minutes>\d+)M)?' # minutes
|
||||
'(?:(?P<seconds>\d+)S)?' # seconds
|
||||
')?' # end of time part
|
||||
) # http://stackoverflow.com/a/16742742
|
||||
) # http://stackoverflow.com/a/16742742
|
||||
return ISO_8601_period_rx.match(stamp).groupdict()
|
||||
|
||||
|
||||
def youtube(self, args, prefix, trailing):
|
||||
|
||||
|
||||
cmd = self.bot.messageHasCommand(".youtube", trailing)
|
||||
if not cmd:
|
||||
cmd = self.bot.messageHasCommand(".yt", trailing)
|
||||
if cmd and args[0][0:1]=="#":
|
||||
#TOTO search youtube
|
||||
if cmd.args_str.strip() =="":
|
||||
if cmd and args[0][0:1] == "#":
|
||||
# TODO search youtube
|
||||
if cmd.args_str.strip() == "":
|
||||
self.bot.act_PRIVMSG(args[0], '.youtube <query> -- returns the first YouTube search result for <query>')
|
||||
return
|
||||
j = get("http://gdata.youtube.com/feeds/api/videos?v=2&alt=jsonc&max-results=1", params={"q":trailing}).json()
|
||||
if 'error' in j or j['data']['totalItems']==0:
|
||||
j = get("http://gdata.youtube.com/feeds/api/videos?v=2&alt=jsonc&max-results=1",
|
||||
params={"q": trailing}).json()
|
||||
if 'error' in j or j['data']['totalItems'] == 0:
|
||||
self.bot.act_PRIVMSG(args[0], "YouTube: No results found.")
|
||||
else:
|
||||
vid_id = j['data']['items'][0]['id']
|
||||
vidinfo = self.get_video_description(vid_id)
|
||||
if vidinfo:
|
||||
self.bot.act_PRIVMSG(args[0], "http://youtu.be/%s :: %s" % (vid_id, vidinfo))
|
||||
|
||||
|
||||
def get_video_description(self, vid_id):
|
||||
apidata = get('https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails,statistics&id=%s&key=%s' % (vid_id, self.config["api_key"])).json()
|
||||
|
||||
apidata = get('https://www.googleapis.com/youtube/v3/videos?part=snippet,contentDetails,statistics&id=%s'
|
||||
'&key=%s' % (vid_id, self.config["api_key"])).json()
|
||||
|
||||
if not apidata['pageInfo']['totalResults']:
|
||||
return
|
||||
|
||||
|
||||
video = apidata['items'][0]
|
||||
snippet = video["snippet"]
|
||||
duration = self.getISOdurationseconds(video["contentDetails"]["duration"])
|
||||
|
||||
|
||||
out = '\x02\x031,0You\x0f\x030,4Tube\x02\x0f :: \x02%s\x02' % snippet["title"]
|
||||
|
||||
|
||||
out += ' - \x02'
|
||||
if duration["hours"]!=None:
|
||||
if duration["hours"] is not None:
|
||||
out += '%dh ' % int(duration["hours"])
|
||||
if duration["minutes"]!=None:
|
||||
if duration["minutes"] is not None:
|
||||
out += '%dm ' % int(duration["minutes"])
|
||||
out += "%ds\x02" % int(duration["seconds"])
|
||||
|
||||
totalvotes = float(video["statistics"]["dislikeCount"])+float(video["statistics"]["likeCount"])
|
||||
|
||||
totalvotes = float(video["statistics"]["dislikeCount"]) + float(video["statistics"]["likeCount"])
|
||||
rating = float(video["statistics"]["likeCount"]) / totalvotes
|
||||
out += ' - rated \x02%.2f/5\x02' % round(rating*5,1)
|
||||
out += ' - rated \x02%.2f/5\x02' % round(rating * 5, 1)
|
||||
out += ' - \x02%s\x02 views' % self.group_int_digits(video["statistics"]["viewCount"])
|
||||
upload_time = time.strptime(snippet['publishedAt'], "%Y-%m-%dT%H:%M:%S.000Z")
|
||||
out += ' - by \x02%s\x02 on \x02%s\x02' % (snippet['channelTitle'], time.strftime("%Y.%m.%d", upload_time))
|
||||
|
||||
|
||||
return out
|
||||
|
||||
|
||||
def group_int_digits(self, number, delimiter=',', grouping=3):
|
||||
base = str(number).strip()
|
||||
builder = []
|
||||
|
||||
@@ -17,8 +17,7 @@ import os.path
|
||||
|
||||
ParsedCommand = namedtuple("ParsedCommand", "command args args_str message")
|
||||
|
||||
|
||||
class PyIRCBot:
|
||||
class PyIRCBot(object):
|
||||
""":param botconfig: The configuration of this instance of the bot. Passed by main.py.
|
||||
:type botconfig: dict
|
||||
"""
|
||||
@@ -44,7 +43,7 @@ class PyIRCBot:
|
||||
"""IRC protocol class"""
|
||||
self.irc.servers = self.botconfig["connection"]["servers"]
|
||||
self.irc.port = self.botconfig["connection"]["port"]
|
||||
self.irc.ipv6 = True if self.botconfig["connection"]["ipv6"]=="on" else False
|
||||
self.irc.ipv6 = True if self.botconfig["connection"]["ipv6"] == "on" else False
|
||||
|
||||
self.irc.addHook("_DISCONNECT", self.connection_closed)
|
||||
|
||||
@@ -57,8 +56,9 @@ class PyIRCBot:
|
||||
self.act_MODE = self.irc.act_MODE
|
||||
self.act_ACTION = self.irc.act_ACTION
|
||||
self.act_KICK = self.irc.act_KICK
|
||||
self.act_QUIT = self.irc.act_QUIT
|
||||
self.get_nick = self.irc.get_nick
|
||||
self.act_QUIT = self.irc.act_QUIT
|
||||
self.act_PASS = self.irc.act_PASS
|
||||
self.get_nick = self.irc.get_nick
|
||||
self.decodePrefix = IRCCore.decodePrefix
|
||||
|
||||
# Load modules
|
||||
@@ -96,7 +96,6 @@ class PyIRCBot:
|
||||
:param message: Quit message
|
||||
:type message: str
|
||||
"""
|
||||
#Close all modules
|
||||
self.closeAllModules()
|
||||
|
||||
self.irc.kill(message=message, alive=not sys_exit)
|
||||
@@ -114,11 +113,11 @@ class PyIRCBot:
|
||||
def initModules(self):
|
||||
"""load modules specified in instance config"""
|
||||
" append module location to path "
|
||||
sys.path.append(os.path.dirname(__file__)+"/modules/")
|
||||
sys.path.append(os.path.dirname(__file__) + "/modules/")
|
||||
|
||||
" append usermodule dir to beginning of path"
|
||||
for path in self.botconfig["bot"]["usermodules"]:
|
||||
sys.path.insert(0, path+"/")
|
||||
sys.path.insert(0, path + "/")
|
||||
|
||||
for modulename in self.botconfig[ | ||||