Misc & lint fixes

This commit is contained in:
dave
2017-01-01 14:59:01 -08:00
parent e11d068a6e
commit fa8783e6cc
42 changed files with 1726 additions and 1593 deletions

View File

@@ -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 "

View File

@@ -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")

View File

@@ -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

View File

@@ -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()

View File

@@ -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()

View File

@@ -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

View File

@@ -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()

View File

@@ -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:

View File

@@ -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"))

View File

@@ -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))

View File

@@ -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

View File

@@ -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"]))

View File

@@ -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)

View File

@@ -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"))

View File

@@ -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()

View File

@@ -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)

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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 = []

View File

@@ -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"])

View File

@@ -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

View File

@@ -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"))

View File

@@ -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()

View File

@@ -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()

View File

@@ -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,

View File

@@ -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()

View File

@@ -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()

View File

@@ -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

View File

@@ -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})

View File

@@ -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)

View File

@@ -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,))

View File

@@ -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

View File

@@ -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):

View File

@@ -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 = []

View File

@@ -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']))

View File

@@ -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

View File

@@ -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 = []

View File

@@ -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[